Implement a proper ability system (#2166)

* Apply fix `21dec2fe`

* Apply fix `89d01d5f`

* Apply fix `d900f154`

this one was already implemented; updated to use call from previous commit

* Ability changing commit

TODO: change info to debug

* Remove use of deprecated methods/fields

* Temp commit v2
(Adding LoseHP and some fixes)

* Oopsie

* Probably fix monster battle

* Fix issue with reflecting into fields

* Fix some things

* Fix ability names for 3.6 resources

* Improve logging

---------

Co-authored-by: StartForKiller <jesussanz2003@gmail.com>
This commit is contained in:
Magix
2023-05-29 23:40:02 -07:00
committed by GitHub
parent 9b58105120
commit f00c54cb95
71 changed files with 2015 additions and 995 deletions

View File

@@ -1,10 +1,7 @@
package emu.grasscutter.data;
import static emu.grasscutter.utils.FileUtils.getDataPath;
import static emu.grasscutter.utils.FileUtils.getResourcePath;
import static emu.grasscutter.utils.lang.Language.translate;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.*;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
@@ -15,6 +12,7 @@ import emu.grasscutter.data.custom.TrialAvatarCustomData;
import emu.grasscutter.data.excels.trial.TrialAvatarActivityDataData;
import emu.grasscutter.data.server.ActivityCondGroup;
import emu.grasscutter.data.server.GadgetMapping;
import emu.grasscutter.data.server.MonsterMapping;
import emu.grasscutter.game.managers.blossom.BlossomConfig;
import emu.grasscutter.game.quest.QuestEncryptionKey;
import emu.grasscutter.game.quest.RewindData;
@@ -29,10 +27,17 @@ import emu.grasscutter.scripts.ScriptLoader;
import emu.grasscutter.utils.FileUtils;
import emu.grasscutter.utils.JsonUtils;
import emu.grasscutter.utils.TsvUtils;
import emu.grasscutter.utils.Utils;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntArraySet;
import lombok.SneakyThrows;
import lombok.val;
import org.reflections.Reflections;
import javax.script.Bindings;
import javax.script.CompiledScript;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
@@ -44,11 +49,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.script.Bindings;
import javax.script.CompiledScript;
import lombok.SneakyThrows;
import lombok.val;
import org.reflections.Reflections;
import static emu.grasscutter.utils.FileUtils.getDataPath;
import static emu.grasscutter.utils.FileUtils.getResourcePath;
import static emu.grasscutter.utils.lang.Language.translate;
public final class ResourceLoader {
@@ -108,6 +112,7 @@ public final class ResourceLoader {
loadConfigData();
// Load ability lists
loadAbilityEmbryos();
loadTalents();
loadOpenConfig();
loadAbilityModifiers();
// Load resources
@@ -130,9 +135,11 @@ public final class ResourceLoader {
loadConfigLevelEntityData();
loadQuestShareConfig();
loadGadgetMappings();
loadMonsterMappings();
loadActivityCondGroups();
loadGroupReplacements();
loadTrialAvatarCustomData();
loadGlobalCombatConfig();
EntityControllerScriptManager.load();
@@ -223,6 +230,14 @@ public final class ResourceLoader {
});
}
private static void loadGlobalCombatConfig(){
try {
GameData.setConfigGlobalCombat(JsonUtils.loadToClass(getResourcePath("BinOutput/Common/ConfigGlobalCombat.json"), ConfigGlobalCombat.class));
} catch (IOException e) {
Grasscutter.getLogger().error("Cannot load ConfigGlobalCombat.json, this error is important, fix it!");
}
}
private static void loadScenePoints() {
val pattern = Pattern.compile("scene([0-9]+)_point\\.json");
try {
@@ -384,12 +399,13 @@ public final class ResourceLoader {
private static void loadAbilityData(AbilityData data) {
GameData.getAbilityDataMap().put(data.abilityName, data);
GameData.getAbilityHashes().put(Utils.abilityHash(data.abilityName), data.abilityName);
val modifiers = data.modifiers;
var modifiers = data.modifiers;
if (modifiers == null || modifiers.size() == 0) return;
String name = data.abilityName;
AbilityModifierEntry modifierEntry = new AbilityModifierEntry(name);
var name = data.abilityName;
var modifierEntry = new AbilityModifierEntry(name);
modifiers.forEach(
(key, modifier) -> {
Stream.ofNullable(modifier.onAdded)
@@ -408,8 +424,29 @@ public final class ResourceLoader {
.filter(action -> action.type == AbilityModifierAction.Type.HealHP)
.forEach(action -> modifierEntry.getOnRemoved().add(action));
});
}
GameData.getAbilityModifiers().put(name, modifierEntry);
private static void loadTalents() {
// Load from BinOutput
try (var paths = Files.walk(getResourcePath("BinOutput/Talent/AvatarTalents/"))) {
paths.filter(Files::isDirectory).forEach((folderPath) -> {
try (var paths2 = Files.walk(folderPath)) {
paths2.filter(Files::isRegularFile).filter(path -> path.toString().endsWith(".json")).forEach(ResourceLoader::loadTalent);
} catch (IOException e) {
Grasscutter.getLogger().error("Error loading talents: ", e);
}
});
} catch (IOException e) {
Grasscutter.getLogger().error("Error loading talents: ", e);
}
}
private static void loadTalent(Path path) {
try {
GameData.getTalents().putAll(JsonUtils.loadToMap(path, String.class, new TypeToken<List<TalentData>>() {}.getType()));
} catch (IOException e) {
Grasscutter.getLogger().error("Error loading ability modifiers from path " + path.toString() + ": ", e);
}
}
private static void loadSpawnData() {
@@ -773,6 +810,20 @@ public final class ResourceLoader {
}
}
private static void loadMonsterMappings() {
try {
var monsterMap = GameData.getMonsterMappingMap();
try {
JsonUtils.loadToList(getResourcePath("Server/MonsterMapping.json"), MonsterMapping.class)
.forEach(entry -> monsterMap.put(entry.getMonsterId(), entry));
} catch (IOException | NullPointerException ignored) {}
Grasscutter.getLogger().debug("Loaded {} monster mappings.", monsterMap.size());
} catch (Exception e) {
Grasscutter.getLogger().error("Unable to load monster mappings.", e);
}
}
private static void loadActivityCondGroups() {
try {
val gadgetMap = GameData.getActivityCondGroupMap();
@@ -914,7 +965,7 @@ public final class ResourceLoader {
public int pointDelta;
}
public class ScenePointConfig { // Sadly this doesn't work as a local class in loadScenePoints()
public static class ScenePointConfig { // Sadly this doesn't work as a local class in loadScenePoints()
public Map<Integer, PointData> points;
}
}