Commit 4e75361a authored by AnimeGitB's avatar AnimeGitB
Browse files

Refactor GameData, remove deprecated getGsonFactory

- Fix day-of-week dungeons
- AvatarSkill max level enforcement from excels
- Partial fix to bonus levels (need packet on talent update)
parent bb342f91
......@@ -101,8 +101,6 @@ public final class Grasscutter {
// Create command map.
commandMap = new CommandMap(true);
// Generate handbooks.
Tools.createGmHandbooks();
// Initialize server.
Grasscutter.getLogger().info(translate("messages.status.starting"));
......@@ -114,6 +112,9 @@ public final class Grasscutter {
ResourceLoader.loadAll();
ScriptLoader.init();
// Generate handbooks.
Tools.createGmHandbooks();
// Initialize database.
DatabaseManager.initialize();
......@@ -274,11 +275,6 @@ public final class Grasscutter {
return consoleLineReader;
}
@Deprecated(forRemoval = true)
public static Gson getGsonFactory() {
return JsonUtils.getGsonFactory();
}
public static HttpServer getHttpServer() {
return httpServer;
}
......@@ -310,6 +306,7 @@ public final class Grasscutter {
public static void updateDayOfWeek() {
Calendar calendar = Calendar.getInstance();
day = calendar.get(Calendar.DAY_OF_WEEK);
Grasscutter.getLogger().debug("Set day of week to "+day);
}
public static void startConsole() {
......
......@@ -5,6 +5,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.*;
......@@ -16,6 +17,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.Getter;
import lombok.experimental.Tolerate;
......@@ -26,7 +28,8 @@ public class GameData {
@Getter private static final Map<String, AbilityModifierEntry> abilityModifiers = new HashMap<>();
@Getter private static final Map<String, ConfigGadget> gadgetConfigData = new HashMap<>();
@Getter private static final Map<String, OpenConfigEntry> openConfigEntries = new HashMap<>();
@Getter private static final Map<String, ScenePointEntry> scenePointEntries = new HashMap<>();
@Deprecated(forRemoval = true) @Getter private static final Map<String, ScenePointEntry> scenePointEntries = new HashMap<>();
protected static final Int2ObjectMap<ScenePointEntry> scenePointEntryMap = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<MainQuestData> mainQuestData = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<QuestEncryptionKey> questsKeys = new Int2ObjectOpenHashMap<>();
private static final Int2ObjectMap<SceneNpcBornData> npcBornData = new Int2ObjectOpenHashMap<>();
......@@ -118,6 +121,8 @@ public class GameData {
@Getter private static final Map<String, ScriptSceneData> scriptSceneDataMap = new HashMap<>();
private static Map<Integer, List<Integer>> fetters = new HashMap<>();
private static Map<Integer, List<ShopGoodsData>> shopGoods = new HashMap<>();
protected static Int2ObjectMap<IntSet> proudSkillGroupLevels = new Int2ObjectOpenHashMap<>();
protected static Int2ObjectMap<IntSet> avatarSkillLevels = new Int2ObjectOpenHashMap<>();
// Getters with wrong names, remove later
@Deprecated(forRemoval = true) public static Int2ObjectMap<CodexReliquaryData> getcodexReliquaryIdMap() {return codexReliquaryDataIdMap;}
......@@ -130,7 +135,42 @@ public class GameData {
public static Int2ObjectMap<SceneNpcBornData> getSceneNpcBornData() {return npcBornData;}
public static Map<String, AbilityEmbryoEntry> getAbilityEmbryoInfo() {return abilityEmbryos;}
// Getters that get values rather than containers. If Lombok ever gets syntactic sugar for this, we should adopt that.
public static IntSet getAvatarSkillLevels(int avatarSkillId) {return avatarSkillLevels.get(avatarSkillId);}
public static IntSet getProudSkillGroupLevels(int proudSkillGroupId) {return proudSkillGroupLevels.get(proudSkillGroupId);}
// Multi-keyed getters
public static AvatarPromoteData getAvatarPromoteData(int promoteId, int promoteLevel) {
return avatarPromoteDataMap.get((promoteId << 8) + promoteLevel);
}
public static WeaponPromoteData getWeaponPromoteData(int promoteId, int promoteLevel) {
return weaponPromoteDataMap.get((promoteId << 8) + promoteLevel);
}
public static ReliquaryLevelData getRelicLevelData(int rankLevel, int level) {
return reliquaryLevelDataMap.get((rankLevel << 8) + level);
}
public static ScenePointEntry getScenePointEntryById(int sceneId, int pointId) {
return scenePointEntryMap.get((sceneId << 16) + pointId);
}
// Non-nullable value getters
public static int getAvatarLevelExpRequired(int level) {
return Optional.ofNullable(avatarLevelDataMap.get(level)).map(d -> d.getExp()).orElse(0);
}
public static int getAvatarFetterLevelExpRequired(int level) {
return Optional.ofNullable(avatarFetterLevelDataMap.get(level)).map(d -> d.getExp()).orElse(0);
}
public static int getRelicExpRequired(int rankLevel, int level) {
return Optional.ofNullable(getRelicLevelData(rankLevel, level)).map(d -> d.getExp()).orElse(0);
}
// Generic getter
public static Int2ObjectMap<?> getMapByResourceDef(Class<?> resourceDefinition) {
Int2ObjectMap<?> map = null;
......@@ -149,24 +189,6 @@ public class GameData {
// TODO optimize
public static ScenePointEntry getScenePointEntryById(int sceneId, int pointId) {
return getScenePointEntries().get(sceneId + "_" + pointId);
}
public static int getRelicExpRequired(int rankLevel, int level) {
ReliquaryLevelData levelData = reliquaryLevelDataMap.get((rankLevel << 8) + level);
return levelData != null ? levelData.getExp() : 0;
}
public static ReliquaryLevelData getRelicLevelData(int rankLevel, int level) {
return reliquaryLevelDataMap.get((rankLevel << 8) + level);
}
public static WeaponPromoteData getWeaponPromoteData(int promoteId, int promoteLevel) {
return weaponPromoteDataMap.get((promoteId << 8) + promoteLevel);
}
public static int getWeaponExpRequired(int rankLevel, int level) {
WeaponLevelData levelData = weaponLevelDataMap.get(level);
if (levelData == null) {
......@@ -179,21 +201,6 @@ public class GameData {
}
}
public static AvatarPromoteData getAvatarPromoteData(int promoteId, int promoteLevel) {
return avatarPromoteDataMap.get((promoteId << 8) + promoteLevel);
}
public static int getAvatarLevelExpRequired(int level) {
AvatarLevelData levelData = avatarLevelDataMap.get(level);
return levelData != null ? levelData.getExp() : 0;
}
public static int getAvatarFetterLevelExpRequired(int level) {
AvatarFetterLevelData levelData = avatarFetterLevelDataMap.get(level);
return levelData != null ? levelData.getExp() : 0;
}
public static Map<Integer, List<Integer>> getFetterDataEntries() {
if (fetters.isEmpty()) {
fetterDataMap.forEach((k, v) -> {
......
package emu.grasscutter.data;
import com.google.gson.JsonElement;
import com.google.gson.annotations.SerializedName;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.binout.*;
import emu.grasscutter.data.binout.AbilityModifier.AbilityConfigData;
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierActionType;
import emu.grasscutter.data.common.PointData;
import emu.grasscutter.data.common.ScenePointConfig;
import emu.grasscutter.game.managers.blossom.BlossomConfig;
import emu.grasscutter.game.quest.QuestEncryptionKey;
import emu.grasscutter.game.world.SpawnDataEntry;
......@@ -16,6 +14,8 @@ import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry;
import emu.grasscutter.scripts.SceneIndexManager;
import emu.grasscutter.utils.JsonUtils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntArraySet;
import lombok.val;
import org.reflections.Reflections;
......@@ -75,6 +75,7 @@ public class ResourceLoader {
loadHomeworldDefaultSaveData();
loadNpcBornData();
loadBlossomResources();
cacheTalentLevelSets();
Grasscutter.getLogger().info(translate("messages.status.resources.finish"));
loadedAll = true;
......@@ -129,6 +130,9 @@ public class ResourceLoader {
}
}
public class ScenePointConfig { // Sadly this doesn't work as a local class in loadScenePoints()
public Map<Integer, PointData> points;
}
private static void loadScenePoints() {
val pattern = Pattern.compile("scene([0-9]+)_point\\.json");
try {
......@@ -136,8 +140,8 @@ public class ResourceLoader {
val matcher = pattern.matcher(path.getFileName().toString());
if (!matcher.find()) return;
int sceneId = Integer.parseInt(matcher.group(1));
ScenePointConfig config;
ScenePointConfig config;
try {
config = JsonUtils.loadToClass(path, ScenePointConfig.class);
} catch (Exception e) {
......@@ -147,20 +151,18 @@ public class ResourceLoader {
if (config.points == null) return;
List<Integer> scenePoints = new ArrayList<>();
for (Map.Entry<String, JsonElement> entry : config.points.entrySet()) {
String key = entry.getKey();
String name = sceneId + "_" + key;
int id = Integer.parseInt(key);
PointData pointData = JsonUtils.decode(entry.getValue(), PointData.class);
pointData.setId(id);
val scenePoints = new IntArrayList();
config.points.forEach((pointId, pointData) -> {
val scenePoint = new ScenePointEntry(sceneId, pointData);
scenePoints.add(pointId);
pointData.setId(pointId);
GameData.getScenePointIdList().add(id);
GameData.getScenePointEntries().put(name, new ScenePointEntry(name, pointData));
scenePoints.add(id);
GameData.getScenePointIdList().add(pointId);
GameData.getScenePointEntries().put(scenePoint.getName(), scenePoint);
GameData.scenePointEntryMap.put((sceneId << 16) + pointId, scenePoint);
pointData.updateDailyDungeon();
}
});
GameData.getScenePointsPerScene().put(sceneId, scenePoints);
});
} catch (IOException e) {
......@@ -169,6 +171,15 @@ public class ResourceLoader {
}
}
private static void cacheTalentLevelSets() {
GameData.getProudSkillDataMap().forEach((id, data) ->
GameData.proudSkillGroupLevels
.computeIfAbsent(data.getProudSkillGroupId(), i -> new IntArraySet())
.add(data.getLevel()));
GameData.getAvatarSkillDataMap().forEach((id, data) ->
GameData.avatarSkillLevels.put((int) id, GameData.proudSkillGroupLevels.get(data.getProudSkillGroupId())));
}
private static void loadAbilityEmbryos() {
List<AbilityEmbryoEntry> embryoList = null;
......
package emu.grasscutter.data.binout;
import emu.grasscutter.data.common.PointData;
import lombok.Getter;
public class ScenePointEntry {
private String name;
private PointData pointData;
public ScenePointEntry(String name, PointData pointData) {
this.name = name;
this.pointData = pointData;
}
@Getter final private int sceneId;
@Getter final private PointData pointData;
public String getName() {
return name;
}
@Deprecated(forRemoval = true)
public ScenePointEntry(String name, PointData pointData) {
this.sceneId = Integer.parseInt(name.split("_")[0]);
this.pointData = pointData;
}
public ScenePointEntry(int sceneId, PointData pointData) {
this.sceneId = sceneId;
this.pointData = pointData;
}
public PointData getPointData() {
return pointData;
public String getName() {
return this.sceneId + "_" + this.pointData.getId();
}
}
......@@ -5,71 +5,44 @@ import com.google.gson.annotations.SerializedName;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.excels.DailyDungeonData;
import emu.grasscutter.utils.JsonUtils;
import emu.grasscutter.utils.Position;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import lombok.Getter;
import lombok.Setter;
public class PointData {
private int id;
@Getter @Setter private int id;
private String $type;
private Position tranPos;
@Getter private Position tranPos;
@SerializedName(value="dungeonIds", alternate={"JHHFPGJNMIN"})
private int[] dungeonIds;
@Getter private int[] dungeonIds;
@SerializedName(value="dungeonRandomList", alternate={"OIBKFJNBLHO"})
private int[] dungeonRandomList;
@Getter private int[] dungeonRandomList;
@SerializedName(value="tranSceneId", alternate={"JHBICGBAPIH"})
private int tranSceneId;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Getter @Setter private int tranSceneId;
public String getType() {
return $type;
}
public Position getTranPos() {
return tranPos;
}
public int[] getDungeonIds() {
return dungeonIds;
}
public int[] getDungeonRandomList() {
return dungeonRandomList;
}
public int getTranSceneId() {
return tranSceneId;
}
public void setTranSceneId(int tranSceneId) {
this.tranSceneId = tranSceneId;
}
public void updateDailyDungeon() {
if (getDungeonRandomList() == null || getDungeonRandomList().length == 0) {
if (this.dungeonRandomList == null || this.dungeonRandomList.length == 0) {
return;
}
IntList newDungeons = new IntArrayList();
int day = Grasscutter.getCurrentDayOfWeek();
for (int randomId : getDungeonRandomList()) {
for (int randomId : this.dungeonRandomList) {
DailyDungeonData data = GameData.getDailyDungeonDataMap().get(randomId);
if (data != null) {
int[] addDungeons = data.getDungeonsByDay(day);
for (int d : addDungeons) {
for (int d : data.getDungeonsByDay(day)) {
newDungeons.add(d);
}
}
......
package emu.grasscutter.data.common;
import com.google.gson.JsonObject;
public class ScenePointConfig {
public JsonObject points;
public JsonObject getPoints() {
return points;
}
public void setPoints(JsonObject Points) {
points = Points;
}
}
......@@ -2,11 +2,9 @@ package emu.grasscutter.data.excels;
import java.util.Calendar;
import emu.grasscutter.data.GameData;
import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType;
import emu.grasscutter.game.props.SceneType;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
......
......@@ -67,6 +67,7 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import lombok.Getter;
import lombok.Setter;
import lombok.val;
@Entity(value = "avatars", useDiscriminator = false)
public class Avatar {
......@@ -96,7 +97,7 @@ public class Avatar {
private Map<Integer, Integer> skillLevelMap; // Talent levels
private Map<Integer, Integer> skillExtraChargeMap; // Charges
@Getter private Map<Integer, Integer> proudSkillBonusMap; // Talent bonus levels (from const)
private Map<Integer, Integer> proudSkillBonusMap; // Talent bonus levels (from const)
@Getter private int skillDepotId;
private Set<Integer> talentIdList; // Constellation id list
@Getter private Set<Integer> proudSkillList; // Character passives
......@@ -301,8 +302,28 @@ public class Avatar {
public Map<Integer, Integer> getSkillLevelMap() { // Returns a copy of the skill levels for the current skillDepot.
var map = new Int2IntOpenHashMap();
this.skillDepot.getSkillsAndEnergySkill()
.forEach(skillId -> map.put(skillId, this.skillLevelMap.computeIfAbsent(skillId, id -> 1).intValue()));
this.skillDepot.getSkillsAndEnergySkill().forEach(skillId ->
map.put(skillId, this.skillLevelMap.putIfAbsent(skillId, 1).intValue()));
return map;
}
// Returns a copy of the skill bonus levels for the current skillDepot, capped to avoid invalid levels.
public Map<Integer, Integer> getProudSkillBonusMap() {
var map = new Int2IntOpenHashMap();
this.skillDepot.getSkillsAndEnergySkill().forEach(skillId -> {
val skillData = GameData.getAvatarSkillDataMap().get(skillId);
if (skillData == null) return;
int proudSkillGroupId = skillData.getProudSkillGroupId();
int bonus = this.proudSkillBonusMap.getOrDefault(proudSkillGroupId, 0);
val validLevels = GameData.getProudSkillGroupLevels(proudSkillGroupId);
if (validLevels != null && validLevels.size() > 0) {
int maxLevel = validLevels.intStream().max().getAsInt();
int maxBonus = maxLevel - this.skillLevelMap.getOrDefault(skillId, 0);
if (maxBonus < bonus)
bonus = maxBonus;
}
map.put(proudSkillGroupId, bonus);
});
return map;
}
......@@ -705,10 +726,14 @@ public class Avatar {
}
// Add to bonus list
this.getProudSkillBonusMap().put(skillData.getProudSkillGroupId(), 3);
this.addProudSkillLevelBonus(skillId, 3);
return true;
}
private int addProudSkillLevelBonus(int proudSkillGroupId, int bonus) {
return this.proudSkillBonusMap.compute(proudSkillGroupId, (k,v) -> (v==null) ? bonus : v + bonus);
}
public boolean upgradeSkill(int skillId) {
AvatarSkillData skillData = GameData.getAvatarSkillDataMap().get(skillId);
if (skillData == null) return false;
......@@ -735,6 +760,9 @@ public class Avatar {
public boolean setSkillLevel(int skillId, int level) {
if (level < 0 || level > 15) return false;
var validLevels = GameData.getAvatarSkillLevels(skillId);
if (validLevels != null && !validLevels.contains(level)) return false;
int oldLevel = this.skillLevelMap.getOrDefault(skillId, 0); // just taking the return value of put would have null concerns
this.skillLevelMap.put(skillId, level);
this.save();
......
......@@ -107,8 +107,6 @@ public class DungeonSystem extends BaseGameSystem {
}
public void updateDailyDungeons() {
for (ScenePointEntry entry : GameData.getScenePointEntries().values()) {
entry.getPointData().updateDailyDungeon();
}
GameData.getScenePointEntries().forEach((id, entry) -> entry.getPointData().updateDailyDungeon());
}
}
......@@ -102,7 +102,7 @@ public class PlayerCodex {
}
public void checkUnlockedSuits(int reliquaryId){
GameData.getcodexReliquaryArrayList().stream()
GameData.getCodexReliquaryArrayList().stream()
.filter(x -> !this.getUnlockedReliquarySuitCodex().contains(x.getId()))
.filter(x -> x.containsId(reliquaryId))
.filter(x -> this.getUnlockedReliquary().containsAll(x.getIds()))
......@@ -121,7 +121,7 @@ public class PlayerCodex {
this.unlockedReliquary.forEach(i -> newReliquaries.add((i/10)*10));
this.unlockedReliquary = newReliquaries;
GameData.getcodexReliquaryArrayList().stream()
GameData.getCodexReliquaryArrayList().stream()
.filter(x -> !this.getUnlockedReliquarySuitCodex().contains(x.getId()))
.filter(x -> this.getUnlockedReliquary().containsAll(x.getIds()))
.forEach(x -> this.getUnlockedReliquarySuitCodex().add(x.getId()));
......
......@@ -198,8 +198,7 @@ public class PlayerProgressManager extends BasePlayerDataManager {
public boolean unlockTransPoint(int sceneId, int pointId, boolean isStatue) {
// Check whether the unlocked point exists and whether it is still locked.
String key = sceneId + "_" + pointId;
ScenePointEntry scenePointEntry = GameData.getScenePointEntries().get(key);
ScenePointEntry scenePointEntry = GameData.getScenePointEntryById(sceneId, pointId);
if (scenePointEntry == null || this.player.getUnlockedScenePoints(sceneId).contains(pointId)) {
return false;
......
......@@ -20,8 +20,7 @@ public class HandlerPersonalSceneJumpReq extends PacketHandler {
var player = session.getPlayer();
// get the scene point
String code = player.getSceneId() + "_" + req.getPointId();
ScenePointEntry scenePointEntry = GameData.getScenePointEntries().get(code);
ScenePointEntry scenePointEntry = GameData.getScenePointEntryById(player.getSceneId(), req.getPointId());
if (scenePointEntry != null) {
Position pos = scenePointEntry.getPointData().getTranPos().clone(); // This might not need cloning
......
......@@ -18,8 +18,7 @@ public class HandlerSceneTransToPointReq extends PacketHandler {
SceneTransToPointReq req = SceneTransToPointReq.parseFrom(payload);
var player = session.getPlayer();
String code = req.getSceneId() + "_" + req.getPointId();
ScenePointEntry scenePointEntry = GameData.getScenePointEntries().get(code);
ScenePointEntry scenePointEntry = GameData.getScenePointEntryById(req.getSceneId(), req.getPointId());
if (scenePointEntry != null) {
if (player.getWorld().transferPlayerToScene(player, req.getSceneId(), TeleportType.WAYPOINT, scenePointEntry.getPointData().getTranPos().clone())) {
......
......@@ -59,11 +59,6 @@ public final class JsonUtils {
.registerTypeAdapter(DynamicFloat.class, new DynamicFloatAdapter())
.create();
@Deprecated(forRemoval = true)
public static Gson getGsonFactory() {
return gson;
}
/*
* Encode an object to a JSON string
*/
......@@ -79,7 +74,7 @@ public final class JsonUtils {
return gson.fromJson(fileReader, classType);
}
@Deprecated
@Deprecated(forRemoval = true)
public static <T> T loadToClass(String filename, Class<T> classType) throws IOException {
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(filename)), StandardCharsets.UTF_8)) {
return loadToClass(fileReader, classType);
......@@ -96,7 +91,7 @@ public final class JsonUtils {
return gson.fromJson(fileReader, TypeToken.getParameterized(List.class, classType).getType());
}
@Deprecated
@Deprecated(forRemoval = true)
public static <T> List<T> loadToList(String filename, Class<T> classType) throws IOException {
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(filename)), StandardCharsets.UTF_8)) {
return loadToList(fileReader, classType);
......@@ -113,7 +108,7 @@ public final class JsonUtils {
return gson.fromJson(fileReader, TypeToken.getParameterized(Map.class, keyType, valueType).getType());
}
@Deprecated
@Deprecated(forRemoval = true)
public static <T1,T2> Map<T1,T2> loadToMap(String filename, Class<T1> keyType, Class<T2> valueType) throws IOException {
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(filename)), StandardCharsets.UTF_8)) {
return loadToMap(fileReader, keyType, valueType);
......
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