diff --git a/src/main/java/emu/grasscutter/DebugConstants.java b/src/main/java/emu/grasscutter/DebugConstants.java index 647e58bf7..503238c64 100644 --- a/src/main/java/emu/grasscutter/DebugConstants.java +++ b/src/main/java/emu/grasscutter/DebugConstants.java @@ -4,6 +4,16 @@ public final class DebugConstants { public static boolean LOG_ABILITIES = false; public static boolean LOG_LUA_SCRIPTS = false; public static boolean LOG_QUEST_START = false; + public static boolean LOG_MISSING_ABILITIES = false; + public static boolean LOG_MISSING_LUA_SCRIPTS = false; + + /** + * WARNING: THIS IS A DANGEROUS SETTING. DO NOT ENABLE UNLESS YOU KNOW WHAT YOU ARE DOING. + * This allows the *client* to send *ANY* token and UID pair to the server. + * The server will then accept the token and UID pair as valid, and set the account's token to the client specified one. + * This can allow for IMPERSONATION and HIJACKING of accounts/servers. + */ + public static final boolean ACCEPT_CLIENT_TOKEN = false; private DebugConstants() { // Prevent instantiation. diff --git a/src/main/java/emu/grasscutter/command/commands/DebugCommand.java b/src/main/java/emu/grasscutter/command/commands/DebugCommand.java new file mode 100644 index 000000000..e7ea8a989 --- /dev/null +++ b/src/main/java/emu/grasscutter/command/commands/DebugCommand.java @@ -0,0 +1,67 @@ +package emu.grasscutter.command.commands; + +import emu.grasscutter.Grasscutter; +import emu.grasscutter.command.*; +import emu.grasscutter.game.player.Player; + +import java.util.List; + +@Command( + label = "debug", + usage = "/debug", + permission = "grasscutter.command.debug", + targetRequirement = Command.TargetRequirement.NONE) +public final class DebugCommand implements CommandHandler { + @Override + public void execute(Player sender, Player targetPlayer, List args) { + if (sender == null) return; + + if (args.isEmpty()) { + sender.dropMessage("No arguments provided. (check command for help)"); + return; + } + + var subCommand = args.get(0); + args.remove(0); + switch (subCommand) { + default -> sender.dropMessage("No arguments provided. (check command for help)"); + case "abilities" -> { + if (args.isEmpty()) { + sender.dropMessage("No arguments provided. (check command for help)"); + return; + } + + var scene = sender.getScene(); + var entityId = Integer.parseInt(args.get(0)); + var entity = args.size() > 1 && args.get(1).equals("config") ? + scene.getEntityByConfigId(entityId) : + scene.getEntityById(entityId); + if (entity == null) { + sender.dropMessage("Entity not found."); + return; + } + + try { + var abilities = entity.getInstancedAbilities(); + for (var i = 0; i < abilities.size(); i++) { + try { + var ability = abilities.get(i); + Grasscutter.getLogger().debug("Ability #{}: {}; Modifiers: {}", + i, ability.toString(), ability.getModifiers().keySet()); + } catch (Exception exception) { + Grasscutter.getLogger().warn("Failed to print ability #{}.", i, exception); + } + } + + if (abilities.isEmpty()) { + Grasscutter.getLogger().debug("No abilities found on {}.", entity.toString()); + } + } catch (Exception exception) { + Grasscutter.getLogger().warn("Failed to get abilities.", exception); + } + + sender.dropMessage("Check console for abilities."); + } + } + } +} diff --git a/src/main/java/emu/grasscutter/data/ResourceLoader.java b/src/main/java/emu/grasscutter/data/ResourceLoader.java index 243df4a32..4773ff115 100644 --- a/src/main/java/emu/grasscutter/data/ResourceLoader.java +++ b/src/main/java/emu/grasscutter/data/ResourceLoader.java @@ -1,8 +1,5 @@ package emu.grasscutter.data; -import static emu.grasscutter.utils.FileUtils.*; -import static emu.grasscutter.utils.lang.Language.translate; - import com.google.gson.annotations.SerializedName; import com.google.gson.reflect.TypeToken; import emu.grasscutter.Grasscutter; @@ -23,6 +20,10 @@ import emu.grasscutter.scripts.*; import emu.grasscutter.utils.*; import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.*; +import lombok.*; +import org.reflections.Reflections; + +import javax.script.*; import java.io.*; import java.nio.file.*; import java.util.*; @@ -30,9 +31,9 @@ import java.util.Map.Entry; import java.util.concurrent.*; import java.util.regex.Pattern; import java.util.stream.*; -import javax.script.*; -import lombok.*; -import org.reflections.Reflections; + +import static emu.grasscutter.utils.FileUtils.*; +import static emu.grasscutter.utils.lang.Language.translate; public final class ResourceLoader { @@ -780,7 +781,7 @@ public final class ResourceLoader { if (cs == null) return; try { - cs.eval(bindings); + ScriptLoader.eval(cs, bindings); // these are Map var teleportDataMap = ScriptLoader.getSerializer() @@ -964,7 +965,7 @@ public final class ResourceLoader { } try { - cs.eval(bindings); + ScriptLoader.eval(cs, bindings); // these are Map var replacementsMap = ScriptLoader.getSerializer() diff --git a/src/main/java/emu/grasscutter/game/ability/AbilityManager.java b/src/main/java/emu/grasscutter/game/ability/AbilityManager.java index 0ba1d7339..5e7082597 100644 --- a/src/main/java/emu/grasscutter/game/ability/AbilityManager.java +++ b/src/main/java/emu/grasscutter/game/ability/AbilityManager.java @@ -19,11 +19,12 @@ import emu.grasscutter.net.proto.AbilityScalarTypeOuterClass.AbilityScalarType; import emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry; import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction; import io.netty.util.concurrent.FastThreadLocalThread; -import java.util.HashMap; -import java.util.concurrent.*; import lombok.Getter; import org.reflections.Reflections; +import java.util.HashMap; +import java.util.concurrent.*; + public final class AbilityManager extends BasePlayerManager { private static final HashMap actionHandlers = new HashMap<>(); @@ -179,7 +180,12 @@ public final class AbilityManager extends BasePlayerManager { .handleModifierDurabilityChange(invoke); case ABILITY_INVOKE_ARGUMENT_META_ADD_NEW_ABILITY -> this.handleAddNewAbility(invoke); case ABILITY_INVOKE_ARGUMENT_META_SET_KILLED_SETATE -> this.handleKillState(invoke); - default -> {} + default -> { + if (DebugConstants.LOG_MISSING_ABILITIES) { + Grasscutter.getLogger().trace("Missing invoke handler for ability {}.", + invoke.getArgumentType().name()); + } + } } } @@ -520,27 +526,28 @@ public final class AbilityManager extends BasePlayerManager { var entity = this.player.getScene().getEntityById(invoke.getEntityId()); if (entity == null) { - Grasscutter.getLogger().trace("Entity not found: {}", invoke.getEntityId()); + if (DebugConstants.LOG_ABILITIES) + Grasscutter.getLogger().debug("Entity not found: {}", invoke.getEntityId()); return; } var addAbility = AbilityMetaAddAbility.parseFrom(invoke.getAbilityData()); - var abilityName = Ability.getAbilityName(addAbility.getAbility().getAbilityName()); - var ability = GameData.getAbilityData(abilityName); if (ability == null) { - Grasscutter.getLogger().trace("Ability not found: {}", abilityName); + if (DebugConstants.LOG_MISSING_ABILITIES) + Grasscutter.getLogger().debug("Ability not found: {}", abilityName); return; } entity.getInstancedAbilities().add(new Ability(ability, entity, player)); - - Grasscutter.getLogger() - .trace( - "Ability added to entity {} at index {}", - entity.getId(), - entity.getInstancedAbilities().size()); + if (DebugConstants.LOG_ABILITIES) { + Grasscutter.getLogger() + .debug( + "Ability added to entity {} at index {}.", + entity.getId(), + entity.getInstancedAbilities().size()); + } } private void handleKillState(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException { @@ -568,7 +575,7 @@ public final class AbilityManager extends BasePlayerManager { } public void addAbilityToEntity(GameEntity entity, AbilityData abilityData) { - Ability ability = new Ability(abilityData, entity, this.player); + var ability = new Ability(abilityData, entity, this.player); entity.getInstancedAbilities().add(ability); // This are in order } } diff --git a/src/main/java/emu/grasscutter/game/ability/actions/ActionServerLuaCall.java b/src/main/java/emu/grasscutter/game/ability/actions/ActionServerLuaCall.java index 3a029bf79..6c678b579 100644 --- a/src/main/java/emu/grasscutter/game/ability/actions/ActionServerLuaCall.java +++ b/src/main/java/emu/grasscutter/game/ability/actions/ActionServerLuaCall.java @@ -5,9 +5,11 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction; import emu.grasscutter.game.ability.Ability; import emu.grasscutter.game.entity.GameEntity; -import javax.script.Bindings; +import emu.grasscutter.scripts.ScriptLoader; import org.luaj.vm2.LuaFunction; +import javax.script.Bindings; + @AbilityAction(AbilityModifierAction.Type.ServerLuaCall) public final class ActionServerLuaCall extends AbilityActionHandler { @Override @@ -17,6 +19,11 @@ public final class ActionServerLuaCall extends AbilityActionHandler { var scriptManager = scene.getScriptManager(); var functionName = action.funcName; + // Set the script library's manager. + var scriptLib = ScriptLoader.getScriptLib(); + scriptLib.setCurrentEntity(target); + scriptLib.setSceneScriptManager(scriptManager); + // Attempt to call the function. return switch (action.luaCallType) { default -> false; case FromGroup -> { @@ -24,6 +31,9 @@ public final class ActionServerLuaCall extends AbilityActionHandler { var group = scriptManager.getGroupById(groupId); var script = group.getBindings(); + // Set the script library's group. + scriptLib.setCurrentGroup(group); + yield ActionServerLuaCall.callFunction(script, functionName); } case SpecificGroup -> { @@ -31,6 +41,9 @@ public final class ActionServerLuaCall extends AbilityActionHandler { var group = scriptManager.getGroupById(groupId); var script = group.getBindings(); + // Set the script library's group. + scriptLib.setCurrentGroup(group); + yield ActionServerLuaCall.callFunction(script, functionName); } }; @@ -51,7 +64,7 @@ public final class ActionServerLuaCall extends AbilityActionHandler { throw new Exception("Function is not a LuaFunction."); // Attempt to invoke the function. - luaFunction.call(); + luaFunction.call(ScriptLoader.getScriptLibLua()); return true; } catch (Exception exception) { diff --git a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java index 6b9307cd3..4c4777548 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java @@ -1,19 +1,15 @@ package emu.grasscutter.game.entity; import emu.grasscutter.data.GameData; -import emu.grasscutter.data.binout.AbilityData; import emu.grasscutter.data.binout.config.ConfigEntityMonster; import emu.grasscutter.data.common.PropGrowCurve; import emu.grasscutter.data.excels.EnvAnimalGatherConfigData; -import emu.grasscutter.data.excels.monster.MonsterCurveData; -import emu.grasscutter.data.excels.monster.MonsterData; +import emu.grasscutter.data.excels.monster.*; import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.*; import emu.grasscutter.game.quest.enums.QuestContent; -import emu.grasscutter.game.world.Position; -import emu.grasscutter.game.world.Scene; -import emu.grasscutter.game.world.SceneGroupInstance; +import emu.grasscutter.game.world.*; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo; @@ -28,18 +24,14 @@ import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; import emu.grasscutter.net.proto.SceneMonsterInfoOuterClass.SceneMonsterInfo; import emu.grasscutter.net.proto.SceneWeaponInfoOuterClass.SceneWeaponInfo; import emu.grasscutter.scripts.constants.EventType; -import emu.grasscutter.scripts.data.SceneMonster; -import emu.grasscutter.scripts.data.ScriptArgs; +import emu.grasscutter.scripts.data.*; import emu.grasscutter.server.event.entity.EntityDamageEvent; import emu.grasscutter.utils.helpers.ProtoHelper; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; -import lombok.Getter; -import lombok.Setter; +import lombok.*; import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.util.*; import static emu.grasscutter.scripts.constants.EventType.EVENT_SPECIFIC_MONSTER_HP_CHANGE; @@ -64,17 +56,19 @@ public class EntityMonster extends GameEntity { public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) { super(scene); - this.id = getWorld().getNextEntityId(EntityIdType.MONSTER); + + this.id = this.getWorld().getNextEntityId(EntityIdType.MONSTER); this.monsterData = monsterData; this.fightProperties = new Int2FloatOpenHashMap(); this.position = new Position(pos); this.rotation = new Position(); - this.bornPos = getPosition().clone(); + this.bornPos = this.getPosition().clone(); this.level = level; this.playerOnBattle = new ArrayList<>(); - if(GameData.getMonsterMappingMap().containsKey(getMonsterId())) { - this.configEntityMonster = GameData.getMonsterConfigData().get(GameData.getMonsterMappingMap().get(getMonsterId()).getMonsterJson()); + if (GameData.getMonsterMappingMap().containsKey(this.getMonsterId())) { + this.configEntityMonster = GameData.getMonsterConfigData().get( + GameData.getMonsterMappingMap().get(this.getMonsterId()).getMonsterJson()); } else { this.configEntityMonster = null; } @@ -87,90 +81,95 @@ public class EntityMonster extends GameEntity { } this.recalcStats(); - - initAbilities(); + this.initAbilities(); } - private void addConfigAbility(String name){ - AbilityData data = GameData.getAbilityData(name); - if(data != null) - getScene().getWorld().getHost().getAbilityManager().addAbilityToEntity( - this, data); + private void addConfigAbility(String name) { + var data = GameData.getAbilityData(name); + if (data != null) { + this.getWorld().getHost() + .getAbilityManager() + .addAbilityToEntity(this, data); + } } @Override public void initAbilities() { - if(configEntityMonster != null) { - // Affix abilities - var optionalGroup = getScene().getLoadedGroups().stream() + // Affix abilities + var optionalGroup = this.getScene().getLoadedGroups().stream() .filter(g -> g.id == this.getGroupId()) .findAny(); - List affixes = null; - if (optionalGroup.isPresent()) { - var group = optionalGroup.get(); + List affixes = null; + if (optionalGroup.isPresent()) { + var group = optionalGroup.get(); - SceneMonster monster = group.monsters.get(getConfigId()); - if(monster != null) affixes = monster.affix; - } + var monster = group.monsters.get(getConfigId()); + if (monster != null) affixes = monster.affix; + } - if (monsterData != null) { - // TODO: Research if group affixes goes first - if (affixes == null) affixes = monsterData.getAffix(); - else affixes.addAll(monsterData.getAffix()); - } + if (monsterData != null) { + // TODO: Research if group affixes goes first + if (affixes == null) affixes = monsterData.getAffix(); + else affixes.addAll(monsterData.getAffix()); + } - if(affixes != null) { - for(var affixId : affixes) { - var affix = GameData.getMonsterAffixDataMap().get(affixId.intValue()); - if (!affix.isPreAdd()) continue; + if (affixes != null) { + for (var affixId : affixes) { + var affix = GameData.getMonsterAffixDataMap().get(affixId.intValue()); + if (!affix.isPreAdd()) continue; - //Add the ability - for(var name : affix.getAbilityName()) { - this.addConfigAbility(name); - } + //Add the ability + for (var name : affix.getAbilityName()) { + this.addConfigAbility(name); } } + } - //TODO: Research if any monster is non humanoid - for(var ability : GameData.getConfigGlobalCombat().getDefaultAbilities().getNonHumanoidMoveAbilities()) { - this.addConfigAbility(ability); + // TODO: Research if any monster is non humanoid + for(var ability : GameData.getConfigGlobalCombat() + .getDefaultAbilities() + .getNonHumanoidMoveAbilities()) { + this.addConfigAbility(ability); + } + + if (this.configEntityMonster != null && + this.configEntityMonster.getAbilities() != null) { + for (var configAbilityData : this.configEntityMonster.getAbilities()) { + this.addConfigAbility(configAbilityData.abilityName); } + } - if (configEntityMonster.getAbilities() != null) - for (var configAbilityData : configEntityMonster.getAbilities()) { - this.addConfigAbility(configAbilityData.abilityName); - } + if (optionalGroup.isPresent()) { + var group = optionalGroup.get(); + var monster = group.monsters.get(getConfigId()); + if (monster != null && monster.isElite) { + this.addConfigAbility(GameData.getConfigGlobalCombat() + .getDefaultAbilities() + .getMonterEliteAbilityName()); + } + } - if (optionalGroup.isPresent()) { - var group = optionalGroup.get(); - SceneMonster monster = group.monsters.get(getConfigId()); - if(monster != null && monster.isElite) { - addConfigAbility(GameData.getConfigGlobalCombat().getDefaultAbilities().getMonterEliteAbilityName()); + if (affixes != null) { + for (var affixId : affixes) { + var affix = GameData.getMonsterAffixDataMap().get(affixId.intValue()); + if (affix.isPreAdd()) continue; + + //Add the ability + for(var name : affix.getAbilityName()) { + this.addConfigAbility(name); } } + } - if (affixes != null) { - for (var affixId : affixes) { - var affix = GameData.getMonsterAffixDataMap().get(affixId.intValue()); - if(affix.isPreAdd()) continue; + var levelEntityConfig = getScene().getSceneData().getLevelEntityConfig(); + var config = GameData.getConfigLevelEntityDataMap().get(levelEntityConfig); + if (config == null){ + return; + } - //Add the ability - for(var name : affix.getAbilityName()) { - this.addConfigAbility(name); - } - } - } - - var levelEntityConfig = getScene().getSceneData().getLevelEntityConfig(); - var config = GameData.getConfigLevelEntityDataMap().get(levelEntityConfig); - if (config == null){ - return; - } - - if (config.getMonsterAbilities() != null) { - for (var monsterAbility : config.getMonsterAbilities()) { - addConfigAbility(monsterAbility.abilityName); - } + if (config.getMonsterAbilities() != null) { + for (var monsterAbility : config.getMonsterAbilities()) { + addConfigAbility(monsterAbility.abilityName); } } } diff --git a/src/main/java/emu/grasscutter/game/entity/GameEntity.java b/src/main/java/emu/grasscutter/game/entity/GameEntity.java index c1c195a63..1b0854f25 100644 --- a/src/main/java/emu/grasscutter/game/entity/GameEntity.java +++ b/src/main/java/emu/grasscutter/game/entity/GameEntity.java @@ -15,9 +15,10 @@ import emu.grasscutter.scripts.data.controller.EntityController; import emu.grasscutter.server.event.entity.*; import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; import it.unimi.dsi.fastutil.ints.*; -import java.util.*; import lombok.*; +import java.util.*; + public abstract class GameEntity { @Getter private final Scene scene; @Getter protected int id; @@ -338,4 +339,10 @@ public abstract class GameEntity { } public abstract SceneEntityInfo toProto(); + + @Override + public String toString() { + return "Entity ID: %s; Group ID: %s; Config ID: %s" + .formatted(this.getId(), this.getGroupId(), this.getConfigId()); + } } diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index 02a3df192..55bfc22be 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -23,8 +23,8 @@ import emu.grasscutter.game.props.*; import emu.grasscutter.game.quest.QuestGroupSuite; import emu.grasscutter.game.world.data.TeleportProperties; import emu.grasscutter.net.packet.BasePacket; -import emu.grasscutter.net.proto.*; import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult; +import emu.grasscutter.net.proto.*; import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType; import emu.grasscutter.scripts.*; import emu.grasscutter.scripts.constants.EventType; @@ -35,11 +35,12 @@ import emu.grasscutter.server.packet.send.*; import emu.grasscutter.server.scheduler.ServerTaskScheduler; import emu.grasscutter.utils.objects.KahnsSort; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import lombok.*; + +import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.*; import java.util.stream.Collectors; -import javax.annotation.Nullable; -import lombok.*; public final class Scene { @Getter private final World world; @@ -715,6 +716,11 @@ public final class Scene { * @param runnable The callback to be executed. */ public void runWhenHostInitialized(Runnable runnable) { + if (this.isFinishedLoading()) { + runnable.run(); + return; + } + this.afterHostInitCallbacks.add(runnable); } diff --git a/src/main/java/emu/grasscutter/scripts/EntityControllerScriptManager.java b/src/main/java/emu/grasscutter/scripts/EntityControllerScriptManager.java index db71338ea..05dbf1b50 100644 --- a/src/main/java/emu/grasscutter/scripts/EntityControllerScriptManager.java +++ b/src/main/java/emu/grasscutter/scripts/EntityControllerScriptManager.java @@ -1,14 +1,15 @@ package emu.grasscutter.scripts; -import static emu.grasscutter.utils.FileUtils.getScriptPath; - import emu.grasscutter.Grasscutter; import emu.grasscutter.scripts.data.controller.EntityController; +import lombok.val; + import java.io.IOException; import java.nio.file.Files; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import lombok.val; + +import static emu.grasscutter.utils.FileUtils.getScriptPath; public class EntityControllerScriptManager { private static final Map gadgetController = new ConcurrentHashMap<>(); @@ -30,7 +31,7 @@ public class EntityControllerScriptManager { if (cs == null) return; try { - cs.eval(bindings); + ScriptLoader.eval(cs, bindings); gadgetController.put(controllerName, new EntityController(cs, bindings)); } catch (Throwable e) { Grasscutter.getLogger().error("Error while loading gadget controller: {}.", fileName); diff --git a/src/main/java/emu/grasscutter/scripts/ScriptLib.java b/src/main/java/emu/grasscutter/scripts/ScriptLib.java index 3321dd9bf..ba7b02874 100644 --- a/src/main/java/emu/grasscutter/scripts/ScriptLib.java +++ b/src/main/java/emu/grasscutter/scripts/ScriptLib.java @@ -472,7 +472,7 @@ public class ScriptLib { private void printLog(String source, String msg){ var currentGroup = this.currentGroup.getIfExists(); - if(currentGroup != null) { + if (currentGroup != null) { Grasscutter.getLogger().trace("[LUA] {} {} {}", source, currentGroup.id, msg); } else { Grasscutter.getLogger().trace("[LUA] {} {}", source, msg); @@ -782,7 +782,7 @@ public class ScriptLib { return 1; } - public LuaTable GetSceneUidList(){ + public LuaTable GetSceneUidList() { logger.warn("[LUA] Call unchecked GetSceneUidList"); //TODO check var scriptManager = sceneScriptManager.getIfExists(); @@ -966,10 +966,12 @@ public class ScriptLib { var group = this.getCurrentGroup().get(); // Create a new time axis instance. - scriptManager.initTimeAxis(new SceneTimeAxis( + var timeAxis = new SceneTimeAxis( scriptManager, group.id, identifier, delays[0], shouldLoop - )); + ); + scriptManager.initTimeAxis(timeAxis); + timeAxis.start(); return 0; } diff --git a/src/main/java/emu/grasscutter/scripts/ScriptLoader.java b/src/main/java/emu/grasscutter/scripts/ScriptLoader.java index 0eef5a5b2..23d6bedc3 100644 --- a/src/main/java/emu/grasscutter/scripts/ScriptLoader.java +++ b/src/main/java/emu/grasscutter/scripts/ScriptLoader.java @@ -1,6 +1,6 @@ package emu.grasscutter.scripts; -import emu.grasscutter.Grasscutter; +import emu.grasscutter.*; import emu.grasscutter.game.dungeons.challenge.enums.*; import emu.grasscutter.game.props.*; import emu.grasscutter.game.quest.enums.QuestState; @@ -8,17 +8,19 @@ import emu.grasscutter.scripts.constants.*; import emu.grasscutter.scripts.data.SceneMeta; import emu.grasscutter.scripts.serializer.*; import emu.grasscutter.utils.FileUtils; -import java.lang.ref.SoftReference; -import java.nio.file.*; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import javax.script.*; import lombok.Getter; import org.luaj.vm2.*; import org.luaj.vm2.lib.OneArgFunction; import org.luaj.vm2.lib.jse.CoerceJavaToLua; import org.luaj.vm2.script.LuajContext; +import javax.script.*; +import java.lang.ref.SoftReference; +import java.nio.file.*; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; + public class ScriptLoader { private static ScriptEngineManager sm; @Getter private static ScriptEngine engine; @@ -32,6 +34,9 @@ public class ScriptLoader { /** sceneId - SceneMeta */ private static Map> sceneMetaCache = new ConcurrentHashMap<>(); + private static final AtomicReference currentBindings + = new AtomicReference<>(null); + public static synchronized void init() throws Exception { if (sm != null) { throw new Exception("Script loader already initialized"); @@ -104,25 +109,54 @@ public class ScriptLoader { } } + /** + * Performs a smart evaluation. + * This allows for 'require' to work. + * + * @param script The script to evaluate. + * @param bindings The bindings to use. + * @return The result of the evaluation. + */ + public static Object eval( + CompiledScript script, + Bindings bindings) + throws ScriptException { + // Set the current bindings. + currentBindings.set(bindings); + // Evaluate the script. + var result = script.eval(bindings); + // Clear the current bindings. + currentBindings.set(null); + + return result; + } + static final class RequireFunction extends OneArgFunction { @Override public LuaValue call(LuaValue arg) { // Resolve the script path. var scriptName = arg.checkjstring(); - var scriptPath = FileUtils.getScriptPath("Common/" + scriptName + ".lua"); + var scriptPath = "Common/" + scriptName + ".lua"; // Load & compile the script. - var script = ScriptLoader.getScript(scriptPath.toString()); + var script = ScriptLoader.getScript(scriptPath); if (script == null) { return LuaValue.NONE; } // Append the script to the context. try { - script.eval(); + var bindings = currentBindings.get(); + if (bindings != null) { + ScriptLoader.eval(script, bindings); + } else { + script.eval(); + } } catch (Exception exception) { - Grasscutter.getLogger() - .error("Loading script {} failed! - {}", scriptPath, exception.getLocalizedMessage()); + if (DebugConstants.LOG_MISSING_LUA_SCRIPTS) { + Grasscutter.getLogger() + .error("Loading script {} failed! - {}", scriptPath, exception.getLocalizedMessage()); + } } // TODO: What is the proper return value? diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneBlock.java b/src/main/java/emu/grasscutter/scripts/data/SceneBlock.java index b99390c59..dc71c4e3a 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneBlock.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneBlock.java @@ -1,19 +1,15 @@ package emu.grasscutter.scripts.data; import com.github.davidmoten.rtreemulti.RTree; -import com.github.davidmoten.rtreemulti.geometry.Geometry; -import com.github.davidmoten.rtreemulti.geometry.Rectangle; +import com.github.davidmoten.rtreemulti.geometry.*; import emu.grasscutter.Grasscutter; import emu.grasscutter.game.world.Position; -import emu.grasscutter.scripts.SceneIndexManager; -import emu.grasscutter.scripts.ScriptLoader; +import emu.grasscutter.scripts.*; +import lombok.*; + +import javax.script.*; import java.util.Map; import java.util.stream.Collectors; -import javax.script.Bindings; -import javax.script.CompiledScript; -import javax.script.ScriptException; -import lombok.Setter; -import lombok.ToString; @ToString @Setter @@ -61,7 +57,7 @@ public class SceneBlock { // Eval script try { - cs.eval(bindings); + ScriptLoader.eval(cs, bindings); // Set groups this.groups = diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java index 47322a38c..32835f9af 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java @@ -3,20 +3,12 @@ package emu.grasscutter.scripts.data; import emu.grasscutter.Grasscutter; import emu.grasscutter.game.world.Position; import emu.grasscutter.scripts.ScriptLoader; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Random; +import lombok.*; +import org.luaj.vm2.*; + +import javax.script.*; +import java.util.*; import java.util.stream.Collectors; -import javax.script.Bindings; -import javax.script.CompiledScript; -import javax.script.ScriptException; -import lombok.Getter; -import lombok.Setter; -import lombok.ToString; -import org.luaj.vm2.LuaError; -import org.luaj.vm2.LuaValue; @ToString @Setter @@ -105,7 +97,7 @@ public final class SceneGroup { // Eval script try { - cs.eval(this.bindings); + ScriptLoader.eval(cs, this.bindings); // Set this.monsters = diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneMeta.java b/src/main/java/emu/grasscutter/scripts/data/SceneMeta.java index 6b73e7c53..4377053a2 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneMeta.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneMeta.java @@ -3,16 +3,12 @@ package emu.grasscutter.scripts.data; import com.github.davidmoten.rtreemulti.RTree; import com.github.davidmoten.rtreemulti.geometry.Geometry; import emu.grasscutter.Grasscutter; -import emu.grasscutter.scripts.SceneIndexManager; -import emu.grasscutter.scripts.ScriptLoader; -import java.util.List; -import java.util.Map; +import emu.grasscutter.scripts.*; +import lombok.*; + +import javax.script.*; +import java.util.*; import java.util.stream.Collectors; -import javax.script.Bindings; -import javax.script.CompiledScript; -import javax.script.ScriptException; -import lombok.Setter; -import lombok.ToString; @ToString @Setter @@ -43,7 +39,7 @@ public class SceneMeta { // Eval script try { - cs.eval(this.context); + ScriptLoader.eval(cs, this.context); this.config = ScriptLoader.getSerializer() diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java index c18f48b79..7052a0c4a 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java @@ -1,8 +1,6 @@ package emu.grasscutter.server.packet.recv; -import static emu.grasscutter.config.Configuration.ACCOUNT; - -import emu.grasscutter.Grasscutter; +import emu.grasscutter.*; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.packet.*; @@ -13,9 +11,12 @@ import emu.grasscutter.server.game.GameSession.SessionState; import emu.grasscutter.server.packet.send.PacketGetPlayerTokenRsp; import emu.grasscutter.utils.*; import emu.grasscutter.utils.helpers.ByteHelper; + +import javax.crypto.Cipher; import java.nio.ByteBuffer; import java.security.Signature; -import javax.crypto.Cipher; + +import static emu.grasscutter.config.Configuration.ACCOUNT; @Opcodes(PacketOpcodes.GetPlayerTokenReq) public class HandlerGetPlayerTokenReq extends PacketHandler { @@ -28,9 +29,15 @@ public class HandlerGetPlayerTokenReq extends PacketHandler { var account = DispatchUtils.authenticate(accountId, req.getAccountToken()); // Check the account. - if (account == null) { + if (account == null && !DebugConstants.ACCEPT_CLIENT_TOKEN) { session.close(); return; + } else if (account == null && DebugConstants.ACCEPT_CLIENT_TOKEN) { + account = DispatchUtils.getAccountById(accountId); + if (account == null) { + session.close(); + return; + } } // Set account