Commit ae2d1fe4 authored by github-actions's avatar github-actions Committed by Melledy
Browse files

Fix whitespace [skip actions]

parent 510d564b
...@@ -22,47 +22,47 @@ public class GameDepot { ...@@ -22,47 +22,47 @@ public class GameDepot {
private static Int2ObjectMap<List<ReliquaryMainPropData>> relicMainPropDepot = new Int2ObjectOpenHashMap<>(); private static Int2ObjectMap<List<ReliquaryMainPropData>> relicMainPropDepot = new Int2ObjectOpenHashMap<>();
private static Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot = new Int2ObjectOpenHashMap<>(); private static Int2ObjectMap<List<ReliquaryAffixData>> relicAffixDepot = new Int2ObjectOpenHashMap<>();
private static Map<String, AvatarConfig> playerAbilities = new HashMap<>(); private static Map<String, AvatarConfig> playerAbilities = new HashMap<>();
private static HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> spawnLists = new HashMap<>(); private static HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> spawnLists = new HashMap<>();
public static void load() { public static void load() {
for (ReliquaryMainPropData data : GameData.getReliquaryMainPropDataMap().values()) { for (ReliquaryMainPropData data : GameData.getReliquaryMainPropDataMap().values()) {
if (data.getWeight() <= 0 || data.getPropDepotId() <= 0) { if (data.getWeight() <= 0 || data.getPropDepotId() <= 0) {
continue; continue;
} }
List<ReliquaryMainPropData> list = relicMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new ArrayList<>()); List<ReliquaryMainPropData> list = relicMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new ArrayList<>());
list.add(data); list.add(data);
WeightedList<ReliquaryMainPropData> weightedList = relicRandomMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new WeightedList<>()); WeightedList<ReliquaryMainPropData> weightedList = relicRandomMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new WeightedList<>());
weightedList.add(data.getWeight(), data); weightedList.add(data.getWeight(), data);
} }
for (ReliquaryAffixData data : GameData.getReliquaryAffixDataMap().values()) { for (ReliquaryAffixData data : GameData.getReliquaryAffixDataMap().values()) {
if (data.getWeight() <= 0 || data.getDepotId() <= 0) { if (data.getWeight() <= 0 || data.getDepotId() <= 0) {
continue; continue;
} }
List<ReliquaryAffixData> list = relicAffixDepot.computeIfAbsent(data.getDepotId(), k -> new ArrayList<>()); List<ReliquaryAffixData> list = relicAffixDepot.computeIfAbsent(data.getDepotId(), k -> new ArrayList<>());
list.add(data); list.add(data);
} }
// Let the server owner know if theyre missing weights // Let the server owner know if theyre missing weights
if (relicMainPropDepot.size() == 0 || relicAffixDepot.size() == 0) { if (relicMainPropDepot.size() == 0 || relicAffixDepot.size() == 0) {
Grasscutter.getLogger().error("Relic properties are missing weights! Please check your ReliquaryMainPropExcelConfigData or ReliquaryAffixExcelConfigData files in your ExcelBinOutput folder."); Grasscutter.getLogger().error("Relic properties are missing weights! Please check your ReliquaryMainPropExcelConfigData or ReliquaryAffixExcelConfigData files in your ExcelBinOutput folder.");
} }
} }
public static ReliquaryMainPropData getRandomRelicMainProp(int depot) { public static ReliquaryMainPropData getRandomRelicMainProp(int depot) {
WeightedList<ReliquaryMainPropData> depotList = relicRandomMainPropDepot.get(depot); WeightedList<ReliquaryMainPropData> depotList = relicRandomMainPropDepot.get(depot);
if (depotList == null) { if (depotList == null) {
return null; return null;
} }
return depotList.next(); return depotList.next();
} }
public static List<ReliquaryMainPropData> getRelicMainPropList(int depot) { public static List<ReliquaryMainPropData> getRelicMainPropList(int depot) {
return relicMainPropDepot.get(depot); return relicMainPropDepot.get(depot);
} }
public static List<ReliquaryAffixData> getRelicAffixList(int depot) { public static List<ReliquaryAffixData> getRelicAffixList(int depot) {
return relicAffixDepot.get(depot); return relicAffixDepot.get(depot);
} }
public static HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> getSpawnLists() { public static HashMap<SpawnDataEntry.GridBlockId, ArrayList<SpawnDataEntry>> getSpawnLists() {
return spawnLists; return spawnLists;
...@@ -72,9 +72,9 @@ public class GameDepot { ...@@ -72,9 +72,9 @@ public class GameDepot {
spawnLists.putAll(data); spawnLists.putAll(data);
} }
public static void setPlayerAbilities(Map<String, AvatarConfig> playerAbilities) { public static void setPlayerAbilities(Map<String, AvatarConfig> playerAbilities) {
GameDepot.playerAbilities = playerAbilities; GameDepot.playerAbilities = playerAbilities;
} }
public static Map<String, AvatarConfig> getPlayerAbilities() { public static Map<String, AvatarConfig> getPlayerAbilities() {
return playerAbilities; return playerAbilities;
......
...@@ -34,281 +34,281 @@ import static emu.grasscutter.utils.Language.translate; ...@@ -34,281 +34,281 @@ import static emu.grasscutter.utils.Language.translate;
public class ResourceLoader { public class ResourceLoader {
private static final List<String> loadedResources = new ArrayList<>(); private static final List<String> loadedResources = new ArrayList<>();
public static List<Class<?>> getResourceDefClasses() { public static List<Class<?>> getResourceDefClasses() {
Reflections reflections = new Reflections(ResourceLoader.class.getPackage().getName()); Reflections reflections = new Reflections(ResourceLoader.class.getPackage().getName());
Set<?> classes = reflections.getSubTypesOf(GameResource.class); Set<?> classes = reflections.getSubTypesOf(GameResource.class);
List<Class<?>> classList = new ArrayList<>(classes.size()); List<Class<?>> classList = new ArrayList<>(classes.size());
classes.forEach(o -> { classes.forEach(o -> {
Class<?> c = (Class<?>) o; Class<?> c = (Class<?>) o;
if (c.getAnnotation(ResourceType.class) != null) { if (c.getAnnotation(ResourceType.class) != null) {
classList.add(c); classList.add(c);
} }
}); });
classList.sort((a, b) -> b.getAnnotation(ResourceType.class).loadPriority().value() - a.getAnnotation(ResourceType.class).loadPriority().value()); classList.sort((a, b) -> b.getAnnotation(ResourceType.class).loadPriority().value() - a.getAnnotation(ResourceType.class).loadPriority().value());
return classList; return classList;
} }
public static void loadAll() { public static void loadAll() {
Grasscutter.getLogger().info(translate("messages.status.resources.loading")); Grasscutter.getLogger().info(translate("messages.status.resources.loading"));
// Load ability lists // Load ability lists
loadAbilityEmbryos(); loadAbilityEmbryos();
loadOpenConfig(); loadOpenConfig();
loadAbilityModifiers(); loadAbilityModifiers();
// Load resources // Load resources
loadResources(); loadResources();
// Process into depots // Process into depots
GameDepot.load(); GameDepot.load();
// Load spawn data and quests // Load spawn data and quests
loadSpawnData(); loadSpawnData();
loadQuests(); loadQuests();
// Load scene points - must be done AFTER resources are loaded // Load scene points - must be done AFTER resources are loaded
loadScenePoints(); loadScenePoints();
// Load default home layout // Load default home layout
loadHomeworldDefaultSaveData(); loadHomeworldDefaultSaveData();
loadNpcBornData(); loadNpcBornData();
Grasscutter.getLogger().info(translate("messages.status.resources.finish")); Grasscutter.getLogger().info(translate("messages.status.resources.finish"));
} }
public static void loadResources() { public static void loadResources() {
loadResources(false); loadResources(false);
} }
public static void loadResources(boolean doReload) { public static void loadResources(boolean doReload) {
for (Class<?> resourceDefinition : getResourceDefClasses()) { for (Class<?> resourceDefinition : getResourceDefClasses()) {
ResourceType type = resourceDefinition.getAnnotation(ResourceType.class); ResourceType type = resourceDefinition.getAnnotation(ResourceType.class);
if (type == null) { if (type == null) {
continue; continue;
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
Int2ObjectMap map = GameData.getMapByResourceDef(resourceDefinition); Int2ObjectMap map = GameData.getMapByResourceDef(resourceDefinition);
if (map == null) { if (map == null) {
continue; continue;
} }
try { try {
loadFromResource(resourceDefinition, type, map, doReload); loadFromResource(resourceDefinition, type, map, doReload);
} catch (Exception e) { } catch (Exception e) {
Grasscutter.getLogger().error("Error loading resource file: " + Arrays.toString(type.name()), e); Grasscutter.getLogger().error("Error loading resource file: " + Arrays.toString(type.name()), e);
} }
} }
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
protected static void loadFromResource(Class<?> c, ResourceType type, Int2ObjectMap map, boolean doReload) throws Exception { protected static void loadFromResource(Class<?> c, ResourceType type, Int2ObjectMap map, boolean doReload) throws Exception {
if(!loadedResources.contains(c.getSimpleName()) || doReload) { if (!loadedResources.contains(c.getSimpleName()) || doReload) {
for (String name : type.name()) { for (String name : type.name()) {
loadFromResource(c, name, map); loadFromResource(c, name, map);
} }
loadedResources.add(c.getSimpleName()); loadedResources.add(c.getSimpleName());
Grasscutter.getLogger().debug("Loaded " + map.size() + " " + c.getSimpleName() + "s."); Grasscutter.getLogger().debug("Loaded " + map.size() + " " + c.getSimpleName() + "s.");
} }
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
protected static void loadFromResource(Class<?> c, String fileName, Int2ObjectMap map) throws Exception { protected static void loadFromResource(Class<?> c, String fileName, Int2ObjectMap map) throws Exception {
try (FileReader fileReader = new FileReader(RESOURCE("ExcelBinOutput/" + fileName))) { try (FileReader fileReader = new FileReader(RESOURCE("ExcelBinOutput/" + fileName))) {
List list = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, c).getType()); List list = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, c).getType());
for (Object o : list) { for (Object o : list) {
GameResource res = (GameResource) o; GameResource res = (GameResource) o;
res.onLoad(); res.onLoad();
map.put(res.getId(), res); map.put(res.getId(), res);
} }
} }
} }
private static void loadScenePoints() { private static void loadScenePoints() {
Pattern pattern = Pattern.compile("(?<=scene)(.*?)(?=_point.json)"); Pattern pattern = Pattern.compile("(?<=scene)(.*?)(?=_point.json)");
File folder = new File(RESOURCE("BinOutput/Scene/Point")); File folder = new File(RESOURCE("BinOutput/Scene/Point"));
if (!folder.isDirectory() || !folder.exists() || folder.listFiles() == null) { if (!folder.isDirectory() || !folder.exists() || folder.listFiles() == null) {
Grasscutter.getLogger().error("Scene point files cannot be found, you cannot use teleport waypoints!"); Grasscutter.getLogger().error("Scene point files cannot be found, you cannot use teleport waypoints!");
return; return;
} }
List<ScenePointEntry> scenePointList = new ArrayList<>(); List<ScenePointEntry> scenePointList = new ArrayList<>();
for (File file : Objects.requireNonNull(folder.listFiles())) { for (File file : Objects.requireNonNull(folder.listFiles())) {
ScenePointConfig config; Integer sceneId; ScenePointConfig config; Integer sceneId;
Matcher matcher = pattern.matcher(file.getName()); Matcher matcher = pattern.matcher(file.getName());
if (matcher.find()) { if (matcher.find()) {
sceneId = Integer.parseInt(matcher.group(1)); sceneId = Integer.parseInt(matcher.group(1));
} else { } else {
continue; continue;
} }
try (FileReader fileReader = new FileReader(file)) { try (FileReader fileReader = new FileReader(file)) {
config = Grasscutter.getGsonFactory().fromJson(fileReader, ScenePointConfig.class); config = Grasscutter.getGsonFactory().fromJson(fileReader, ScenePointConfig.class);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
continue; continue;
} }
if (config.points == null) { if (config.points == null) {
continue; continue;
} }
for (Map.Entry<String, JsonElement> entry : config.points.entrySet()) { for (Map.Entry<String, JsonElement> entry : config.points.entrySet()) {
PointData pointData = Grasscutter.getGsonFactory().fromJson(entry.getValue(), PointData.class); PointData pointData = Grasscutter.getGsonFactory().fromJson(entry.getValue(), PointData.class);
pointData.setId(Integer.parseInt(entry.getKey())); pointData.setId(Integer.parseInt(entry.getKey()));
ScenePointEntry sl = new ScenePointEntry(sceneId + "_" + entry.getKey(), pointData); ScenePointEntry sl = new ScenePointEntry(sceneId + "_" + entry.getKey(), pointData);
scenePointList.add(sl); scenePointList.add(sl);
GameData.getScenePointIdList().add(pointData.getId()); GameData.getScenePointIdList().add(pointData.getId());
pointData.updateDailyDungeon(); pointData.updateDailyDungeon();
} }
for (ScenePointEntry entry : scenePointList) { for (ScenePointEntry entry : scenePointList) {
GameData.getScenePointEntries().put(entry.getName(), entry); GameData.getScenePointEntries().put(entry.getName(), entry);
} }
} }
} }
private static void loadAbilityEmbryos() { private static void loadAbilityEmbryos() {
List<AbilityEmbryoEntry> embryoList = null; List<AbilityEmbryoEntry> embryoList = null;
// Read from cached file if exists // Read from cached file if exists
try (InputStream embryoCache = DataLoader.load("AbilityEmbryos.json", false)) { try (InputStream embryoCache = DataLoader.load("AbilityEmbryos.json", false)) {
embryoList = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(embryoCache), TypeToken.getParameterized(Collection.class, AbilityEmbryoEntry.class).getType()); embryoList = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(embryoCache), TypeToken.getParameterized(Collection.class, AbilityEmbryoEntry.class).getType());
} catch (Exception ignored) {} } catch (Exception ignored) {}
if(embryoList == null) { if (embryoList == null) {
// Load from BinOutput // Load from BinOutput
Pattern pattern = Pattern.compile("(?<=ConfigAvatar_)(.*?)(?=.json)"); Pattern pattern = Pattern.compile("(?<=ConfigAvatar_)(.*?)(?=.json)");
embryoList = new LinkedList<>(); embryoList = new LinkedList<>();
File folder = new File(Utils.toFilePath(RESOURCE("BinOutput/Avatar/"))); File folder = new File(Utils.toFilePath(RESOURCE("BinOutput/Avatar/")));
File[] files = folder.listFiles(); File[] files = folder.listFiles();
if(files == null) { if (files == null) {
Grasscutter.getLogger().error("Error loading ability embryos: no files found in " + folder.getAbsolutePath()); Grasscutter.getLogger().error("Error loading ability embryos: no files found in " + folder.getAbsolutePath());
return; return;
} }
for (File file : files) { for (File file : files) {
AvatarConfig config; AvatarConfig config;
String avatarName; String avatarName;
Matcher matcher = pattern.matcher(file.getName()); Matcher matcher = pattern.matcher(file.getName());
if (matcher.find()) { if (matcher.find()) {
avatarName = matcher.group(0); avatarName = matcher.group(0);
} else { } else {
continue; continue;
} }
try (FileReader fileReader = new FileReader(file)) { try (FileReader fileReader = new FileReader(file)) {
config = Grasscutter.getGsonFactory().fromJson(fileReader, AvatarConfig.class); config = Grasscutter.getGsonFactory().fromJson(fileReader, AvatarConfig.class);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
continue; continue;
} }
if (config.abilities == null) { if (config.abilities == null) {
continue; continue;
} }
int s = config.abilities.size(); int s = config.abilities.size();
AbilityEmbryoEntry al = new AbilityEmbryoEntry(avatarName, config.abilities.stream().map(Object::toString).toArray(size -> new String[s])); AbilityEmbryoEntry al = new AbilityEmbryoEntry(avatarName, config.abilities.stream().map(Object::toString).toArray(size -> new String[s]));
embryoList.add(al); embryoList.add(al);
} }
File playerElementsFile = new File(Utils.toFilePath(RESOURCE("BinOutput/AbilityGroup/AbilityGroup_Other_PlayerElementAbility.json"))); File playerElementsFile = new File(Utils.toFilePath(RESOURCE("BinOutput/AbilityGroup/AbilityGroup_Other_PlayerElementAbility.json")));
if (playerElementsFile.exists()) { if (playerElementsFile.exists()) {
try (FileReader fileReader = new FileReader(playerElementsFile)) { try (FileReader fileReader = new FileReader(playerElementsFile)) {
GameDepot.setPlayerAbilities(Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken<Map<String, AvatarConfig>>(){}.getType())); GameDepot.setPlayerAbilities(Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken<Map<String, AvatarConfig>>(){}.getType()));
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
} }
if (embryoList == null || embryoList.isEmpty()) { if (embryoList == null || embryoList.isEmpty()) {
Grasscutter.getLogger().error("No embryos loaded!"); Grasscutter.getLogger().error("No embryos loaded!");
return; return;
} }
for (AbilityEmbryoEntry entry : embryoList) { for (AbilityEmbryoEntry entry : embryoList) {
GameData.getAbilityEmbryoInfo().put(entry.getName(), entry); GameData.getAbilityEmbryoInfo().put(entry.getName(), entry);
} }
} }
private static void loadAbilityModifiers() { private static void loadAbilityModifiers() {
// Load from BinOutput // Load from BinOutput
File folder = new File(Utils.toFilePath(RESOURCE("BinOutput/Ability/Temp/AvatarAbilities/"))); File folder = new File(Utils.toFilePath(RESOURCE("BinOutput/Ability/Temp/AvatarAbilities/")));
File[] files = folder.listFiles(); File[] files = folder.listFiles();
if (files == null) { if (files == null) {
Grasscutter.getLogger().error("Error loading ability modifiers: no files found in " + folder.getAbsolutePath()); Grasscutter.getLogger().error("Error loading ability modifiers: no files found in " + folder.getAbsolutePath());
return; return;
} }
for (File file : files) { for (File file : files) {
List<AbilityConfigData> abilityConfigList; List<AbilityConfigData> abilityConfigList;
try (FileReader fileReader = new FileReader(file)) { try (FileReader fileReader = new FileReader(file)) {
abilityConfigList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, AbilityConfigData.class).getType()); abilityConfigList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, AbilityConfigData.class).getType());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
continue; continue;
} }
for (AbilityConfigData data : abilityConfigList) { for (AbilityConfigData data : abilityConfigList) {
if (data.Default.modifiers == null || data.Default.modifiers.size() == 0) { if (data.Default.modifiers == null || data.Default.modifiers.size() == 0) {
continue; continue;
} }
AbilityModifierEntry modifierEntry = new AbilityModifierEntry(data.Default.abilityName); AbilityModifierEntry modifierEntry = new AbilityModifierEntry(data.Default.abilityName);
for (Entry<String, AbilityModifier> entry : data.Default.modifiers.entrySet()) { for (Entry<String, AbilityModifier> entry : data.Default.modifiers.entrySet()) {
AbilityModifier modifier = entry.getValue(); AbilityModifier modifier = entry.getValue();
// Stare. // Stare.
if (modifier.onAdded != null) { if (modifier.onAdded != null) {
for (AbilityModifierAction action : modifier.onAdded) { for (AbilityModifierAction action : modifier.onAdded) {
if (action.$type.contains("HealHP")) { if (action.$type.contains("HealHP")) {
action.type = AbilityModifierActionType.HealHP; action.type = AbilityModifierActionType.HealHP;
modifierEntry.getOnAdded().add(action); modifierEntry.getOnAdded().add(action);
} }
} }
} }
if (modifier.onThinkInterval != null) { if (modifier.onThinkInterval != null) {
for (AbilityModifierAction action : modifier.onThinkInterval) { for (AbilityModifierAction action : modifier.onThinkInterval) {
if (action.$type.contains("HealHP")) { if (action.$type.contains("HealHP")) {
action.type = AbilityModifierActionType.HealHP; action.type = AbilityModifierActionType.HealHP;
modifierEntry.getOnThinkInterval().add(action); modifierEntry.getOnThinkInterval().add(action);
} }
} }
} }
if (modifier.onRemoved != null) { if (modifier.onRemoved != null) {
for (AbilityModifierAction action : modifier.onRemoved) { for (AbilityModifierAction action : modifier.onRemoved) {
if (action.$type.contains("HealHP")) { if (action.$type.contains("HealHP")) {
action.type = AbilityModifierActionType.HealHP; action.type = AbilityModifierActionType.HealHP;
modifierEntry.getOnRemoved().add(action); modifierEntry.getOnRemoved().add(action);
} }
} }
} }
} }
GameData.getAbilityModifiers().put(modifierEntry.getName(), modifierEntry); GameData.getAbilityModifiers().put(modifierEntry.getName(), modifierEntry);
} }
} }
} }
private static void loadSpawnData() { private static void loadSpawnData() {
String[] spawnDataNames = {"Spawns.json", "GadgetSpawns.json"}; String[] spawnDataNames = {"Spawns.json", "GadgetSpawns.json"};
ArrayList<SpawnGroupEntry> spawnEntryMap = new ArrayList<>(); ArrayList<SpawnGroupEntry> spawnEntryMap = new ArrayList<>();
for (String name : spawnDataNames) { for (String name : spawnDataNames) {
// Load spawn entries from file // Load spawn entries from file
...@@ -321,10 +321,10 @@ public class ResourceLoader { ...@@ -321,10 +321,10 @@ public class ResourceLoader {
} catch (Exception ignored) {} } catch (Exception ignored) {}
} }
if (spawnEntryMap.isEmpty()) { if (spawnEntryMap.isEmpty()) {
Grasscutter.getLogger().error("No spawn data loaded!"); Grasscutter.getLogger().error("No spawn data loaded!");
return; return;
} }
HashMap<GridBlockId, ArrayList<SpawnDataEntry>> areaSort = new HashMap<>(); HashMap<GridBlockId, ArrayList<SpawnDataEntry>> areaSort = new HashMap<>();
//key = sceneId,x,z , value = ArrayList<SpawnDataEntry> //key = sceneId,x,z , value = ArrayList<SpawnDataEntry>
...@@ -333,7 +333,7 @@ public class ResourceLoader { ...@@ -333,7 +333,7 @@ public class ResourceLoader {
s -> { s -> {
s.setGroup(entry); s.setGroup(entry);
GridBlockId point = s.getBlockId(); GridBlockId point = s.getBlockId();
if(!areaSort.containsKey(point)) { if (!areaSort.containsKey(point)) {
areaSort.put(point, new ArrayList<>()); areaSort.put(point, new ArrayList<>());
} }
areaSort.get(point).add(s); areaSort.get(point).add(s);
...@@ -341,155 +341,155 @@ public class ResourceLoader { ...@@ -341,155 +341,155 @@ public class ResourceLoader {
); );
} }
GameDepot.addSpawnListById(areaSort); GameDepot.addSpawnListById(areaSort);
} }
private static void loadOpenConfig() { private static void loadOpenConfig() {
// Read from cached file if exists // Read from cached file if exists
List<OpenConfigEntry> list = null; List<OpenConfigEntry> list = null;
try(InputStream openConfigCache = DataLoader.load("OpenConfig.json", false)) { try (InputStream openConfigCache = DataLoader.load("OpenConfig.json", false)) {
list = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(openConfigCache), TypeToken.getParameterized(Collection.class, SpawnGroupEntry.class).getType()); list = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(openConfigCache), TypeToken.getParameterized(Collection.class, SpawnGroupEntry.class).getType());
} catch (Exception ignored) {} } catch (Exception ignored) {}
if (list == null) { if (list == null) {
Map<String, OpenConfigEntry> map = new TreeMap<>(); Map<String, OpenConfigEntry> map = new TreeMap<>();
java.lang.reflect.Type type = new TypeToken<Map<String, OpenConfigData[]>>() {}.getType(); java.lang.reflect.Type type = new TypeToken<Map<String, OpenConfigData[]>>() {}.getType();
String[] folderNames = {"BinOutput/Talent/EquipTalents/", "BinOutput/Talent/AvatarTalents/"}; String[] folderNames = {"BinOutput/Talent/EquipTalents/", "BinOutput/Talent/AvatarTalents/"};
for (String name : folderNames) { for (String name : folderNames) {
File folder = new File(Utils.toFilePath(RESOURCE(name))); File folder = new File(Utils.toFilePath(RESOURCE(name)));
File[] files = folder.listFiles(); File[] files = folder.listFiles();
if(files == null) { if (files == null) {
Grasscutter.getLogger().error("Error loading open config: no files found in " + folder.getAbsolutePath()); return; Grasscutter.getLogger().error("Error loading open config: no files found in " + folder.getAbsolutePath()); return;
} }
for (File file : files) { for (File file : files) {
if (!file.getName().endsWith(".json")) { if (!file.getName().endsWith(".json")) {
continue; continue;
} }
Map<String, OpenConfigData[]> config; Map<String, OpenConfigData[]> config;
try (FileReader fileReader = new FileReader(file)) { try (FileReader fileReader = new FileReader(file)) {
config = Grasscutter.getGsonFactory().fromJson(fileReader, type); config = Grasscutter.getGsonFactory().fromJson(fileReader, type);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
continue; continue;
} }
for (Entry<String, OpenConfigData[]> e : config.entrySet()) { for (Entry<String, OpenConfigData[]> e : config.entrySet()) {
OpenConfigEntry entry = new OpenConfigEntry(e.getKey(), e.getValue()); OpenConfigEntry entry = new OpenConfigEntry(e.getKey(), e.getValue());
map.put(entry.getName(), entry); map.put(entry.getName(), entry);
} }
} }
} }
list = new ArrayList<>(map.values()); list = new ArrayList<>(map.values());
} }
if (list == null || list.isEmpty()) { if (list == null || list.isEmpty()) {
Grasscutter.getLogger().error("No openconfig entries loaded!"); Grasscutter.getLogger().error("No openconfig entries loaded!");
return; return;
} }
for (OpenConfigEntry entry : list) { for (OpenConfigEntry entry : list) {
GameData.getOpenConfigEntries().put(entry.getName(), entry); GameData.getOpenConfigEntries().put(entry.getName(), entry);
} }
} }
private static void loadQuests() { private static void loadQuests() {
File folder = new File(RESOURCE("BinOutput/Quest/")); File folder = new File(RESOURCE("BinOutput/Quest/"));
if (!folder.exists()) { if (!folder.exists()) {
return; return;
} }
for (File file : folder.listFiles()) { for (File file : folder.listFiles()) {
MainQuestData mainQuest = null; MainQuestData mainQuest = null;
try (FileReader fileReader = new FileReader(file)) { try (FileReader fileReader = new FileReader(file)) {
mainQuest = Grasscutter.getGsonFactory().fromJson(fileReader, MainQuestData.class); mainQuest = Grasscutter.getGsonFactory().fromJson(fileReader, MainQuestData.class);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
continue; continue;
} }
GameData.getMainQuestDataMap().put(mainQuest.getId(), mainQuest); GameData.getMainQuestDataMap().put(mainQuest.getId(), mainQuest);
} }
Grasscutter.getLogger().debug("Loaded " + GameData.getMainQuestDataMap().size() + " MainQuestDatas."); Grasscutter.getLogger().debug("Loaded " + GameData.getMainQuestDataMap().size() + " MainQuestDatas.");
} }
@SneakyThrows @SneakyThrows
private static void loadHomeworldDefaultSaveData(){ private static void loadHomeworldDefaultSaveData() {
var folder = Files.list(Path.of(RESOURCE("BinOutput/HomeworldDefaultSave"))).toList(); var folder = Files.list(Path.of(RESOURCE("BinOutput/HomeworldDefaultSave"))).toList();
var pattern = Pattern.compile("scene(.*)_home_config.json"); var pattern = Pattern.compile("scene(.*)_home_config.json");
for(var file : folder){ for (var file : folder) {
var matcher = pattern.matcher(file.getFileName().toString()); var matcher = pattern.matcher(file.getFileName().toString());
if(!matcher.find()){ if (!matcher.find()) {
continue; continue;
} }
var sceneId = matcher.group(1); var sceneId = matcher.group(1);
var data = Grasscutter.getGsonFactory().fromJson(Files.readString(file), HomeworldDefaultSaveData.class); var data = Grasscutter.getGsonFactory().fromJson(Files.readString(file), HomeworldDefaultSaveData.class);
GameData.getHomeworldDefaultSaveData().put(Integer.parseInt(sceneId), data); GameData.getHomeworldDefaultSaveData().put(Integer.parseInt(sceneId), data);
} }
Grasscutter.getLogger().debug("Loaded " + GameData.getHomeworldDefaultSaveData().size() + " HomeworldDefaultSaveDatas."); Grasscutter.getLogger().debug("Loaded " + GameData.getHomeworldDefaultSaveData().size() + " HomeworldDefaultSaveDatas.");
} }
@SneakyThrows @SneakyThrows
private static void loadNpcBornData(){ private static void loadNpcBornData() {
var folder = Files.list(Path.of(RESOURCE("BinOutput/Scene/SceneNpcBorn"))).toList(); var folder = Files.list(Path.of(RESOURCE("BinOutput/Scene/SceneNpcBorn"))).toList();
for(var file : folder){ for (var file : folder) {
if(file.toFile().isDirectory()){ if (file.toFile().isDirectory()) {
continue; continue;
} }
var data = Grasscutter.getGsonFactory().fromJson(Files.readString(file), SceneNpcBornData.class); var data = Grasscutter.getGsonFactory().fromJson(Files.readString(file), SceneNpcBornData.class);
if(data.getBornPosList() == null || data.getBornPosList().size() == 0){ if (data.getBornPosList() == null || data.getBornPosList().size() == 0) {
continue; continue;
} }
data.setIndex(SceneIndexManager.buildIndex(3, data.getBornPosList(), item -> item.getPos().toPoint())); data.setIndex(SceneIndexManager.buildIndex(3, data.getBornPosList(), item -> item.getPos().toPoint()));
GameData.getSceneNpcBornData().put(data.getSceneId(), data); GameData.getSceneNpcBornData().put(data.getSceneId(), data);
} }
Grasscutter.getLogger().debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas."); Grasscutter.getLogger().debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas.");
} }
// BinOutput configs // BinOutput configs
public static class AvatarConfig { public static class AvatarConfig {
@SerializedName(value="abilities", alternate={"targetAbilities"}) @SerializedName(value="abilities", alternate={"targetAbilities"})
public ArrayList<AvatarConfigAbility> abilities; public ArrayList<AvatarConfigAbility> abilities;
} }
public static class AvatarConfigAbility { public static class AvatarConfigAbility {
public String abilityName; public String abilityName;
public String toString() { public String toString() {
return abilityName; return abilityName;
} }
} }
private static class OpenConfig { private static class OpenConfig {
public OpenConfigData[] data; public OpenConfigData[] data;
} }
public static class OpenConfigData { public static class OpenConfigData {
public String $type; public String $type;
public String abilityName; public String abilityName;
@SerializedName(value="talentIndex", alternate={"OJOFFKLNAHN"})
public int talentIndex;
@SerializedName(value="talentIndex", alternate={"OJOFFKLNAHN"}) @SerializedName(value="skillID", alternate={"overtime"})
public int talentIndex; public int skillID;
@SerializedName(value="skillID", alternate={"overtime"}) @SerializedName(value="pointDelta", alternate={"IGEBKIHPOIF"})
public int skillID; public int pointDelta;
}
@SerializedName(value="pointDelta", alternate={"IGEBKIHPOIF"})
public int pointDelta;
}
} }
...@@ -4,32 +4,32 @@ import com.google.gson.annotations.SerializedName; ...@@ -4,32 +4,32 @@ import com.google.gson.annotations.SerializedName;
// Used in excels // Used in excels
public class ItemParamData { public class ItemParamData {
@SerializedName(value="id", alternate={"itemId"}) @SerializedName(value="id", alternate={"itemId"})
private int id; private int id;
@SerializedName(value="count", alternate={"itemCount"}) @SerializedName(value="count", alternate={"itemCount"})
private int count; private int count;
public ItemParamData() {} public ItemParamData() {}
public ItemParamData(int id, int count) { public ItemParamData(int id, int count) {
this.id = id; this.id = id;
this.count = count; this.count = count;
} }
public int getId() { public int getId() {
return id; return id;
} }
public int getItemId() { public int getItemId() {
return id; return id;
} }
public int getCount() { public int getCount() {
return count; return count;
} }
public int getItemCount() { public int getItemCount() {
return count; return count;
} }
} }
package emu.grasscutter.data.excels; package emu.grasscutter.data.excels;
import java.util.List; import java.util.List;
import emu.grasscutter.data.GameResource; import emu.grasscutter.data.GameResource;
import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.ResourceType;
import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.ItemParamData;
@ResourceType(name = "EnvAnimalGatherExcelConfigData.json", loadPriority = ResourceType.LoadPriority.LOW) @ResourceType(name = "EnvAnimalGatherExcelConfigData.json", loadPriority = ResourceType.LoadPriority.LOW)
public class EnvAnimalGatherConfigData extends GameResource { public class EnvAnimalGatherConfigData extends GameResource {
private int animalId; private int animalId;
private String entityType; private String entityType;
private List<ItemParamData> gatherItemId; private List<ItemParamData> gatherItemId;
private String excludeWeathers; private String excludeWeathers;
private int aliveTime; private int aliveTime;
private int escapeTime; private int escapeTime;
private int escapeRadius; private int escapeRadius;
@Override @Override
public int getId() { public int getId() {
return animalId; return animalId;
} }
public int getAnimalId(){ public int getAnimalId() {
return animalId; return animalId;
} }
public String getEntityType(){ public String getEntityType() {
return entityType; return entityType;
} }
public ItemParamData getGatherItem() { public ItemParamData getGatherItem() {
return gatherItemId.size() > 0 ? gatherItemId.get(0) : null; return gatherItemId.size() > 0 ? gatherItemId.get(0) : null;
} }
} }
...@@ -23,9 +23,9 @@ public class ForgeData extends GameResource { ...@@ -23,9 +23,9 @@ public class ForgeData extends GameResource {
private List<ItemParamData> materialItems; private List<ItemParamData> materialItems;
@Override @Override
public int getId() { public int getId() {
return this.id; return this.id;
} }
public int getPlayerLevel() { public int getPlayerLevel() {
return playerLevel; return playerLevel;
......
...@@ -12,58 +12,58 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; ...@@ -12,58 +12,58 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@ResourceType(name = "ReliquaryLevelExcelConfigData.json") @ResourceType(name = "ReliquaryLevelExcelConfigData.json")
public class ReliquaryLevelData extends GameResource { public class ReliquaryLevelData extends GameResource {
private int id; private int id;
private Int2FloatMap propMap; private Int2FloatMap propMap;
private int rank; private int rank;
private int level; private int level;
private int exp; private int exp;
private List<RelicLevelProperty> addProps; private List<RelicLevelProperty> addProps;
@Override @Override
public int getId() { public int getId() {
return this.id; return this.id;
} }
public int getRank() { public int getRank() {
return rank; return rank;
} }
public int getLevel() { public int getLevel() {
return level; return level;
} }
public int getExp() { public int getExp() {
return exp; return exp;
} }
public float getPropValue(FightProperty prop) { public float getPropValue(FightProperty prop) {
return getPropValue(prop.getId()); return getPropValue(prop.getId());
} }
public float getPropValue(int id) { public float getPropValue(int id) {
return propMap.getOrDefault(id, 0f); return propMap.getOrDefault(id, 0f);
} }
@Override @Override
public void onLoad() { public void onLoad() {
this.id = (rank << 8) + this.getLevel(); this.id = (rank << 8) + this.getLevel();
this.propMap = new Int2FloatOpenHashMap(); this.propMap = new Int2FloatOpenHashMap();
for (RelicLevelProperty p : addProps) { for (RelicLevelProperty p : addProps) {
this.propMap.put(FightProperty.getPropByName(p.getPropType()).getId(), p.getValue()); this.propMap.put(FightProperty.getPropByName(p.getPropType()).getId(), p.getValue());
} }
} }
public class RelicLevelProperty { public class RelicLevelProperty {
private String propType; private String propType;
private float value; private float value;
public String getPropType() { public String getPropType() {
return propType; return propType;
} }
public float getValue() { public float getValue() {
return value; return value;
} }
} }
} }
...@@ -29,98 +29,98 @@ import emu.grasscutter.game.quest.GameMainQuest; ...@@ -29,98 +29,98 @@ import emu.grasscutter.game.quest.GameMainQuest;
import emu.grasscutter.game.quest.GameQuest; import emu.grasscutter.game.quest.GameQuest;
public final class DatabaseManager { public final class DatabaseManager {
private static Datastore gameDatastore; private static Datastore gameDatastore;
private static Datastore dispatchDatastore; private static Datastore dispatchDatastore;
private static final Class<?>[] mappedClasses = new Class<?>[] { private static final Class<?>[] mappedClasses = new Class<?>[] {
DatabaseCounter.class, Account.class, Player.class, Avatar.class, GameItem.class, Friendship.class, DatabaseCounter.class, Account.class, Player.class, Avatar.class, GameItem.class, Friendship.class,
GachaRecord.class, Mail.class, GameMainQuest.class, GameHome.class, BattlePassManager.class, GachaRecord.class, Mail.class, GameMainQuest.class, GameHome.class, BattlePassManager.class,
PlayerActivityData.class, MusicGameBeatmap.class PlayerActivityData.class, MusicGameBeatmap.class
}; };
public static Datastore getGameDatastore() { public static Datastore getGameDatastore() {
return gameDatastore; return gameDatastore;
} }
public static MongoDatabase getGameDatabase() { public static MongoDatabase getGameDatabase() {
return getGameDatastore().getDatabase(); return getGameDatastore().getDatabase();
} }
// Yes. I very dislike this method. However, this will be good for now. // Yes. I very dislike this method. However, this will be good for now.
// TODO: Add dispatch routes for player account management // TODO: Add dispatch routes for player account management
public static Datastore getAccountDatastore() { public static Datastore getAccountDatastore() {
if(SERVER.runMode == ServerRunMode.GAME_ONLY) { if (SERVER.runMode == ServerRunMode.GAME_ONLY) {
return dispatchDatastore; return dispatchDatastore;
} else { } else {
return gameDatastore; return gameDatastore;
} }
} }
public static void initialize() { public static void initialize() {
// Initialize // Initialize
MongoClient gameMongoClient = MongoClients.create(DATABASE.game.connectionUri); MongoClient gameMongoClient = MongoClients.create(DATABASE.game.connectionUri);
// Set mapper options.
MapperOptions mapperOptions = MapperOptions.builder()
.storeEmpties(true).storeNulls(false).build();
// Create data store.
gameDatastore = Morphia.createDatastore(gameMongoClient, DATABASE.game.collection, mapperOptions);
// Map classes.
gameDatastore.getMapper().map(mappedClasses);
// Ensure indexes
try {
gameDatastore.ensureIndexes();
} catch (MongoCommandException exception) {
Grasscutter.getLogger().info("Mongo index error: ", exception);
// Duplicate index error
if (exception.getCode() == 85) {
// Drop all indexes and re add them
MongoIterable<String> collections = gameDatastore.getDatabase().listCollectionNames();
for (String name : collections) {
gameDatastore.getDatabase().getCollection(name).dropIndexes();
}
// Add back indexes
gameDatastore.ensureIndexes();
}
}
if(SERVER.runMode == ServerRunMode.GAME_ONLY) { // Set mapper options.
MongoClient dispatchMongoClient = MongoClients.create(DATABASE.server.connectionUri); MapperOptions mapperOptions = MapperOptions.builder()
dispatchDatastore = Morphia.createDatastore(dispatchMongoClient, DATABASE.server.collection); .storeEmpties(true).storeNulls(false).build();
// Create data store.
gameDatastore = Morphia.createDatastore(gameMongoClient, DATABASE.game.collection, mapperOptions);
// Map classes.
gameDatastore.getMapper().map(mappedClasses);
// Ensure indexes for dispatch server // Ensure indexes
try { try {
dispatchDatastore.ensureIndexes(); gameDatastore.ensureIndexes();
} catch (MongoCommandException e) { } catch (MongoCommandException exception) {
Grasscutter.getLogger().info("Mongo index error: ", e); Grasscutter.getLogger().info("Mongo index error: ", exception);
// Duplicate index error // Duplicate index error
if (e.getCode() == 85) { if (exception.getCode() == 85) {
// Drop all indexes and re add them // Drop all indexes and re add them
MongoIterable<String> collections = dispatchDatastore.getDatabase().listCollectionNames(); MongoIterable<String> collections = gameDatastore.getDatabase().listCollectionNames();
for (String name : collections) { for (String name : collections) {
dispatchDatastore.getDatabase().getCollection(name).dropIndexes(); gameDatastore.getDatabase().getCollection(name).dropIndexes();
} }
// Add back indexes // Add back indexes
dispatchDatastore.ensureIndexes(); gameDatastore.ensureIndexes();
} }
} }
}
}
public static synchronized int getNextId(Class<?> c) { if (SERVER.runMode == ServerRunMode.GAME_ONLY) {
DatabaseCounter counter = getGameDatastore().find(DatabaseCounter.class).filter(Filters.eq("_id", c.getSimpleName())).first(); MongoClient dispatchMongoClient = MongoClients.create(DATABASE.server.connectionUri);
if (counter == null) { dispatchDatastore = Morphia.createDatastore(dispatchMongoClient, DATABASE.server.collection);
counter = new DatabaseCounter(c.getSimpleName());
} // Ensure indexes for dispatch server
try { try {
return counter.getNextId(); dispatchDatastore.ensureIndexes();
} finally { } catch (MongoCommandException e) {
getGameDatastore().save(counter); Grasscutter.getLogger().info("Mongo index error: ", e);
} // Duplicate index error
} if (e.getCode() == 85) {
// Drop all indexes and re add them
MongoIterable<String> collections = dispatchDatastore.getDatabase().listCollectionNames();
for (String name : collections) {
dispatchDatastore.getDatabase().getCollection(name).dropIndexes();
}
// Add back indexes
dispatchDatastore.ensureIndexes();
}
}
}
}
public static synchronized int getNextId(Object o) { public static synchronized int getNextId(Class<?> c) {
return getNextId(o.getClass()); DatabaseCounter counter = getGameDatastore().find(DatabaseCounter.class).filter(Filters.eq("_id", c.getSimpleName())).first();
} if (counter == null) {
} counter = new DatabaseCounter(c.getSimpleName());
\ No newline at end of file }
try {
return counter.getNextId();
} finally {
getGameDatastore().save(counter);
}
}
public static synchronized int getNextId(Object o) {
return getNextId(o.getClass());
}
}
...@@ -14,93 +14,93 @@ import org.bson.Document; ...@@ -14,93 +14,93 @@ import org.bson.Document;
@Entity(value = "accounts", useDiscriminator = false) @Entity(value = "accounts", useDiscriminator = false)
public class Account { public class Account {
@Id private String id; @Id private String id;
@Indexed(options = @IndexOptions(unique = true)) @Indexed(options = @IndexOptions(unique = true))
@Collation(locale = "simple", caseLevel = true) @Collation(locale = "simple", caseLevel = true)
private String username; private String username;
private String password; // Unused for now private String password; // Unused for now
private int reservedPlayerId; private int reservedPlayerId;
private String email; private String email;
private String token; private String token;
private String sessionKey; // Session token for dispatch server private String sessionKey; // Session token for dispatch server
private List<String> permissions; private List<String> permissions;
private Locale locale; private Locale locale;
private String banReason; private String banReason;
private int banEndTime; private int banEndTime;
private int banStartTime; private int banStartTime;
private boolean isBanned; private boolean isBanned;
@Deprecated @Deprecated
public Account() { public Account() {
this.permissions = new ArrayList<>(); this.permissions = new ArrayList<>();
this.locale = LANGUAGE; this.locale = LANGUAGE;
} }
public String getId() { public String getId() {
return id; return id;
} }
public void setId(String id) { public void setId(String id) {
this.id = id; this.id = id;
} }
public String getUsername() { public String getUsername() {
return username; return username;
} }
public void setUsername(String username) { public void setUsername(String username) {
this.username = username; this.username = username;
} }
public String getPassword() { public String getPassword() {
return password; return password;
} }
public void setPassword(String password) { public void setPassword(String password) {
this.password = password; this.password = password;
} }
public String getToken() { public String getToken() {
return token; return token;
} }
public void setToken(String token) { public void setToken(String token) {
this.token = token; this.token = token;
} }
public int getReservedPlayerUid() { public int getReservedPlayerUid() {
return this.reservedPlayerId; return this.reservedPlayerId;
} }
public void setReservedPlayerUid(int playerId) { public void setReservedPlayerUid(int playerId) {
this.reservedPlayerId = playerId; this.reservedPlayerId = playerId;
} }
public String getEmail() { public String getEmail() {
if(email != null && !email.isEmpty()) { if (email != null && !email.isEmpty()) {
return email; return email;
} else { } else {
return ""; return "";
} }
} }
public void setEmail(String email) { public void setEmail(String email) {
this.email = email; this.email = email;
} }
public String getSessionKey() { public String getSessionKey() {
return this.sessionKey; return this.sessionKey;
} }
public String generateSessionKey() { public String generateSessionKey() {
this.sessionKey = Utils.bytesToHex(Crypto.createSessionKey(32)); this.sessionKey = Utils.bytesToHex(Crypto.createSessionKey(32));
this.save(); this.save();
return this.sessionKey; return this.sessionKey;
} }
public Locale getLocale() { public Locale getLocale() {
return locale; return locale;
...@@ -110,126 +110,126 @@ public class Account { ...@@ -110,126 +110,126 @@ public class Account {
this.locale = locale; this.locale = locale;
} }
public String getBanReason() { public String getBanReason() {
return banReason; return banReason;
} }
public void setBanReason(String banReason) { public void setBanReason(String banReason) {
this.banReason = banReason; this.banReason = banReason;
} }
public int getBanEndTime() { public int getBanEndTime() {
return banEndTime; return banEndTime;
} }
public void setBanEndTime(int banEndTime) { public void setBanEndTime(int banEndTime) {
this.banEndTime = banEndTime; this.banEndTime = banEndTime;
} }
public int getBanStartTime() { public int getBanStartTime() {
return banStartTime; return banStartTime;
} }
public void setBanStartTime(int banStartTime) { public void setBanStartTime(int banStartTime) {
this.banStartTime = banStartTime; this.banStartTime = banStartTime;
} }
public boolean isBanned() { public boolean isBanned() {
if (banEndTime > 0 && banEndTime < System.currentTimeMillis() / 1000) { if (banEndTime > 0 && banEndTime < System.currentTimeMillis() / 1000) {
this.isBanned = false; this.isBanned = false;
this.banEndTime = 0; this.banEndTime = 0;
this.banStartTime = 0; this.banStartTime = 0;
this.banReason = null; this.banReason = null;
save(); save();
} }
return isBanned; return isBanned;
} }
public void setBanned(boolean isBanned) { public void setBanned(boolean isBanned) {
this.isBanned = isBanned; this.isBanned = isBanned;
} }
/** /**
* The collection of a player's permissions. * The collection of a player's permissions.
*/ */
public List<String> getPermissions() { public List<String> getPermissions() {
return this.permissions; return this.permissions;
} }
public boolean addPermission(String permission) { public boolean addPermission(String permission) {
if(this.permissions.contains(permission)) return false; if (this.permissions.contains(permission)) return false;
this.permissions.add(permission); return true; this.permissions.add(permission); return true;
} }
public static boolean permissionMatchesWildcard(String wildcard, String[] permissionParts) { public static boolean permissionMatchesWildcard(String wildcard, String[] permissionParts) {
String[] wildcardParts = wildcard.split("\\."); String[] wildcardParts = wildcard.split("\\.");
if (permissionParts.length < wildcardParts.length) { // A longer wildcard can never match a shorter permission if (permissionParts.length < wildcardParts.length) { // A longer wildcard can never match a shorter permission
return false; return false;
} }
for (int i=0; i<wildcardParts.length; i++) { for (int i=0; i<wildcardParts.length; i++) {
switch (wildcardParts[i]) { switch (wildcardParts[i]) {
case "**": // Recursing match case "**": // Recursing match
return true; return true;
case "*": // Match only one layer case "*": // Match only one layer
if (i >= (permissionParts.length-1)) { if (i >= (permissionParts.length-1)) {
return true; return true;
} }
break; break;
default: // This layer isn't a wildcard, it needs to match exactly default: // This layer isn't a wildcard, it needs to match exactly
if (!wildcardParts[i].equals(permissionParts[i])) { if (!wildcardParts[i].equals(permissionParts[i])) {
return false; return false;
} }
} }
} }
// At this point the wildcard will have matched every layer, but if it is shorter then the permission then this is not a match at this point (no **). // At this point the wildcard will have matched every layer, but if it is shorter then the permission then this is not a match at this point (no **).
return (wildcardParts.length == permissionParts.length); return (wildcardParts.length == permissionParts.length);
} }
public boolean hasPermission(String permission) { public boolean hasPermission(String permission) {
if(this.permissions.contains("*") && this.permissions.size() == 1) return true; if (this.permissions.contains("*") && this.permissions.size() == 1) return true;
// Add default permissions if it doesn't exist // Add default permissions if it doesn't exist
List<String> permissions = Stream.of(this.permissions, Arrays.asList(ACCOUNT.defaultPermissions)) List<String> permissions = Stream.of(this.permissions, Arrays.asList(ACCOUNT.defaultPermissions))
.flatMap(Collection::stream) .flatMap(Collection::stream)
.distinct().toList(); .distinct().toList();
if (permissions.contains(permission)) return true; if (permissions.contains(permission)) return true;
String[] permissionParts = permission.split("\\."); String[] permissionParts = permission.split("\\.");
for (String p : permissions) { for (String p : permissions) {
if (p.startsWith("-") && permissionMatchesWildcard(p.substring(1), permissionParts)) return false; if (p.startsWith("-") && permissionMatchesWildcard(p.substring(1), permissionParts)) return false;
if (permissionMatchesWildcard(p, permissionParts)) return true; if (permissionMatchesWildcard(p, permissionParts)) return true;
} }
return permissions.contains("*"); return permissions.contains("*");
} }
public boolean removePermission(String permission) { public boolean removePermission(String permission) {
return this.permissions.remove(permission); return this.permissions.remove(permission);
} }
// TODO make unique // TODO make unique
public String generateLoginToken() { public String generateLoginToken() {
this.token = Utils.bytesToHex(Crypto.createSessionKey(32)); this.token = Utils.bytesToHex(Crypto.createSessionKey(32));
this.save(); this.save();
return this.token; return this.token;
} }
public void save() { public void save() {
DatabaseHelper.saveAccount(this); DatabaseHelper.saveAccount(this);
} }
@PreLoad @PreLoad
public void onLoad(Document document) { public void onLoad(Document document) {
// Grant the superuser permissions to accounts created before the permissions update // Grant the superuser permissions to accounts created before the permissions update
if (!document.containsKey("permissions")) { if (!document.containsKey("permissions")) {
this.addPermission("*"); this.addPermission("*");
} }
// Set account default language as server default language // Set account default language as server default language
if (!document.containsKey("locale")) { if (!document.containsKey("locale")) {
this.locale = LANGUAGE; this.locale = LANGUAGE;
} }
} }
} }
...@@ -20,158 +20,158 @@ import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction; ...@@ -20,158 +20,158 @@ import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction;
public class AbilityManager extends BasePlayerManager { public class AbilityManager extends BasePlayerManager {
HealAbilityManager healAbilityManager; HealAbilityManager healAbilityManager;
public AbilityManager(Player player) { public AbilityManager(Player player) {
super(player); super(player);
this.healAbilityManager = new HealAbilityManager(player); this.healAbilityManager = new HealAbilityManager(player);
} }
public void onAbilityInvoke(AbilityInvokeEntry invoke) throws Exception { public void onAbilityInvoke(AbilityInvokeEntry invoke) throws Exception {
healAbilityManager.healHandler(invoke); healAbilityManager.healHandler(invoke);
//Grasscutter.getLogger().info(invoke.getArgumentType() + " (" + invoke.getArgumentTypeValue() + "): " + Utils.bytesToHex(invoke.toByteArray())); //Grasscutter.getLogger().info(invoke.getArgumentType() + " (" + invoke.getArgumentTypeValue() + "): " + Utils.bytesToHex(invoke.toByteArray()));
switch (invoke.getArgumentType()) { switch (invoke.getArgumentType()) {
case ABILITY_INVOKE_ARGUMENT_META_OVERRIDE_PARAM: case ABILITY_INVOKE_ARGUMENT_META_OVERRIDE_PARAM:
handleOverrideParam(invoke); handleOverrideParam(invoke);
break; break;
case ABILITY_INVOKE_ARGUMENT_META_REINIT_OVERRIDEMAP: case ABILITY_INVOKE_ARGUMENT_META_REINIT_OVERRIDEMAP:
handleReinitOverrideMap(invoke); handleReinitOverrideMap(invoke);
break; break;
case ABILITY_INVOKE_ARGUMENT_META_MODIFIER_CHANGE: case ABILITY_INVOKE_ARGUMENT_META_MODIFIER_CHANGE:
handleModifierChange(invoke); handleModifierChange(invoke);
break; break;
case ABILITY_INVOKE_ARGUMENT_MIXIN_COST_STAMINA: case ABILITY_INVOKE_ARGUMENT_MIXIN_COST_STAMINA:
handleMixinCostStamina(invoke); handleMixinCostStamina(invoke);
break; break;
case ABILITY_INVOKE_ARGUMENT_ACTION_GENERATE_ELEM_BALL: case ABILITY_INVOKE_ARGUMENT_ACTION_GENERATE_ELEM_BALL:
handleGenerateElemBall(invoke); handleGenerateElemBall(invoke);
break; break;
default: default:
break; break;
} }
} }
private void handleOverrideParam(AbilityInvokeEntry invoke) throws Exception { private void handleOverrideParam(AbilityInvokeEntry invoke) throws Exception {
GameEntity entity = player.getScene().getEntityById(invoke.getEntityId()); GameEntity entity = player.getScene().getEntityById(invoke.getEntityId());
if (entity == null) { if (entity == null) {
return; return;
} }
AbilityScalarValueEntry entry = AbilityScalarValueEntry.parseFrom(invoke.getAbilityData()); AbilityScalarValueEntry entry = AbilityScalarValueEntry.parseFrom(invoke.getAbilityData());
entity.getMetaOverrideMap().put(entry.getKey().getStr(), entry.getFloatValue()); entity.getMetaOverrideMap().put(entry.getKey().getStr(), entry.getFloatValue());
} }
private void handleReinitOverrideMap(AbilityInvokeEntry invoke) throws Exception { private void handleReinitOverrideMap(AbilityInvokeEntry invoke) throws Exception {
GameEntity entity = player.getScene().getEntityById(invoke.getEntityId()); GameEntity entity = player.getScene().getEntityById(invoke.getEntityId());
if (entity == null) { if (entity == null) {
return; return;
} }
AbilityMetaReInitOverrideMap map = AbilityMetaReInitOverrideMap.parseFrom(invoke.getAbilityData()); AbilityMetaReInitOverrideMap map = AbilityMetaReInitOverrideMap.parseFrom(invoke.getAbilityData());
for (AbilityScalarValueEntry entry : map.getOverrideMapList()) { for (AbilityScalarValueEntry entry : map.getOverrideMapList()) {
entity.getMetaOverrideMap().put(entry.getKey().getStr(), entry.getFloatValue()); entity.getMetaOverrideMap().put(entry.getKey().getStr(), entry.getFloatValue());
} }
} }
private void handleModifierChange(AbilityInvokeEntry invoke) throws Exception { private void handleModifierChange(AbilityInvokeEntry invoke) throws Exception {
// Sanity checks // Sanity checks
GameEntity target = player.getScene().getEntityById(invoke.getEntityId()); GameEntity target = player.getScene().getEntityById(invoke.getEntityId());
if (target == null) { if (target == null) {
return; return;
} }
AbilityMetaModifierChange data = AbilityMetaModifierChange.parseFrom(invoke.getAbilityData()); AbilityMetaModifierChange data = AbilityMetaModifierChange.parseFrom(invoke.getAbilityData());
if (data == null) { if (data == null) {
return; return;
} }
// Destroying rocks // Destroying rocks
if (target instanceof EntityGadget targetGadget && targetGadget.getContent() instanceof GadgetGatherObject gatherObject) { if (target instanceof EntityGadget targetGadget && targetGadget.getContent() instanceof GadgetGatherObject gatherObject) {
if (data.getAction() == ModifierAction.REMOVED) { if (data.getAction() == ModifierAction.REMOVED) {
gatherObject.dropItems(this.getPlayer()); gatherObject.dropItems(this.getPlayer());
return; return;
} }
}
// Sanity checks
AbilityInvokeEntryHead head = invoke.getHead();
if (head == null) {
return;
}
GameEntity sourceEntity = player.getScene().getEntityById(data.getApplyEntityId());
if (sourceEntity == null) {
return;
}
// This is not how it works but we will keep it for now since healing abilities dont work properly anyways
if (data.getAction() == ModifierAction.ADDED && data.getParentAbilityName() != null) {
// Handle add modifier here
String modifierString = data.getParentAbilityName().getStr();
AbilityModifierEntry modifier = GameData.getAbilityModifiers().get(modifierString);
if (modifier != null && modifier.getOnAdded().size() > 0) {
for (AbilityModifierAction action : modifier.getOnAdded()) {
invokeAction(action, target, sourceEntity);
}
}
// Add to meta modifier list
target.getMetaModifiers().put(head.getInstancedModifierId(), modifierString);
} else if (data.getAction() == ModifierAction.REMOVED) {
// Handle remove modifier
String modifierString = target.getMetaModifiers().get(head.getInstancedModifierId());
if (modifierString != null) {
// Get modifier and call on remove event
AbilityModifierEntry modifier = GameData.getAbilityModifiers().get(modifierString);
if (modifier != null && modifier.getOnRemoved().size() > 0) {
for (AbilityModifierAction action : modifier.getOnRemoved()) {
invokeAction(action, target, sourceEntity);
}
}
// Remove from meta modifiers
target.getMetaModifiers().remove(head.getInstancedModifierId());
}
}
}
private void handleMixinCostStamina(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException {
AbilityMixinCostStamina costStamina = AbilityMixinCostStamina.parseFrom((invoke.getAbilityData()));
getPlayer().getStaminaManager().handleMixinCostStamina(costStamina.getIsSwim());
}
private void handleGenerateElemBall(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException {
this.player.getEnergyManager().handleGenerateElemBall(invoke);
}
private void invokeAction(AbilityModifierAction action, GameEntity target, GameEntity sourceEntity) {
switch (action.type) {
case HealHP -> {
}
case LoseHP -> {
if (action.amountByTargetCurrentHPRatio == null) {
return;
}
float damageAmount = 0;
if (action.amount.isDynamic && action.amount.dynamicKey != null) {
damageAmount = sourceEntity.getMetaOverrideMap().getOrDefault(action.amount.dynamicKey, 0f);
}
if (damageAmount > 0) {
target.damage(damageAmount);
}
}
} }
}
// Sanity checks
AbilityInvokeEntryHead head = invoke.getHead();
if (head == null) {
return;
}
GameEntity sourceEntity = player.getScene().getEntityById(data.getApplyEntityId());
if (sourceEntity == null) {
return;
}
// This is not how it works but we will keep it for now since healing abilities dont work properly anyways
if (data.getAction() == ModifierAction.ADDED && data.getParentAbilityName() != null) {
// Handle add modifier here
String modifierString = data.getParentAbilityName().getStr();
AbilityModifierEntry modifier = GameData.getAbilityModifiers().get(modifierString);
if (modifier != null && modifier.getOnAdded().size() > 0) {
for (AbilityModifierAction action : modifier.getOnAdded()) {
invokeAction(action, target, sourceEntity);
}
}
// Add to meta modifier list
target.getMetaModifiers().put(head.getInstancedModifierId(), modifierString);
} else if (data.getAction() == ModifierAction.REMOVED) {
// Handle remove modifier
String modifierString = target.getMetaModifiers().get(head.getInstancedModifierId());
if (modifierString != null) {
// Get modifier and call on remove event
AbilityModifierEntry modifier = GameData.getAbilityModifiers().get(modifierString);
if (modifier != null && modifier.getOnRemoved().size() > 0) {
for (AbilityModifierAction action : modifier.getOnRemoved()) {
invokeAction(action, target, sourceEntity);
}
}
// Remove from meta modifiers
target.getMetaModifiers().remove(head.getInstancedModifierId());
}
}
}
private void handleMixinCostStamina(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException {
AbilityMixinCostStamina costStamina = AbilityMixinCostStamina.parseFrom((invoke.getAbilityData()));
getPlayer().getStaminaManager().handleMixinCostStamina(costStamina.getIsSwim());
}
private void handleGenerateElemBall(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException {
this.player.getEnergyManager().handleGenerateElemBall(invoke);
}
private void invokeAction(AbilityModifierAction action, GameEntity target, GameEntity sourceEntity) {
switch (action.type) {
case HealHP -> {
}
case LoseHP -> {
if (action.amountByTargetCurrentHPRatio == null) {
return;
}
float damageAmount = 0;
if (action.amount.isDynamic && action.amount.dynamicKey != null) {
damageAmount = sourceEntity.getMetaOverrideMap().getOrDefault(action.amount.dynamicKey, 0f);
}
if (damageAmount > 0) {
target.damage(damageAmount);
}
}
}
}
} }
...@@ -45,7 +45,7 @@ public class ActivityManager extends BasePlayerManager { ...@@ -45,7 +45,7 @@ public class ActivityManager extends BasePlayerManager {
activityWatcherTypeMap.put(typeName.value(), ConstructorAccess.get(item)); activityWatcherTypeMap.put(typeName.value(), ConstructorAccess.get(item));
}); });
try(Reader reader = DataLoader.loadReader("ActivityConfig.json")) { try (Reader reader = DataLoader.loadReader("ActivityConfig.json")) {
List<ActivityConfigItem> activities = Grasscutter.getGsonFactory().fromJson( List<ActivityConfigItem> activities = Grasscutter.getGsonFactory().fromJson(
reader, reader,
TypeToken.getParameterized(List.class, ActivityConfigItem.class).getType()); TypeToken.getParameterized(List.class, ActivityConfigItem.class).getType());
...@@ -53,16 +53,16 @@ public class ActivityManager extends BasePlayerManager { ...@@ -53,16 +53,16 @@ public class ActivityManager extends BasePlayerManager {
activities.forEach(item -> { activities.forEach(item -> {
var activityData = GameData.getActivityDataMap().get(item.getActivityId()); var activityData = GameData.getActivityDataMap().get(item.getActivityId());
if(activityData == null){ if (activityData == null) {
Grasscutter.getLogger().warn("activity {} not exist.", item.getActivityId()); Grasscutter.getLogger().warn("activity {} not exist.", item.getActivityId());
return; return;
} }
var activityHandlerType = activityHandlerTypeMap.get(ActivityType.getTypeByName(activityData.getActivityType())); var activityHandlerType = activityHandlerTypeMap.get(ActivityType.getTypeByName(activityData.getActivityType()));
ActivityHandler activityHandler; ActivityHandler activityHandler;
if(activityHandlerType != null) { if (activityHandlerType != null) {
activityHandler = (ActivityHandler) activityHandlerType.newInstance(); activityHandler = (ActivityHandler) activityHandlerType.newInstance();
}else{ }else {
activityHandler = new DefaultActivityHandler(); activityHandler = new DefaultActivityHandler();
} }
activityHandler.setActivityConfigItem(item); activityHandler.setActivityConfigItem(item);
...@@ -79,14 +79,14 @@ public class ActivityManager extends BasePlayerManager { ...@@ -79,14 +79,14 @@ public class ActivityManager extends BasePlayerManager {
} }
public ActivityManager(Player player){ public ActivityManager(Player player) {
super(player); super(player);
playerActivityDataMap = new ConcurrentHashMap<>(); playerActivityDataMap = new ConcurrentHashMap<>();
// load data for player // load data for player
activityConfigItemMap.values().forEach(item -> { activityConfigItemMap.values().forEach(item -> {
var data = PlayerActivityData.getByPlayer(player, item.getActivityId()); var data = PlayerActivityData.getByPlayer(player, item.getActivityId());
if(data == null){ if (data == null) {
data = item.getActivityHandler().initPlayerActivityData(player); data = item.getActivityHandler().initPlayerActivityData(player);
data.save(); data.save();
} }
...@@ -116,34 +116,34 @@ public class ActivityManager extends BasePlayerManager { ...@@ -116,34 +116,34 @@ public class ActivityManager extends BasePlayerManager {
params)); params));
} }
public ActivityInfoOuterClass.ActivityInfo getInfoProtoByActivityId(int activityId){ public ActivityInfoOuterClass.ActivityInfo getInfoProtoByActivityId(int activityId) {
var activityHandler = activityConfigItemMap.get(activityId).getActivityHandler(); var activityHandler = activityConfigItemMap.get(activityId).getActivityHandler();
var activityData = playerActivityDataMap.get(activityId); var activityData = playerActivityDataMap.get(activityId);
return activityHandler.toProto(activityData); return activityHandler.toProto(activityData);
} }
public Optional<ActivityHandler> getActivityHandler(ActivityType type){ public Optional<ActivityHandler> getActivityHandler(ActivityType type) {
return activityConfigItemMap.values().stream() return activityConfigItemMap.values().stream()
.map(ActivityConfigItem::getActivityHandler) .map(ActivityConfigItem::getActivityHandler)
.filter(x -> type == x.getClass().getAnnotation(GameActivity.class).value()) .filter(x -> type == x.getClass().getAnnotation(GameActivity.class).value())
.findFirst(); .findFirst();
} }
public <T extends ActivityHandler> Optional<T> getActivityHandlerAs(ActivityType type, Class<T> clazz){ public <T extends ActivityHandler> Optional<T> getActivityHandlerAs(ActivityType type, Class<T> clazz) {
return getActivityHandler(type).map(x -> (T)x); return getActivityHandler(type).map(x -> (T)x);
} }
public Optional<Integer> getActivityIdByActivityType(ActivityType type){ public Optional<Integer> getActivityIdByActivityType(ActivityType type) {
return getActivityHandler(type) return getActivityHandler(type)
.map(ActivityHandler::getActivityConfigItem) .map(ActivityHandler::getActivityConfigItem)
.map(ActivityConfigItem::getActivityId); .map(ActivityConfigItem::getActivityId);
} }
public Optional<PlayerActivityData> getPlayerActivityDataByActivityType(ActivityType type){ public Optional<PlayerActivityData> getPlayerActivityDataByActivityType(ActivityType type) {
return getActivityIdByActivityType(type) return getActivityIdByActivityType(type)
.map(playerActivityDataMap::get); .map(playerActivityDataMap::get);
} }
public Optional<ActivityInfoOuterClass.ActivityInfo> getInfoProtoByActivityType(ActivityType type){ public Optional<ActivityInfoOuterClass.ActivityInfo> getInfoProtoByActivityType(ActivityType type) {
return getActivityIdByActivityType(type) return getActivityIdByActivityType(type)
.map(this::getInfoProtoByActivityId); .map(this::getInfoProtoByActivityId);
} }
......
...@@ -41,8 +41,8 @@ public class MusicGameActivityHandler extends ActivityHandler { ...@@ -41,8 +41,8 @@ public class MusicGameActivityHandler extends ActivityHandler {
.build()); .build());
} }
public MusicGamePlayerData getMusicGamePlayerData(PlayerActivityData playerActivityData){ public MusicGamePlayerData getMusicGamePlayerData(PlayerActivityData playerActivityData) {
if(playerActivityData.getDetail() == null || playerActivityData.getDetail().isBlank()){ if (playerActivityData.getDetail() == null || playerActivityData.getDetail().isBlank()) {
onInitPlayerActivityData(playerActivityData); onInitPlayerActivityData(playerActivityData);
playerActivityData.save(); playerActivityData.save();
} }
...@@ -51,7 +51,7 @@ public class MusicGameActivityHandler extends ActivityHandler { ...@@ -51,7 +51,7 @@ public class MusicGameActivityHandler extends ActivityHandler {
MusicGamePlayerData.class); MusicGamePlayerData.class);
} }
public boolean setMusicGameRecord(PlayerActivityData playerActivityData, MusicGamePlayerData.MusicGameRecord newRecord){ public boolean setMusicGameRecord(PlayerActivityData playerActivityData, MusicGamePlayerData.MusicGameRecord newRecord) {
var musicGamePlayerData = getMusicGamePlayerData(playerActivityData); var musicGamePlayerData = getMusicGamePlayerData(playerActivityData);
var saveRecord = musicGamePlayerData.getMusicGameRecord().get(newRecord.getMusicId()); var saveRecord = musicGamePlayerData.getMusicGameRecord().get(newRecord.getMusicId());
...@@ -63,7 +63,7 @@ public class MusicGameActivityHandler extends ActivityHandler { ...@@ -63,7 +63,7 @@ public class MusicGameActivityHandler extends ActivityHandler {
return newRecord.getMaxScore() > saveRecord.getMaxScore(); return newRecord.getMaxScore() > saveRecord.getMaxScore();
} }
public void setMusicGameCustomBeatmapRecord(PlayerActivityData playerActivityData, MusicGamePlayerData.CustomBeatmapRecord newRecord){ public void setMusicGameCustomBeatmapRecord(PlayerActivityData playerActivityData, MusicGamePlayerData.CustomBeatmapRecord newRecord) {
var musicGamePlayerData = getMusicGamePlayerData(playerActivityData); var musicGamePlayerData = getMusicGamePlayerData(playerActivityData);
musicGamePlayerData.getOthersCustomBeatmapRecord().put(newRecord.getMusicShareId(), newRecord); musicGamePlayerData.getOthersCustomBeatmapRecord().put(newRecord.getMusicShareId(), newRecord);
......
...@@ -21,7 +21,7 @@ public class MusicGamePlayerData { ...@@ -21,7 +21,7 @@ public class MusicGamePlayerData {
Map<Long, CustomBeatmapRecord> personalCustomBeatmapRecord; Map<Long, CustomBeatmapRecord> personalCustomBeatmapRecord;
Map<Long, CustomBeatmapRecord> othersCustomBeatmapRecord; Map<Long, CustomBeatmapRecord> othersCustomBeatmapRecord;
public static MusicGamePlayerData create(){ public static MusicGamePlayerData create() {
return MusicGamePlayerData.of() return MusicGamePlayerData.of()
.musicGameRecord(GameData.getMusicGameBasicDataMap().values().stream() .musicGameRecord(GameData.getMusicGameBasicDataMap().values().stream()
.collect(Collectors.toMap(MusicGameBasicData::getId, MusicGamePlayerData.MusicGameRecord::create))) .collect(Collectors.toMap(MusicGameBasicData::getId, MusicGamePlayerData.MusicGameRecord::create)))
...@@ -38,13 +38,13 @@ public class MusicGamePlayerData { ...@@ -38,13 +38,13 @@ public class MusicGamePlayerData {
int maxCombo; int maxCombo;
int maxScore; int maxScore;
public static MusicGameRecord create(MusicGameBasicData musicGameBasicData){ public static MusicGameRecord create(MusicGameBasicData musicGameBasicData) {
return MusicGameRecord.of() return MusicGameRecord.of()
.musicId(musicGameBasicData.getId()) .musicId(musicGameBasicData.getId())
.build(); .build();
} }
public MusicGameRecordOuterClass.MusicGameRecord toProto(){ public MusicGameRecordOuterClass.MusicGameRecord toProto() {
return MusicGameRecordOuterClass.MusicGameRecord.newBuilder() return MusicGameRecordOuterClass.MusicGameRecord.newBuilder()
.setIsUnlock(true) .setIsUnlock(true)
.setMaxCombo(maxCombo) .setMaxCombo(maxCombo)
...@@ -61,7 +61,7 @@ public class MusicGamePlayerData { ...@@ -61,7 +61,7 @@ public class MusicGamePlayerData {
int score; int score;
boolean settle; boolean settle;
public MusicBriefInfoOuterClass.MusicBriefInfo.Builder toPersonalBriefProto(){ public MusicBriefInfoOuterClass.MusicBriefInfo.Builder toPersonalBriefProto() {
var musicGameBeatmap = MusicGameBeatmap.getByShareId(musicShareId); var musicGameBeatmap = MusicGameBeatmap.getByShareId(musicShareId);
return MusicBriefInfoOuterClass.MusicBriefInfo.newBuilder() return MusicBriefInfoOuterClass.MusicBriefInfo.newBuilder()
...@@ -74,7 +74,7 @@ public class MusicGamePlayerData { ...@@ -74,7 +74,7 @@ public class MusicGamePlayerData {
.setMusicShareId(musicShareId); .setMusicShareId(musicShareId);
} }
public MusicBriefInfoOuterClass.MusicBriefInfo.Builder toOthersBriefProto(){ public MusicBriefInfoOuterClass.MusicBriefInfo.Builder toOthersBriefProto() {
var musicGameBeatmap = MusicGameBeatmap.getByShareId(musicShareId); var musicGameBeatmap = MusicGameBeatmap.getByShareId(musicShareId);
return musicGameBeatmap.toBriefProto() return musicGameBeatmap.toBriefProto()
......
...@@ -66,896 +66,896 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; ...@@ -66,896 +66,896 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
@Entity(value = "avatars", useDiscriminator = false) @Entity(value = "avatars", useDiscriminator = false)
public class Avatar { public class Avatar {
@Id private ObjectId id; @Id private ObjectId id;
@Indexed private int ownerId; // Id of player that this avatar belongs to @Indexed private int ownerId; // Id of player that this avatar belongs to
@Transient private Player owner; @Transient private Player owner;
@Transient private AvatarData data; @Transient private AvatarData data;
@Transient private AvatarSkillDepotData skillDepot; @Transient private AvatarSkillDepotData skillDepot;
@Transient private long guid; // Player unique id @Transient private long guid; // Player unique id
private int avatarId; // Id of avatar private int avatarId; // Id of avatar
private int level = 1; private int level = 1;
private int exp; private int exp;
private int promoteLevel; private int promoteLevel;
private int satiation; // ? private int satiation; // ?
private int satiationPenalty; // ? private int satiationPenalty; // ?
private float currentHp; private float currentHp;
private float currentEnergy; private float currentEnergy;
@Transient private final Int2ObjectMap<GameItem> equips; @Transient private final Int2ObjectMap<GameItem> equips;
@Transient private final Int2FloatOpenHashMap fightProp; @Transient private final Int2FloatOpenHashMap fightProp;
@Transient private Set<String> extraAbilityEmbryos; @Transient private Set<String> extraAbilityEmbryos;
private List<Integer> fetters; private List<Integer> fetters;
private Map<Integer, Integer> skillLevelMap; // Talent levels private Map<Integer, Integer> skillLevelMap; // Talent levels
private Map<Integer, Integer> skillExtraChargeMap; // Charges private Map<Integer, Integer> skillExtraChargeMap; // Charges
private Map<Integer, Integer> proudSkillBonusMap; // Talent bonus levels (from const) private Map<Integer, Integer> proudSkillBonusMap; // Talent bonus levels (from const)
private int skillDepotId; private int skillDepotId;
private int coreProudSkillLevel; // Constellation level private int coreProudSkillLevel; // Constellation level
private Set<Integer> talentIdList; // Constellation id list private Set<Integer> talentIdList; // Constellation id list
private Set<Integer> proudSkillList; // Character passives private Set<Integer> proudSkillList; // Character passives
private int flyCloak; private int flyCloak;
private int costume; private int costume;
private int bornTime; private int bornTime;
private int fetterLevel = 1; private int fetterLevel = 1;
private int fetterExp; private int fetterExp;
private int nameCardRewardId; private int nameCardRewardId;
private int nameCardId; private int nameCardId;
@Deprecated // Do not use. Morhpia only! @Deprecated // Do not use. Morhpia only!
public Avatar() { public Avatar() {
this.equips = new Int2ObjectOpenHashMap<>(); this.equips = new Int2ObjectOpenHashMap<>();
this.fightProp = new Int2FloatOpenHashMap(); this.fightProp = new Int2FloatOpenHashMap();
this.extraAbilityEmbryos = new HashSet<>(); this.extraAbilityEmbryos = new HashSet<>();
this.proudSkillBonusMap = new HashMap<>(); this.proudSkillBonusMap = new HashMap<>();
this.fetters = new ArrayList<>(); // TODO Move to avatar this.fetters = new ArrayList<>(); // TODO Move to avatar
} }
// On creation // On creation
public Avatar(int avatarId) { public Avatar(int avatarId) {
this(GameData.getAvatarDataMap().get(avatarId)); this(GameData.getAvatarDataMap().get(avatarId));
} }
public Avatar(AvatarData data) { public Avatar(AvatarData data) {
this(); this();
this.avatarId = data.getId(); this.avatarId = data.getId();
this.nameCardRewardId = data.getNameCardRewardId(); this.nameCardRewardId = data.getNameCardRewardId();
this.nameCardId = data.getNameCardId(); this.nameCardId = data.getNameCardId();
this.data = data; this.data = data;
this.bornTime = (int) (System.currentTimeMillis() / 1000); this.bornTime = (int) (System.currentTimeMillis() / 1000);
this.flyCloak = 140001; this.flyCloak = 140001;
this.skillLevelMap = new HashMap<>(); this.skillLevelMap = new HashMap<>();
this.skillExtraChargeMap = new HashMap<>(); this.skillExtraChargeMap = new HashMap<>();
this.talentIdList = new HashSet<>(); this.talentIdList = new HashSet<>();
this.proudSkillList = new HashSet<>(); this.proudSkillList = new HashSet<>();
// Combat properties // Combat properties
for (FightProperty prop : FightProperty.values()) { for (FightProperty prop : FightProperty.values()) {
if (prop.getId() <= 0 || prop.getId() >= 3000) { if (prop.getId() <= 0 || prop.getId() >= 3000) {
continue; continue;
} }
this.setFightProperty(prop, 0f); this.setFightProperty(prop, 0f);
} }
// Skill depot // Skill depot
this.setSkillDepotData(getAvatarData().getSkillDepot()); this.setSkillDepotData(getAvatarData().getSkillDepot());
// Set stats // Set stats
this.recalcStats(); this.recalcStats();
this.currentHp = getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); this.currentHp = getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.currentHp); setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.currentHp);
this.currentEnergy = 0f; this.currentEnergy = 0f;
// Load handler // Load handler
this.onLoad(); this.onLoad();
} }
public Player getPlayer() { public Player getPlayer() {
return this.owner; return this.owner;
} }
public ObjectId getObjectId() { public ObjectId getObjectId() {
return id; return id;
} }
public AvatarData getAvatarData() { public AvatarData getAvatarData() {
return data; return data;
} }
protected void setAvatarData(AvatarData data) { protected void setAvatarData(AvatarData data) {
if (this.data != null) return; if (this.data != null) return;
this.data = data; // Used while loading this from the database this.data = data; // Used while loading this from the database
} }
public int getOwnerId() { public int getOwnerId() {
return ownerId; return ownerId;
} }
public void setOwner(Player player) { public void setOwner(Player player) {
this.owner = player; this.owner = player;
this.ownerId = player.getUid(); this.ownerId = player.getUid();
this.guid = player.getNextGameGuid(); this.guid = player.getNextGameGuid();
} }
public int getSatiation() { public int getSatiation() {
return satiation; return satiation;
} }
public void setSatiation(int satiation) { public void setSatiation(int satiation) {
this.satiation = satiation; this.satiation = satiation;
} }
public int getNameCardRewardId() { public int getNameCardRewardId() {
return nameCardRewardId; return nameCardRewardId;
} }
public void setNameCardRewardId(int nameCardRewardId) { public void setNameCardRewardId(int nameCardRewardId) {
this.nameCardRewardId = nameCardRewardId; this.nameCardRewardId = nameCardRewardId;
} }
public int getSatiationPenalty() { public int getSatiationPenalty() {
return satiationPenalty; return satiationPenalty;
} }
public void setSatiationPenalty(int satiationPenalty) { public void setSatiationPenalty(int satiationPenalty) {
this.satiationPenalty = satiationPenalty; this.satiationPenalty = satiationPenalty;
} }
public AvatarData getData() { public AvatarData getData() {
return data; return data;
} }
public long getGuid() { public long getGuid() {
return guid; return guid;
} }
public int getAvatarId() { public int getAvatarId() {
return avatarId; return avatarId;
} }
public int getLevel() { public int getLevel() {
return level; return level;
} }
public void setLevel(int level) { public void setLevel(int level) {
this.level = level; this.level = level;
} }
public int getExp() { public int getExp() {
return exp; return exp;
} }
public void setExp(int exp) { public void setExp(int exp) {
this.exp = exp; this.exp = exp;
} }
public int getPromoteLevel() { public int getPromoteLevel() {
return promoteLevel; return promoteLevel;
} }
public void setPromoteLevel(int promoteLevel) { public void setPromoteLevel(int promoteLevel) {
this.promoteLevel = promoteLevel; this.promoteLevel = promoteLevel;
} }
static public int getMinPromoteLevel(int level) { static public int getMinPromoteLevel(int level) {
if (level > 80) { if (level > 80) {
return 6; return 6;
} else if (level > 70) { } else if (level > 70) {
return 5; return 5;
} else if (level > 60) { } else if (level > 60) {
return 4; return 4;
} else if (level > 50) { } else if (level > 50) {
return 3; return 3;
} else if (level > 40) { } else if (level > 40) {
return 2; return 2;
} else if (level > 20) { } else if (level > 20) {
return 1; return 1;
} }
return 0; return 0;
} }
public Int2ObjectMap<GameItem> getEquips() { public Int2ObjectMap<GameItem> getEquips() {
return equips; return equips;
} }
public GameItem getEquipBySlot(EquipType slot) { public GameItem getEquipBySlot(EquipType slot) {
return this.getEquips().get(slot.getValue()); return this.getEquips().get(slot.getValue());
} }
private GameItem getEquipBySlot(int slotId) { private GameItem getEquipBySlot(int slotId) {
return this.getEquips().get(slotId); return this.getEquips().get(slotId);
} }
public GameItem getWeapon() { public GameItem getWeapon() {
return this.getEquipBySlot(EquipType.EQUIP_WEAPON); return this.getEquipBySlot(EquipType.EQUIP_WEAPON);
} }
public int getSkillDepotId() { public int getSkillDepotId() {
return skillDepotId; return skillDepotId;
} }
public AvatarSkillDepotData getSkillDepot() { public AvatarSkillDepotData getSkillDepot() {
return skillDepot; return skillDepot;
} }
protected void setSkillDepot(AvatarSkillDepotData skillDepot) { protected void setSkillDepot(AvatarSkillDepotData skillDepot) {
if (this.skillDepot != null) return; if (this.skillDepot != null) return;
this.skillDepot = skillDepot; // Used while loading this from the database this.skillDepot = skillDepot; // Used while loading this from the database
} }
public void setSkillDepotData(AvatarSkillDepotData skillDepot) { public void setSkillDepotData(AvatarSkillDepotData skillDepot) {
// Set id and depot // Set id and depot
this.skillDepotId = skillDepot.getId(); this.skillDepotId = skillDepot.getId();
this.skillDepot = skillDepot; this.skillDepot = skillDepot;
// Clear, then add skills // Clear, then add skills
getSkillLevelMap().clear(); getSkillLevelMap().clear();
if (skillDepot.getEnergySkill() > 0) { if (skillDepot.getEnergySkill() > 0) {
getSkillLevelMap().put(skillDepot.getEnergySkill(), 1); getSkillLevelMap().put(skillDepot.getEnergySkill(), 1);
} }
for (int skillId : skillDepot.getSkills()) { for (int skillId : skillDepot.getSkills()) {
if (skillId > 0) { if (skillId > 0) {
getSkillLevelMap().put(skillId, 1); getSkillLevelMap().put(skillId, 1);
} }
} }
// Add proud skills // Add proud skills
this.getProudSkillList().clear(); this.getProudSkillList().clear();
for (InherentProudSkillOpens openData : skillDepot.getInherentProudSkillOpens()) { for (InherentProudSkillOpens openData : skillDepot.getInherentProudSkillOpens()) {
if (openData.getProudSkillGroupId() == 0) { if (openData.getProudSkillGroupId() == 0) {
continue; continue;
} }
if (openData.getNeedAvatarPromoteLevel() <= this.getPromoteLevel()) { if (openData.getNeedAvatarPromoteLevel() <= this.getPromoteLevel()) {
int proudSkillId = (openData.getProudSkillGroupId() * 100) + 1; int proudSkillId = (openData.getProudSkillGroupId() * 100) + 1;
if (GameData.getProudSkillDataMap().containsKey(proudSkillId)) { if (GameData.getProudSkillDataMap().containsKey(proudSkillId)) {
this.getProudSkillList().add(proudSkillId); this.getProudSkillList().add(proudSkillId);
} }
} }
} }
} }
public Map<Integer, Integer> getSkillLevelMap() { public Map<Integer, Integer> getSkillLevelMap() {
return skillLevelMap; return skillLevelMap;
} }
public Map<Integer, Integer> getSkillExtraChargeMap() { public Map<Integer, Integer> getSkillExtraChargeMap() {
if (skillExtraChargeMap == null) { if (skillExtraChargeMap == null) {
skillExtraChargeMap = new HashMap<>(); skillExtraChargeMap = new HashMap<>();
} }
return skillExtraChargeMap; return skillExtraChargeMap;
} }
public Map<Integer, Integer> getProudSkillBonusMap() { public Map<Integer, Integer> getProudSkillBonusMap() {
return proudSkillBonusMap; return proudSkillBonusMap;
} }
public Set<String> getExtraAbilityEmbryos() { public Set<String> getExtraAbilityEmbryos() {
return extraAbilityEmbryos; return extraAbilityEmbryos;
} }
public void setFetterList(List<Integer> fetterList) { public void setFetterList(List<Integer> fetterList) {
this.fetters = fetterList; this.fetters = fetterList;
} }
public List<Integer> getFetterList() { public List<Integer> getFetterList() {
return fetters; return fetters;
} }
public int getFetterLevel() { public int getFetterLevel() {
return fetterLevel; return fetterLevel;
} }
public void setFetterLevel(int fetterLevel) { public void setFetterLevel(int fetterLevel) {
this.fetterLevel = fetterLevel; this.fetterLevel = fetterLevel;
} }
public int getFetterExp() { public int getFetterExp() {
return fetterExp; return fetterExp;
} }
public void setFetterExp(int fetterExp) { public void setFetterExp(int fetterExp) {
this.fetterExp = fetterExp; this.fetterExp = fetterExp;
} }
public int getNameCardId() { public int getNameCardId() {
return nameCardId; return nameCardId;
} }
public void setNameCardId(int nameCardId) { public void setNameCardId(int nameCardId) {
this.nameCardId = nameCardId; this.nameCardId = nameCardId;
} }
public float getCurrentHp() { public float getCurrentHp() {
return currentHp; return currentHp;
} }
public void setCurrentHp(float currentHp) { public void setCurrentHp(float currentHp) {
this.currentHp = currentHp; this.currentHp = currentHp;
} }
public void setCurrentEnergy() { public void setCurrentEnergy() {
if (GAME_OPTIONS.energyUsage) { if (GAME_OPTIONS.energyUsage) {
this.setCurrentEnergy(this.currentEnergy); this.setCurrentEnergy(this.currentEnergy);
} }
} }
public void setCurrentEnergy(float currentEnergy) { public void setCurrentEnergy(float currentEnergy) {
if (this.getSkillDepot() != null && this.getSkillDepot().getEnergySkillData() != null) { if (this.getSkillDepot() != null && this.getSkillDepot().getEnergySkillData() != null) {
ElementType element = this.getSkillDepot().getElementType(); ElementType element = this.getSkillDepot().getElementType();
this.setFightProperty(element.getMaxEnergyProp(), this.getSkillDepot().getEnergySkillData().getCostElemVal()); this.setFightProperty(element.getMaxEnergyProp(), this.getSkillDepot().getEnergySkillData().getCostElemVal());
if (GAME_OPTIONS.energyUsage) { if (GAME_OPTIONS.energyUsage) {
this.setFightProperty(element.getCurEnergyProp(), currentEnergy); this.setFightProperty(element.getCurEnergyProp(), currentEnergy);
} }
else { else {
this.setFightProperty(element.getCurEnergyProp(), this.getSkillDepot().getEnergySkillData().getCostElemVal()); this.setFightProperty(element.getCurEnergyProp(), this.getSkillDepot().getEnergySkillData().getCostElemVal());
} }
} }
} }
public void setCurrentEnergy(FightProperty curEnergyProp, float currentEnergy) { public void setCurrentEnergy(FightProperty curEnergyProp, float currentEnergy) {
if (GAME_OPTIONS.energyUsage) { if (GAME_OPTIONS.energyUsage) {
this.setFightProperty(curEnergyProp, currentEnergy); this.setFightProperty(curEnergyProp, currentEnergy);
this.currentEnergy = currentEnergy; this.currentEnergy = currentEnergy;
this.save(); this.save();
} }
} }
public Int2FloatOpenHashMap getFightProperties() { public Int2FloatOpenHashMap getFightProperties() {
return fightProp; return fightProp;
} }
public void setFightProperty(FightProperty prop, float value) { public void setFightProperty(FightProperty prop, float value) {
this.getFightProperties().put(prop.getId(), value); this.getFightProperties().put(prop.getId(), value);
} }
private void setFightProperty(int id, float value) { private void setFightProperty(int id, float value) {
this.getFightProperties().put(id, value); this.getFightProperties().put(id, value);
} }
public void addFightProperty(FightProperty prop, float value) { public void addFightProperty(FightProperty prop, float value) {
this.getFightProperties().put(prop.getId(), getFightProperty(prop) + value); this.getFightProperties().put(prop.getId(), getFightProperty(prop) + value);
} }
public float getFightProperty(FightProperty prop) { public float getFightProperty(FightProperty prop) {
return getFightProperties().getOrDefault(prop.getId(), 0f); return getFightProperties().getOrDefault(prop.getId(), 0f);
} }
public Set<Integer> getTalentIdList() { public Set<Integer> getTalentIdList() {
return talentIdList; return talentIdList;
} }
public int getCoreProudSkillLevel() { public int getCoreProudSkillLevel() {
return coreProudSkillLevel; return coreProudSkillLevel;
} }
public void setCoreProudSkillLevel(int constLevel) { public void setCoreProudSkillLevel(int constLevel) {
this.coreProudSkillLevel = constLevel; this.coreProudSkillLevel = constLevel;
} }
public Set<Integer> getProudSkillList() { public Set<Integer> getProudSkillList() {
return proudSkillList; return proudSkillList;
} }
public int getFlyCloak() { public int getFlyCloak() {
return flyCloak; return flyCloak;
} }
public void setFlyCloak(int flyCloak) { public void setFlyCloak(int flyCloak) {
this.flyCloak = flyCloak; this.flyCloak = flyCloak;
} }
public int getCostume() { public int getCostume() {
return costume; return costume;
} }
public void setCostume(int costume) { public void setCostume(int costume) {
this.costume = costume; this.costume = costume;
} }
public int getBornTime() { public int getBornTime() {
return bornTime; return bornTime;
} }
public boolean equipItem(GameItem item, boolean shouldRecalc) { public boolean equipItem(GameItem item, boolean shouldRecalc) {
// Sanity check equip type // Sanity check equip type
EquipType itemEquipType = item.getItemData().getEquipType(); EquipType itemEquipType = item.getItemData().getEquipType();
if (itemEquipType == EquipType.EQUIP_NONE) { if (itemEquipType == EquipType.EQUIP_NONE) {
return false; return false;
} }
// Check if other avatars have this item equipped // Check if other avatars have this item equipped
Avatar otherAvatar = getPlayer().getAvatars().getAvatarById(item.getEquipCharacter()); Avatar otherAvatar = getPlayer().getAvatars().getAvatarById(item.getEquipCharacter());
if (otherAvatar != null) { if (otherAvatar != null) {
// Unequip other avatar's item // Unequip other avatar's item
if (otherAvatar.unequipItem(item.getItemData().getEquipType())) { if (otherAvatar.unequipItem(item.getItemData().getEquipType())) {
getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(otherAvatar, item.getItemData().getEquipType())); getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(otherAvatar, item.getItemData().getEquipType()));
} }
// Swap with other avatar // Swap with other avatar
if (getEquips().containsKey(itemEquipType.getValue())) { if (getEquips().containsKey(itemEquipType.getValue())) {
GameItem toSwap = this.getEquipBySlot(itemEquipType); GameItem toSwap = this.getEquipBySlot(itemEquipType);
otherAvatar.equipItem(toSwap, false); otherAvatar.equipItem(toSwap, false);
} }
// Recalc // Recalc
otherAvatar.recalcStats(); otherAvatar.recalcStats();
} else if (getEquips().containsKey(itemEquipType.getValue())) { } else if (getEquips().containsKey(itemEquipType.getValue())) {
// Unequip item in current slot if it exists // Unequip item in current slot if it exists
unequipItem(itemEquipType); unequipItem(itemEquipType);
} }
// Set equip // Set equip
getEquips().put(itemEquipType.getValue(), item); getEquips().put(itemEquipType.getValue(), item);
if (itemEquipType == EquipType.EQUIP_WEAPON && getPlayer().getWorld() != null) { if (itemEquipType == EquipType.EQUIP_WEAPON && getPlayer().getWorld() != null) {
item.setWeaponEntityId(this.getPlayer().getWorld().getNextEntityId(EntityIdType.WEAPON)); item.setWeaponEntityId(this.getPlayer().getWorld().getNextEntityId(EntityIdType.WEAPON));
} }
item.setEquipCharacter(this.getAvatarId()); item.setEquipCharacter(this.getAvatarId());
item.save(); item.save();
if (this.getPlayer().hasSentAvatarDataNotify()) { if (this.getPlayer().hasSentAvatarDataNotify()) {
this.getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(this, item)); this.getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(this, item));
} }
if (shouldRecalc) { if (shouldRecalc) {
this.recalcStats(); this.recalcStats();
} }
return true; return true;
} }
public boolean unequipItem(EquipType slot) { public boolean unequipItem(EquipType slot) {
GameItem item = getEquips().remove(slot.getValue()); GameItem item = getEquips().remove(slot.getValue());
if (item != null) { if (item != null) {
item.setEquipCharacter(0); item.setEquipCharacter(0);
item.save(); item.save();
return true; return true;
} }
return false; return false;
} }
public void recalcStats() { public void recalcStats() {
recalcStats(false); recalcStats(false);
} }
public void recalcStats(boolean forceSendAbilityChange) { public void recalcStats(boolean forceSendAbilityChange) {
// Setup // Setup
AvatarData data = this.getAvatarData(); AvatarData data = this.getAvatarData();
AvatarPromoteData promoteData = GameData.getAvatarPromoteData(data.getAvatarPromoteId(), this.getPromoteLevel()); AvatarPromoteData promoteData = GameData.getAvatarPromoteData(data.getAvatarPromoteId(), this.getPromoteLevel());
Int2IntOpenHashMap setMap = new Int2IntOpenHashMap(); Int2IntOpenHashMap setMap = new Int2IntOpenHashMap();
// Extra ability embryos // Extra ability embryos
Set<String> prevExtraAbilityEmbryos = this.getExtraAbilityEmbryos(); Set<String> prevExtraAbilityEmbryos = this.getExtraAbilityEmbryos();
this.extraAbilityEmbryos = new HashSet<>(); this.extraAbilityEmbryos = new HashSet<>();
// Fetters // Fetters
this.setFetterList(data.getFetters()); this.setFetterList(data.getFetters());
this.setNameCardRewardId(data.getNameCardRewardId()); this.setNameCardRewardId(data.getNameCardRewardId());
this.setNameCardId(data.getNameCardId()); this.setNameCardId(data.getNameCardId());
// Get hp percent, set to 100% if none // Get hp percent, set to 100% if none
float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
// Store current energy value for later // Store current energy value for later
float currentEnergy = (this.getSkillDepot() != null) ? this.getFightProperty(this.getSkillDepot().getElementType().getCurEnergyProp()) : 0f; float currentEnergy = (this.getSkillDepot() != null) ? this.getFightProperty(this.getSkillDepot().getElementType().getCurEnergyProp()) : 0f;
// Clear properties // Clear properties
this.getFightProperties().clear(); this.getFightProperties().clear();
// Base stats // Base stats
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, data.getBaseHp(this.getLevel())); this.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, data.getBaseHp(this.getLevel()));
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK, data.getBaseAttack(this.getLevel())); this.setFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK, data.getBaseAttack(this.getLevel()));
this.setFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE, data.getBaseDefense(this.getLevel())); this.setFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE, data.getBaseDefense(this.getLevel()));
this.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL, data.getBaseCritical()); this.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL, data.getBaseCritical());
this.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL_HURT, data.getBaseCriticalHurt()); this.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL_HURT, data.getBaseCriticalHurt());
this.setFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, 1f); this.setFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, 1f);
if (promoteData != null) { if (promoteData != null) {
for (FightPropData fightPropData : promoteData.getAddProps()) { for (FightPropData fightPropData : promoteData.getAddProps()) {
this.addFightProperty(fightPropData.getProp(), fightPropData.getValue()); this.addFightProperty(fightPropData.getProp(), fightPropData.getValue());
} }
} }
// Set energy usage // Set energy usage
setCurrentEnergy(currentEnergy); setCurrentEnergy(currentEnergy);
// Artifacts // Artifacts
for (int slotId = 1; slotId <= 5; slotId++) { for (int slotId = 1; slotId <= 5; slotId++) {
// Get artifact // Get artifact
GameItem equip = this.getEquipBySlot(slotId); GameItem equip = this.getEquipBySlot(slotId);
if (equip == null) { if (equip == null) {
continue; continue;
} }
// Artifact main stat // Artifact main stat
ReliquaryMainPropData mainPropData = GameData.getReliquaryMainPropDataMap().get(equip.getMainPropId()); ReliquaryMainPropData mainPropData = GameData.getReliquaryMainPropDataMap().get(equip.getMainPropId());
if (mainPropData != null) { if (mainPropData != null) {
ReliquaryLevelData levelData = GameData.getRelicLevelData(equip.getItemData().getRankLevel(), equip.getLevel()); ReliquaryLevelData levelData = GameData.getRelicLevelData(equip.getItemData().getRankLevel(), equip.getLevel());
if (levelData != null) { if (levelData != null) {
this.addFightProperty(mainPropData.getFightProp(), levelData.getPropValue(mainPropData.getFightProp())); this.addFightProperty(mainPropData.getFightProp(), levelData.getPropValue(mainPropData.getFightProp()));
} }
} }
// Artifact sub stats // Artifact sub stats
for (int appendPropId : equip.getAppendPropIdList()) { for (int appendPropId : equip.getAppendPropIdList()) {
ReliquaryAffixData affixData = GameData.getReliquaryAffixDataMap().get(appendPropId); ReliquaryAffixData affixData = GameData.getReliquaryAffixDataMap().get(appendPropId);
if (affixData != null) { if (affixData != null) {
this.addFightProperty(affixData.getFightProp(), affixData.getPropValue()); this.addFightProperty(affixData.getFightProp(), affixData.getPropValue());
} }
} }
// Set bonus // Set bonus
if (equip.getItemData().getSetId() > 0) { if (equip.getItemData().getSetId() > 0) {
setMap.addTo(equip.getItemData().getSetId(), 1); setMap.addTo(equip.getItemData().getSetId(), 1);
} }
} }
// Set stuff // Set stuff
for (Int2IntOpenHashMap.Entry e : setMap.int2IntEntrySet()) { for (Int2IntOpenHashMap.Entry e : setMap.int2IntEntrySet()) {
ReliquarySetData setData = GameData.getReliquarySetDataMap().get(e.getIntKey()); ReliquarySetData setData = GameData.getReliquarySetDataMap().get(e.getIntKey());
if (setData == null) { if (setData == null) {
continue; continue;
} }
// Calculate how many items are from the set // Calculate how many items are from the set
int amount = e.getIntValue(); int amount = e.getIntValue();
// Add affix data from set bonus // Add affix data from set bonus
for (int setIndex = 0; setIndex < setData.getSetNeedNum().length; setIndex++) { for (int setIndex = 0; setIndex < setData.getSetNeedNum().length; setIndex++) {
if (amount >= setData.getSetNeedNum()[setIndex]) { if (amount >= setData.getSetNeedNum()[setIndex]) {
int affixId = (setData.getEquipAffixId() * 10) + setIndex; int affixId = (setData.getEquipAffixId() * 10) + setIndex;
EquipAffixData affix = GameData.getEquipAffixDataMap().get(affixId); EquipAffixData affix = GameData.getEquipAffixDataMap().get(affixId);
if (affix == null) { if (affix == null) {
continue; continue;
} }
// Add properties from this affix to our avatar // Add properties from this affix to our avatar
for (FightPropData prop : affix.getAddProps()) { for (FightPropData prop : affix.getAddProps()) {
this.addFightProperty(prop.getProp(), prop.getValue()); this.addFightProperty(prop.getProp(), prop.getValue());
} }
// Add any skill strings from this affix // Add any skill strings from this affix
this.addToExtraAbilityEmbryos(affix.getOpenConfig(), true); this.addToExtraAbilityEmbryos(affix.getOpenConfig(), true);
} else { } else {
break; break;
} }
} }
} }
// Weapon // Weapon
GameItem weapon = this.getWeapon(); GameItem weapon = this.getWeapon();
if (weapon != null) { if (weapon != null) {
// Add stats // Add stats
WeaponCurveData curveData = GameData.getWeaponCurveDataMap().get(weapon.getLevel()); WeaponCurveData curveData = GameData.getWeaponCurveDataMap().get(weapon.getLevel());
if (curveData != null) { if (curveData != null) {
for (WeaponProperty weaponProperty : weapon.getItemData().getWeaponProperties()) { for (WeaponProperty weaponProperty : weapon.getItemData().getWeaponProperties()) {
this.addFightProperty(weaponProperty.getFightProp(), weaponProperty.getInitValue() * curveData.getMultByProp(weaponProperty.getType())); this.addFightProperty(weaponProperty.getFightProp(), weaponProperty.getInitValue() * curveData.getMultByProp(weaponProperty.getType()));
} }
} }
// Weapon promotion stats // Weapon promotion stats
WeaponPromoteData wepPromoteData = GameData.getWeaponPromoteData(weapon.getItemData().getWeaponPromoteId(), weapon.getPromoteLevel()); WeaponPromoteData wepPromoteData = GameData.getWeaponPromoteData(weapon.getItemData().getWeaponPromoteId(), weapon.getPromoteLevel());
if (wepPromoteData != null) { if (wepPromoteData != null) {
for (FightPropData prop : wepPromoteData.getAddProps()) { for (FightPropData prop : wepPromoteData.getAddProps()) {
if (prop.getValue() == 0f || prop.getProp() == null) { if (prop.getValue() == 0f || prop.getProp() == null) {
continue; continue;
} }
this.addFightProperty(prop.getProp(), prop.getValue()); this.addFightProperty(prop.getProp(), prop.getValue());
} }
} }
// Add weapon skill from affixes // Add weapon skill from affixes
if (weapon.getAffixes() != null && weapon.getAffixes().size() > 0) { if (weapon.getAffixes() != null && weapon.getAffixes().size() > 0) {
// Weapons usually dont have more than one affix but just in case... // Weapons usually dont have more than one affix but just in case...
for (int af : weapon.getAffixes()) { for (int af : weapon.getAffixes()) {
if (af == 0) { if (af == 0) {
continue; continue;
} }
// Calculate affix id // Calculate affix id
int affixId = (af * 10) + weapon.getRefinement(); int affixId = (af * 10) + weapon.getRefinement();
EquipAffixData affix = GameData.getEquipAffixDataMap().get(affixId); EquipAffixData affix = GameData.getEquipAffixDataMap().get(affixId);
if (affix == null) { if (affix == null) {
continue; continue;
} }
// Add properties from this affix to our avatar // Add properties from this affix to our avatar
for (FightPropData prop : affix.getAddProps()) { for (FightPropData prop : affix.getAddProps()) {
this.addFightProperty(prop.getProp(), prop.getValue()); this.addFightProperty(prop.getProp(), prop.getValue());
} }
// Add any skill strings from this affix // Add any skill strings from this affix
this.addToExtraAbilityEmbryos(affix.getOpenConfig(), true); this.addToExtraAbilityEmbryos(affix.getOpenConfig(), true);
} }
} }
} }
// Add proud skills and unlock them if needed // Add proud skills and unlock them if needed
AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(this.getSkillDepotId()); AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(this.getSkillDepotId());
this.getProudSkillList().clear(); this.getProudSkillList().clear();
for (InherentProudSkillOpens openData : skillDepot.getInherentProudSkillOpens()) { for (InherentProudSkillOpens openData : skillDepot.getInherentProudSkillOpens()) {
if (openData.getProudSkillGroupId() == 0) { if (openData.getProudSkillGroupId() == 0) {
continue; continue;
} }
if (openData.getNeedAvatarPromoteLevel() <= this.getPromoteLevel()) { if (openData.getNeedAvatarPromoteLevel() <= this.getPromoteLevel()) {
int proudSkillId = (openData.getProudSkillGroupId() * 100) + 1; int proudSkillId = (openData.getProudSkillGroupId() * 100) + 1;
if (GameData.getProudSkillDataMap().containsKey(proudSkillId)) { if (GameData.getProudSkillDataMap().containsKey(proudSkillId)) {
this.getProudSkillList().add(proudSkillId); this.getProudSkillList().add(proudSkillId);
} }
} }
} }
// Proud skills // Proud skills
for (int proudSkillId : this.getProudSkillList()) { for (int proudSkillId : this.getProudSkillList()) {
ProudSkillData proudSkillData = GameData.getProudSkillDataMap().get(proudSkillId); ProudSkillData proudSkillData = GameData.getProudSkillDataMap().get(proudSkillId);
if (proudSkillData == null) { if (proudSkillData == null) {
continue; continue;
} }
// Add properties from this proud skill to our avatar // Add properties from this proud skill to our avatar
for (FightPropData prop : proudSkillData.getAddProps()) { for (FightPropData prop : proudSkillData.getAddProps()) {
this.addFightProperty(prop.getProp(), prop.getValue()); this.addFightProperty(prop.getProp(), prop.getValue());
} }
// Add any skill strings from this proud skill // Add any skill strings from this proud skill
this.addToExtraAbilityEmbryos(proudSkillData.getOpenConfig(), true); this.addToExtraAbilityEmbryos(proudSkillData.getOpenConfig(), true);
} }
// Constellations // Constellations
if (this.getTalentIdList().size() > 0) { if (this.getTalentIdList().size() > 0) {
for (int talentId : this.getTalentIdList()) { for (int talentId : this.getTalentIdList()) {
AvatarTalentData avatarTalentData = GameData.getAvatarTalentDataMap().get(talentId); AvatarTalentData avatarTalentData = GameData.getAvatarTalentDataMap().get(talentId);
if (avatarTalentData == null) { if (avatarTalentData == null) {
return; return;
} }
// Add any skill strings from this constellation // Add any skill strings from this constellation
this.addToExtraAbilityEmbryos(avatarTalentData.getOpenConfig(), false); this.addToExtraAbilityEmbryos(avatarTalentData.getOpenConfig(), false);
} }
} }
// Set % stats // Set % stats
this.setFightProperty( this.setFightProperty(
FightProperty.FIGHT_PROP_MAX_HP, FightProperty.FIGHT_PROP_MAX_HP,
(getFightProperty(FightProperty.FIGHT_PROP_BASE_HP) * (1f + getFightProperty(FightProperty.FIGHT_PROP_HP_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_HP) (getFightProperty(FightProperty.FIGHT_PROP_BASE_HP) * (1f + getFightProperty(FightProperty.FIGHT_PROP_HP_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_HP)
); );
this.setFightProperty( this.setFightProperty(
FightProperty.FIGHT_PROP_CUR_ATTACK, FightProperty.FIGHT_PROP_CUR_ATTACK,
(getFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK) * (1f + getFightProperty(FightProperty.FIGHT_PROP_ATTACK_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_ATTACK) (getFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK) * (1f + getFightProperty(FightProperty.FIGHT_PROP_ATTACK_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_ATTACK)
); );
this.setFightProperty( this.setFightProperty(
FightProperty.FIGHT_PROP_CUR_DEFENSE, FightProperty.FIGHT_PROP_CUR_DEFENSE,
(getFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE) * (1f + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE) (getFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE) * (1f + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE)
); );
// Set current hp // Set current hp
this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent); this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent);
// Packet // Packet
if (getPlayer() != null && getPlayer().hasSentAvatarDataNotify()) { if (getPlayer() != null && getPlayer().hasSentAvatarDataNotify()) {
// Update stats for client // Update stats for client
getPlayer().sendPacket(new PacketAvatarFightPropNotify(this)); getPlayer().sendPacket(new PacketAvatarFightPropNotify(this));
// Update client abilities // Update client abilities
EntityAvatar entity = this.getAsEntity(); EntityAvatar entity = this.getAsEntity();
if (entity != null && (!this.getExtraAbilityEmbryos().equals(prevExtraAbilityEmbryos) || forceSendAbilityChange)) { if (entity != null && (!this.getExtraAbilityEmbryos().equals(prevExtraAbilityEmbryos) || forceSendAbilityChange)) {
getPlayer().sendPacket(new PacketAbilityChangeNotify(entity)); getPlayer().sendPacket(new PacketAbilityChangeNotify(entity));
} }
} }
} }
public void addToExtraAbilityEmbryos(String openConfig, boolean forceAdd) { public void addToExtraAbilityEmbryos(String openConfig, boolean forceAdd) {
if (openConfig == null || openConfig.length() == 0) { if (openConfig == null || openConfig.length() == 0) {
return; return;
} }
OpenConfigEntry entry = GameData.getOpenConfigEntries().get(openConfig); OpenConfigEntry entry = GameData.getOpenConfigEntries().get(openConfig);
if (entry == null) { if (entry == null) {
if (forceAdd) { if (forceAdd) {
// Add config string to ability skill list anyways // Add config string to ability skill list anyways
this.getExtraAbilityEmbryos().add(openConfig); this.getExtraAbilityEmbryos().add(openConfig);
} }
return; return;
} }
if (entry.getAddAbilities() != null) { if (entry.getAddAbilities() != null) {
for (String ability : entry.getAddAbilities()) { for (String ability : entry.getAddAbilities()) {
this.getExtraAbilityEmbryos().add(ability); this.getExtraAbilityEmbryos().add(ability);
} }
} }
} }
public void recalcConstellations() { public void recalcConstellations() {
// Clear first // Clear first
this.getProudSkillBonusMap().clear(); this.getProudSkillBonusMap().clear();
this.getSkillExtraChargeMap().clear(); this.getSkillExtraChargeMap().clear();
// Sanity checks // Sanity checks
if (getData() == null || getData().getSkillDepot() == null) { if (getData() == null || getData().getSkillDepot() == null) {
return; return;
} }
if (this.getTalentIdList().size() > 0) { if (this.getTalentIdList().size() > 0) {
for (int talentId : this.getTalentIdList()) { for (int talentId : this.getTalentIdList()) {
AvatarTalentData avatarTalentData = GameData.getAvatarTalentDataMap().get(talentId); AvatarTalentData avatarTalentData = GameData.getAvatarTalentDataMap().get(talentId);
if (avatarTalentData == null || avatarTalentData.getOpenConfig() == null || avatarTalentData.getOpenConfig().length() == 0) { if (avatarTalentData == null || avatarTalentData.getOpenConfig() == null || avatarTalentData.getOpenConfig().length() == 0) {
continue; continue;
} }
// Get open config to find which skill should be boosted // Get open config to find which skill should be boosted
OpenConfigEntry entry = GameData.getOpenConfigEntries().get(avatarTalentData.getOpenConfig()); OpenConfigEntry entry = GameData.getOpenConfigEntries().get(avatarTalentData.getOpenConfig());
if (entry == null) { if (entry == null) {
continue; continue;
} }
// Check if we can add charges to a skill // Check if we can add charges to a skill
if (entry.getSkillPointModifiers() != null) { if (entry.getSkillPointModifiers() != null) {
for (SkillPointModifier mod : entry.getSkillPointModifiers()) { for (SkillPointModifier mod : entry.getSkillPointModifiers()) {
AvatarSkillData skillData = GameData.getAvatarSkillDataMap().get(mod.getSkillId()); AvatarSkillData skillData = GameData.getAvatarSkillDataMap().get(mod.getSkillId());
if (skillData == null) continue; if (skillData == null) continue;
int charges = skillData.getMaxChargeNum() + mod.getDelta(); int charges = skillData.getMaxChargeNum() + mod.getDelta();
this.getSkillExtraChargeMap().put(mod.getSkillId(), charges); this.getSkillExtraChargeMap().put(mod.getSkillId(), charges);
} }
continue; continue;
} }
// Check if a skill can be boosted by +3 levels // Check if a skill can be boosted by +3 levels
int skillId = 0; int skillId = 0;
if (entry.getExtraTalentIndex() == 2 && this.getData().getSkillDepot().getSkills().size() >= 2) { if (entry.getExtraTalentIndex() == 2 && this.getData().getSkillDepot().getSkills().size() >= 2) {
// E skill // E skill
skillId = this.getData().getSkillDepot().getSkills().get(1); skillId = this.getData().getSkillDepot().getSkills().get(1);
} else if (entry.getExtraTalentIndex() == 9) { } else if (entry.getExtraTalentIndex() == 9) {
// Ult skill // Ult skill
skillId = this.getData().getSkillDepot().getEnergySkill(); skillId = this.getData().getSkillDepot().getEnergySkill();
} }
// Sanity check // Sanity check
if (skillId == 0) { if (skillId == 0) {
continue; continue;
} }
// Get proud skill group id // Get proud skill group id
AvatarSkillData skillData = GameData.getAvatarSkillDataMap().get(skillId); AvatarSkillData skillData = GameData.getAvatarSkillDataMap().get(skillId);
if (skillData == null) { if (skillData == null) {
continue; continue;
} }
// Add to bonus list // Add to bonus list
this.getProudSkillBonusMap().put(skillData.getProudSkillGroupId(), 3); this.getProudSkillBonusMap().put(skillData.getProudSkillGroupId(), 3);
} }
} }
} }
public EntityAvatar getAsEntity() { public EntityAvatar getAsEntity() {
for (EntityAvatar entity : getPlayer().getTeamManager().getActiveTeam()) { for (EntityAvatar entity : getPlayer().getTeamManager().getActiveTeam()) {
if (entity.getAvatar() == this) { if (entity.getAvatar() == this) {
return entity; return entity;
} }
} }
return null; return null;
} }
public int getEntityId() { public int getEntityId() {
EntityAvatar entity = getAsEntity(); EntityAvatar entity = getAsEntity();
return entity != null ? entity.getId() : 0; return entity != null ? entity.getId() : 0;
} }
public void save() { public void save() {
DatabaseHelper.saveAvatar(this); DatabaseHelper.saveAvatar(this);
} }
public AvatarInfo toProto() { public AvatarInfo toProto() {
int fetterLevel = this.getFetterLevel(); int fetterLevel = this.getFetterLevel();
AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder() AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder()
.setExpLevel(fetterLevel); .setExpLevel(fetterLevel);
if (fetterLevel != 10) { if (fetterLevel != 10) {
avatarFetter.setExpNumber(this.getFetterExp()); avatarFetter.setExpNumber(this.getFetterExp());
} }
if (this.getFetterList() != null) { if (this.getFetterList() != null) {
for (int i = 0; i < this.getFetterList().size(); i++) { for (int i = 0; i < this.getFetterList().size(); i++) {
avatarFetter.addFetterList( avatarFetter.addFetterList(
FetterData.newBuilder() FetterData.newBuilder()
.setFetterId(this.getFetterList().get(i)) .setFetterId(this.getFetterList().get(i))
.setFetterState(FetterState.FINISH.getValue()) .setFetterState(FetterState.FINISH.getValue())
); );
} }
} }
int cardId = this.getNameCardId(); int cardId = this.getNameCardId();
if (this.getPlayer().getNameCardList().contains(cardId)) { if (this.getPlayer().getNameCardList().contains(cardId)) {
avatarFetter.addRewardedFetterLevelList(10); avatarFetter.addRewardedFetterLevelList(10);
} }
AvatarInfo.Builder avatarInfo = AvatarInfo.newBuilder() AvatarInfo.Builder avatarInfo = AvatarInfo.newBuilder()
.setAvatarId(this.getAvatarId()) .setAvatarId(this.getAvatarId())
.setGuid(this.getGuid()) .setGuid(this.getGuid())
.setLifeState(1) .setLifeState(1)
.addAllTalentIdList(this.getTalentIdList()) .addAllTalentIdList(this.getTalentIdList())
.putAllFightPropMap(this.getFightProperties()) .putAllFightPropMap(this.getFightProperties())
.setSkillDepotId(this.getSkillDepotId()) .setSkillDepotId(this.getSkillDepotId())
.setCoreProudSkillLevel(this.getCoreProudSkillLevel()) .setCoreProudSkillLevel(this.getCoreProudSkillLevel())
.putAllSkillLevelMap(this.getSkillLevelMap()) .putAllSkillLevelMap(this.getSkillLevelMap())
.addAllInherentProudSkillList(this.getProudSkillList()) .addAllInherentProudSkillList(this.getProudSkillList())
.putAllProudSkillExtraLevelMap(getProudSkillBonusMap()) .putAllProudSkillExtraLevelMap(getProudSkillBonusMap())
.setAvatarType(1) .setAvatarType(1)
.setBornTime(this.getBornTime()) .setBornTime(this.getBornTime())
.setFetterInfo(avatarFetter) .setFetterInfo(avatarFetter)
.setWearingFlycloakId(this.getFlyCloak()) .setWearingFlycloakId(this.getFlyCloak())
.setCostumeId(this.getCostume()); .setCostumeId(this.getCostume());
for (Entry<Integer, Integer> entry : this.getSkillExtraChargeMap().entrySet()) { for (Entry<Integer, Integer> entry : this.getSkillExtraChargeMap().entrySet()) {
avatarInfo.putSkillMap(entry.getKey(), AvatarSkillInfo.newBuilder().setMaxChargeCount(entry.getValue()).build()); avatarInfo.putSkillMap(entry.getKey(), AvatarSkillInfo.newBuilder().setMaxChargeCount(entry.getValue()).build());
} }
for (GameItem item : this.getEquips().values()) { for (GameItem item : this.getEquips().values()) {
avatarInfo.addEquipGuidList(item.getGuid()); avatarInfo.addEquipGuidList(item.getGuid());
} }
avatarInfo.putPropMap(PlayerProperty.PROP_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, this.getLevel())); avatarInfo.putPropMap(PlayerProperty.PROP_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, this.getLevel()));
avatarInfo.putPropMap(PlayerProperty.PROP_EXP.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_EXP, this.getExp())); avatarInfo.putPropMap(PlayerProperty.PROP_EXP.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_EXP, this.getExp()));
avatarInfo.putPropMap(PlayerProperty.PROP_BREAK_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_BREAK_LEVEL, this.getPromoteLevel())); avatarInfo.putPropMap(PlayerProperty.PROP_BREAK_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_BREAK_LEVEL, this.getPromoteLevel()));
avatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_VAL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, 0)); avatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_VAL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, 0));
avatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_PENALTY_TIME.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_PENALTY_TIME, 0)); avatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_PENALTY_TIME.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_PENALTY_TIME, 0));
return avatarInfo.build(); return avatarInfo.build();
} }
// used only in character showcase // used only in character showcase
public ShowAvatarInfo toShowAvatarInfoProto() { public ShowAvatarInfo toShowAvatarInfoProto() {
AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder() AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder()
.setExpLevel(this.getFetterLevel()); .setExpLevel(this.getFetterLevel());
ShowAvatarInfo.Builder showAvatarInfo = ShowAvatarInfoOuterClass.ShowAvatarInfo.newBuilder() ShowAvatarInfo.Builder showAvatarInfo = ShowAvatarInfoOuterClass.ShowAvatarInfo.newBuilder()
.setAvatarId(avatarId) .setAvatarId(avatarId)
.addAllTalentIdList(this.getTalentIdList()) .addAllTalentIdList(this.getTalentIdList())
.putAllFightPropMap(this.getFightProperties()) .putAllFightPropMap(this.getFightProperties())
.setSkillDepotId(this.getSkillDepotId()) .setSkillDepotId(this.getSkillDepotId())
.setCoreProudSkillLevel(this.getCoreProudSkillLevel()) .setCoreProudSkillLevel(this.getCoreProudSkillLevel())
.addAllInherentProudSkillList(this.getProudSkillList()) .addAllInherentProudSkillList(this.getProudSkillList())
.putAllSkillLevelMap(this.getSkillLevelMap()) .putAllSkillLevelMap(this.getSkillLevelMap())
.putAllProudSkillExtraLevelMap(this.getProudSkillBonusMap()) .putAllProudSkillExtraLevelMap(this.getProudSkillBonusMap())
.setFetterInfo(avatarFetter) .setFetterInfo(avatarFetter)
.setCostumeId(this.getCostume()); .setCostumeId(this.getCostume());
showAvatarInfo.putPropMap(PlayerProperty.PROP_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, this.getLevel())); showAvatarInfo.putPropMap(PlayerProperty.PROP_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, this.getLevel()));
showAvatarInfo.putPropMap(PlayerProperty.PROP_EXP.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_EXP, this.getExp())); showAvatarInfo.putPropMap(PlayerProperty.PROP_EXP.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_EXP, this.getExp()));
showAvatarInfo.putPropMap(PlayerProperty.PROP_BREAK_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_BREAK_LEVEL, this.getPromoteLevel())); showAvatarInfo.putPropMap(PlayerProperty.PROP_BREAK_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_BREAK_LEVEL, this.getPromoteLevel()));
showAvatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_VAL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, this.getSatiation())); showAvatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_VAL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, this.getSatiation()));
showAvatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_PENALTY_TIME.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, this.getSatiationPenalty())); showAvatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_PENALTY_TIME.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, this.getSatiationPenalty()));
int maxStamina = this.getPlayer().getProperty(PlayerProperty.PROP_MAX_STAMINA); int maxStamina = this.getPlayer().getProperty(PlayerProperty.PROP_MAX_STAMINA);
showAvatarInfo.putPropMap(PlayerProperty.PROP_MAX_STAMINA.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_MAX_STAMINA, maxStamina)); showAvatarInfo.putPropMap(PlayerProperty.PROP_MAX_STAMINA.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_MAX_STAMINA, maxStamina));
for (GameItem item : this.getEquips().values()) { for (GameItem item : this.getEquips().values()) {
if (item.getItemType() == ItemType.ITEM_RELIQUARY) { if (item.getItemType() == ItemType.ITEM_RELIQUARY) {
showAvatarInfo.addEquipList(ShowEquip.newBuilder() showAvatarInfo.addEquipList(ShowEquip.newBuilder()
.setItemId(item.getItemId()) .setItemId(item.getItemId())
.setReliquary(item.toReliquaryProto())); .setReliquary(item.toReliquaryProto()));
} else if (item.getItemType() == ItemType.ITEM_WEAPON) { } else if (item.getItemType() == ItemType.ITEM_WEAPON) {
showAvatarInfo.addEquipList(ShowEquip.newBuilder() showAvatarInfo.addEquipList(ShowEquip.newBuilder()
.setItemId(item.getItemId()) .setItemId(item.getItemId())
.setWeapon(item.toWeaponProto())); .setWeapon(item.toWeaponProto()));
} }
} }
return showAvatarInfo.build(); return showAvatarInfo.build();
} }
@PostLoad @PostLoad
private void onLoad() { private void onLoad() {
} }
@PrePersist @PrePersist
private void prePersist() { private void prePersist() {
this.currentHp = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); this.currentHp = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
} }
} }
...@@ -19,155 +19,155 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap; ...@@ -19,155 +19,155 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
public class AvatarStorage extends BasePlayerManager implements Iterable<Avatar> { public class AvatarStorage extends BasePlayerManager implements Iterable<Avatar> {
private final Int2ObjectMap<Avatar> avatars; private final Int2ObjectMap<Avatar> avatars;
private final Long2ObjectMap<Avatar> avatarsGuid; private final Long2ObjectMap<Avatar> avatarsGuid;
public AvatarStorage(Player player) { public AvatarStorage(Player player) {
super(player); super(player);
this.avatars = new Int2ObjectOpenHashMap<>(); this.avatars = new Int2ObjectOpenHashMap<>();
this.avatarsGuid = new Long2ObjectOpenHashMap<>(); this.avatarsGuid = new Long2ObjectOpenHashMap<>();
} }
public Int2ObjectMap<Avatar> getAvatars() { public Int2ObjectMap<Avatar> getAvatars() {
return avatars; return avatars;
} }
public int getAvatarCount() { public int getAvatarCount() {
return this.avatars.size(); return this.avatars.size();
} }
public Avatar getAvatarById(int id) { public Avatar getAvatarById(int id) {
return getAvatars().get(id); return getAvatars().get(id);
} }
public Avatar getAvatarByGuid(long id) { public Avatar getAvatarByGuid(long id) {
return avatarsGuid.get(id); return avatarsGuid.get(id);
} }
public boolean hasAvatar(int id) { public boolean hasAvatar(int id) {
return getAvatars().containsKey(id); return getAvatars().containsKey(id);
} }
public boolean addAvatar(Avatar avatar) { public boolean addAvatar(Avatar avatar) {
if (avatar.getAvatarData() == null || this.hasAvatar(avatar.getAvatarId())) { if (avatar.getAvatarData() == null || this.hasAvatar(avatar.getAvatarId())) {
return false; return false;
} }
// Set owner first // Set owner first
avatar.setOwner(getPlayer()); avatar.setOwner(getPlayer());
// Put into maps // Put into maps
this.avatars.put(avatar.getAvatarId(), avatar); this.avatars.put(avatar.getAvatarId(), avatar);
this.avatarsGuid.put(avatar.getGuid(), avatar); this.avatarsGuid.put(avatar.getGuid(), avatar);
avatar.save(); avatar.save();
return true; return true;
} }
public void addStartingWeapon(Avatar avatar) { public void addStartingWeapon(Avatar avatar) {
// Make sure avatar owner is this player // Make sure avatar owner is this player
if (avatar.getPlayer() != this.getPlayer()) { if (avatar.getPlayer() != this.getPlayer()) {
return; return;
} }
// Create weapon // Create weapon
GameItem weapon = new GameItem(avatar.getAvatarData().getInitialWeapon()); GameItem weapon = new GameItem(avatar.getAvatarData().getInitialWeapon());
if (weapon.getItemData() != null) { if (weapon.getItemData() != null) {
this.getPlayer().getInventory().addItem(weapon); this.getPlayer().getInventory().addItem(weapon);
avatar.equipItem(weapon, true); avatar.equipItem(weapon, true);
} }
} }
public boolean wearFlycloak(long avatarGuid, int flycloakId) { public boolean wearFlycloak(long avatarGuid, int flycloakId) {
Avatar avatar = this.getAvatarByGuid(avatarGuid); Avatar avatar = this.getAvatarByGuid(avatarGuid);
if (avatar == null || !getPlayer().getFlyCloakList().contains(flycloakId)) { if (avatar == null || !getPlayer().getFlyCloakList().contains(flycloakId)) {
return false; return false;
} }
avatar.setFlyCloak(flycloakId); avatar.setFlyCloak(flycloakId);
avatar.save(); avatar.save();
// Update // Update
getPlayer().sendPacket(new PacketAvatarFlycloakChangeNotify(avatar)); getPlayer().sendPacket(new PacketAvatarFlycloakChangeNotify(avatar));
return true; return true;
} }
public boolean changeCostume(long avatarGuid, int costumeId) { public boolean changeCostume(long avatarGuid, int costumeId) {
Avatar avatar = this.getAvatarByGuid(avatarGuid); Avatar avatar = this.getAvatarByGuid(avatarGuid);
if (avatar == null) { if (avatar == null) {
return false; return false;
} }
if (costumeId != 0 && !getPlayer().getCostumeList().contains(costumeId)) { if (costumeId != 0 && !getPlayer().getCostumeList().contains(costumeId)) {
return false; return false;
} }
// TODO make sure avatar can wear costume // TODO make sure avatar can wear costume
avatar.setCostume(costumeId); avatar.setCostume(costumeId);
avatar.save(); avatar.save();
// Update entity // Update entity
EntityAvatar entity = avatar.getAsEntity(); EntityAvatar entity = avatar.getAsEntity();
if (entity == null) { if (entity == null) {
entity = new EntityAvatar(avatar); entity = new EntityAvatar(avatar);
getPlayer().sendPacket(new PacketAvatarChangeCostumeNotify(entity)); getPlayer().sendPacket(new PacketAvatarChangeCostumeNotify(entity));
} else { } else {
getPlayer().getScene().broadcastPacket(new PacketAvatarChangeCostumeNotify(entity)); getPlayer().getScene().broadcastPacket(new PacketAvatarChangeCostumeNotify(entity));
} }
// Done // Done
return true; return true;
} }
public void loadFromDatabase() { public void loadFromDatabase() {
List<Avatar> avatars = DatabaseHelper.getAvatars(getPlayer()); List<Avatar> avatars = DatabaseHelper.getAvatars(getPlayer());
for (Avatar avatar : avatars) { for (Avatar avatar : avatars) {
// Should never happen // Should never happen
if (avatar.getObjectId() == null) { if (avatar.getObjectId() == null) {
continue; continue;
} }
AvatarData avatarData = GameData.getAvatarDataMap().get(avatar.getAvatarId()); AvatarData avatarData = GameData.getAvatarDataMap().get(avatar.getAvatarId());
AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(avatar.getSkillDepotId()); AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(avatar.getSkillDepotId());
if (avatarData == null || skillDepot == null) { if (avatarData == null || skillDepot == null) {
continue; continue;
} }
// Set ownerships // Set ownerships
avatar.setAvatarData(avatarData); avatar.setAvatarData(avatarData);
avatar.setSkillDepot(skillDepot); avatar.setSkillDepot(skillDepot);
avatar.setOwner(getPlayer()); avatar.setOwner(getPlayer());
// Force recalc of const boosted skills // Force recalc of const boosted skills
avatar.recalcConstellations(); avatar.recalcConstellations();
// Add to avatar storage // Add to avatar storage
this.avatars.put(avatar.getAvatarId(), avatar); this.avatars.put(avatar.getAvatarId(), avatar);
this.avatarsGuid.put(avatar.getGuid(), avatar); this.avatarsGuid.put(avatar.getGuid(), avatar);
} }
} }
public void postLoad() { public void postLoad() {
for (Avatar avatar : this) { for (Avatar avatar : this) {
// Weapon check // Weapon check
if (avatar.getWeapon() == null) { if (avatar.getWeapon() == null) {
this.addStartingWeapon(avatar); this.addStartingWeapon(avatar);
} }
// Recalc stats // Recalc stats
avatar.recalcStats(); avatar.recalcStats();
} }
} }
@Override @Override
public Iterator<Avatar> iterator() { public Iterator<Avatar> iterator() {
return getAvatars().values().iterator(); return getAvatars().values().iterator();
} }
} }
...@@ -42,322 +42,322 @@ import lombok.Getter; ...@@ -42,322 +42,322 @@ import lombok.Getter;
@Entity(value = "battlepass", useDiscriminator = false) @Entity(value = "battlepass", useDiscriminator = false)
public class BattlePassManager extends BasePlayerDataManager { public class BattlePassManager extends BasePlayerDataManager {
@Id @Getter private ObjectId id; @Id @Getter private ObjectId id;
@Indexed private int ownerUid; @Indexed private int ownerUid;
@Getter private int point; @Getter private int point;
@Getter private int cyclePoints; // Weekly maximum cap @Getter private int cyclePoints; // Weekly maximum cap
@Getter private int level; @Getter private int level;
@Getter private boolean viewed; @Getter private boolean viewed;
private boolean paid; private boolean paid;
private Map<Integer, BattlePassMission> missions; private Map<Integer, BattlePassMission> missions;
private Map<Integer, BattlePassReward> takenRewards; private Map<Integer, BattlePassReward> takenRewards;
@Deprecated // Morphia only @Deprecated // Morphia only
public BattlePassManager() {} public BattlePassManager() {}
public BattlePassManager(Player player) { public BattlePassManager(Player player) {
super(player); super(player);
} }
public void setPlayer(Player player) { public void setPlayer(Player player) {
this.player = player; this.player = player;
this.ownerUid = player.getUid(); this.ownerUid = player.getUid();
} }
public void updateViewed() { public void updateViewed() {
this.viewed = true; this.viewed = true;
} }
public boolean setLevel(int level) { public boolean setLevel(int level) {
if (level >= 0 && level <= GameConstants.BATTLE_PASS_MAX_LEVEL) { if (level >= 0 && level <= GameConstants.BATTLE_PASS_MAX_LEVEL) {
this.level = level; this.level = level;
this.point = 0; this.point = 0;
this.player.sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.player)); this.player.sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.player));
return true; return true;
} }
return false; return false;
} }
public void addPoints(int points){ public void addPoints(int points) {
this.addPointsDirectly(points, false); this.addPointsDirectly(points, false);
this.player.sendPacket(new PacketBattlePassCurScheduleUpdateNotify(player)); this.player.sendPacket(new PacketBattlePassCurScheduleUpdateNotify(player));
this.save(); this.save();
} }
public void addPointsDirectly(int points, boolean isWeekly) { public void addPointsDirectly(int points, boolean isWeekly) {
int amount = points; int amount = points;
if (isWeekly) { if (isWeekly) {
amount = Math.min(amount, GameConstants.BATTLE_PASS_POINT_PER_WEEK - this.cyclePoints); amount = Math.min(amount, GameConstants.BATTLE_PASS_POINT_PER_WEEK - this.cyclePoints);
} }
if (amount <= 0) { if (amount <= 0) {
return; return;
} }
this.point += amount; this.point += amount;
this.cyclePoints += amount; this.cyclePoints += amount;
if (this.point >= GameConstants.BATTLE_PASS_POINT_PER_LEVEL && this.getLevel() < GameConstants.BATTLE_PASS_MAX_LEVEL) { if (this.point >= GameConstants.BATTLE_PASS_POINT_PER_LEVEL && this.getLevel() < GameConstants.BATTLE_PASS_MAX_LEVEL) {
int levelups = Math.floorDiv(this.point, GameConstants.BATTLE_PASS_POINT_PER_LEVEL); int levelups = Math.floorDiv(this.point, GameConstants.BATTLE_PASS_POINT_PER_LEVEL);
// Make sure player cant go above max BP level // Make sure player cant go above max BP level
levelups = Math.min(levelups, GameConstants.BATTLE_PASS_MAX_LEVEL - levelups); levelups = Math.min(levelups, GameConstants.BATTLE_PASS_MAX_LEVEL - levelups);
// Set new points after level up // Set new points after level up
this.point = this.point - (levelups * GameConstants.BATTLE_PASS_POINT_PER_LEVEL); this.point = this.point - (levelups * GameConstants.BATTLE_PASS_POINT_PER_LEVEL);
this.level += levelups; this.level += levelups;
}
}
public Map<Integer, BattlePassMission> getMissions() {
if (this.missions == null) this.missions = new HashMap<>();
return this.missions;
}
// Will return a new empty mission if the mission id is not found
public BattlePassMission loadMissionById(int id) {
return getMissions().computeIfAbsent(id, i -> new BattlePassMission(i));
}
public boolean hasMission(int id) {
return getMissions().containsKey(id);
}
public boolean isPaid() {
// ToDo: Change this when we actually support unlocking "paid" BP.
return true;
}
public Map<Integer, BattlePassReward> getTakenRewards() {
if (this.takenRewards == null) this.takenRewards = new HashMap<>();
return this.takenRewards;
}
// Mission triggers
public void triggerMission(WatcherTriggerType triggerType) {
getPlayer().getServer().getBattlePassSystem().triggerMission(getPlayer(), triggerType);
}
public void triggerMission(WatcherTriggerType triggerType, int param, int progress) {
getPlayer().getServer().getBattlePassSystem().triggerMission(getPlayer(), triggerType, param, progress);
}
// Handlers
public void takeMissionPoint(List<Integer> missionIdList) {
// Obvious exploit check
if (missionIdList.size() > GameData.getBattlePassMissionDataMap().size()) {
return;
}
List<BattlePassMission> updatedMissions = new ArrayList<>(missionIdList.size());
for (int id : missionIdList) {
// Skip if we dont have this mission
if (!this.hasMission(id)) {
continue;
}
BattlePassMission mission = this.loadMissionById(id);
if (mission.getData() == null) {
this.getMissions().remove(mission.getId());
continue;
}
// Take reward
if (mission.getStatus() == BattlePassMissionStatus.MISSION_STATUS_FINISHED) {
this.addPointsDirectly(mission.getData().getAddPoint(), mission.getData().isCycleRefresh());
mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_POINT_TAKEN);
updatedMissions.add(mission);
}
}
if (updatedMissions.size() > 0) {
// Save to db
this.save();
// Packet
getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(updatedMissions));
getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer()));
}
}
private void takeRewardsFromSelectChest(ItemData rewardItemData, int index, ItemParamData entry, List<GameItem> rewardItems) {
// Sanity checks.
if (rewardItemData.getItemUse().size() < 1) {
return;
}
// Get possible item choices.
String[] choices = rewardItemData.getItemUse().get(0).getUseParam().get(0).split(",");
if (choices.length < index) {
return;
}
// Get data for the selected item.
// This depends on the type of chest.
int chosenId = Integer.parseInt(choices[index - 1]);
// For ITEM_USE_ADD_SELECT_ITEM chests, we can directly add the item specified in the chest's data.
if (rewardItemData.getItemUse().get(0).getUseOp().equals("ITEM_USE_ADD_SELECT_ITEM")) {
GameItem rewardItem = new GameItem(GameData.getItemDataMap().get(chosenId), entry.getItemCount());
rewardItems.add(rewardItem);
}
// For ITEM_USE_GRANT_SELECT_REWARD chests, we have to again look up reward data.
else if (rewardItemData.getItemUse().get(0).getUseOp().equals("ITEM_USE_GRANT_SELECT_REWARD")) {
RewardData selectedReward = GameData.getRewardDataMap().get(chosenId);
for (var r : selectedReward.getRewardItemList()) {
GameItem rewardItem = new GameItem(GameData.getItemDataMap().get(r.getItemId()), r.getItemCount());
rewardItems.add(rewardItem);
}
}
else {
Grasscutter.getLogger().error("Invalid chest type for BP reward.");
}
}
public void takeReward(List<BattlePassRewardTakeOption> takeOptionList) {
List<BattlePassRewardTakeOption> rewardList = new ArrayList<>();
for (BattlePassRewardTakeOption option : takeOptionList) {
// Duplicate check
if (option.getTag().getRewardId() == 0 || getTakenRewards().containsKey(option.getTag().getRewardId())) {
continue;
}
// Level check
if (option.getTag().getLevel() > this.getLevel()) {
continue;
}
BattlePassRewardData rewardData = GameData.getBattlePassRewardDataMap().get(GameConstants.BATTLE_PASS_CURRENT_INDEX * 100 + option.getTag().getLevel());
// Sanity check with excel data
if (rewardData.getFreeRewardIdList().contains(option.getTag().getRewardId())) {
rewardList.add(option);
} else if (this.isPaid() && rewardData.getPaidRewardIdList().contains(option.getTag().getRewardId())) {
rewardList.add(option);
}
else {
Grasscutter.getLogger().info("Not in rewards list: {}", option.getTag().getRewardId());
}
}
// Get rewards
List<GameItem> rewardItems = null;
if (rewardList.size() > 0) {
rewardItems = new ArrayList<>();
for (var option : rewardList) {
var tag = option.getTag();
int index = option.getOptionIdx();
// Make sure we have reward data.
RewardData reward = GameData.getRewardDataMap().get(tag.getRewardId());
if (reward == null) {
continue;
}
// Add reward items.
for (var entry : reward.getRewardItemList()) {
ItemData rewardItemData = GameData.getItemDataMap().get(entry.getItemId());
// Some rewards are chests where the user can select the item they want.
if (rewardItemData.getMaterialType() == MaterialType.MATERIAL_SELECTABLE_CHEST) {
this.takeRewardsFromSelectChest(rewardItemData, index, entry, rewardItems);
}
// All other rewards directly give us the right item.
else {
GameItem rewardItem = new GameItem(rewardItemData, entry.getItemCount());
rewardItems.add(rewardItem);
}
}
// Construct the reward and set as taken.
BattlePassReward bpReward = new BattlePassReward(tag.getLevel(), tag.getRewardId(), tag.getUnlockStatus() == BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID);
this.getTakenRewards().put(bpReward.getRewardId(), bpReward);
}
// Save to db
this.save();
// Add items and send battle pass schedule packet
getPlayer().getInventory().addItems(rewardItems);
getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer()));
} }
getPlayer().sendPacket(new PacketTakeBattlePassRewardRsp(takeOptionList, rewardItems));
} }
public Map<Integer, BattlePassMission> getMissions() { public int buyLevels(int buyLevel) {
if (this.missions == null) this.missions = new HashMap<>(); int boughtLevels = Math.min(buyLevel, GameConstants.BATTLE_PASS_MAX_LEVEL - buyLevel);
return this.missions;
} if (boughtLevels > 0) {
int price = GameConstants.BATTLE_PASS_LEVEL_PRICE * boughtLevels;
// Will return a new empty mission if the mission id is not found
public BattlePassMission loadMissionById(int id) { if (getPlayer().getPrimogems() < price) {
return getMissions().computeIfAbsent(id, i -> new BattlePassMission(i)); return 0;
} }
public boolean hasMission(int id) { this.level += boughtLevels;
return getMissions().containsKey(id); this.save();
}
getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer()));
public boolean isPaid() { }
// ToDo: Change this when we actually support unlocking "paid" BP.
return true; return boughtLevels;
} }
public Map<Integer, BattlePassReward> getTakenRewards() { public void resetDailyMissions() {
if (this.takenRewards == null) this.takenRewards = new HashMap<>(); var resetMissions = new ArrayList<BattlePassMission>();
return this.takenRewards;
} for (var mission : this.missions.values()) {
if (mission.getData().getRefreshType() == null || mission.getData().getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_DAILY) {
// Mission triggers mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_UNFINISHED);
public void triggerMission(WatcherTriggerType triggerType) { mission.setProgress(0);
getPlayer().getServer().getBattlePassSystem().triggerMission(getPlayer(), triggerType);
} resetMissions.add(mission);
}
public void triggerMission(WatcherTriggerType triggerType, int param, int progress) { }
getPlayer().getServer().getBattlePassSystem().triggerMission(getPlayer(), triggerType, param, progress);
} this.getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(resetMissions));
this.getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.getPlayer()));
// Handlers }
public void takeMissionPoint(List<Integer> missionIdList) {
// Obvious exploit check public void resetWeeklyMissions() {
if (missionIdList.size() > GameData.getBattlePassMissionDataMap().size()) { var resetMissions = new ArrayList<BattlePassMission>();
return;
} for (var mission : this.missions.values()) {
if (mission.getData().getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE) {
List<BattlePassMission> updatedMissions = new ArrayList<>(missionIdList.size()); mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_UNFINISHED);
mission.setProgress(0);
for (int id : missionIdList) {
// Skip if we dont have this mission resetMissions.add(mission);
if (!this.hasMission(id)) { }
continue; }
}
this.getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(resetMissions));
BattlePassMission mission = this.loadMissionById(id); this.getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.getPlayer()));
}
if (mission.getData() == null) {
this.getMissions().remove(mission.getId()); //
continue; public BattlePassSchedule getScheduleProto() {
} var currentDate = LocalDate.now();
var nextSundayDate = (currentDate.getDayOfWeek() == DayOfWeek.SUNDAY)
// Take reward ? currentDate
if (mission.getStatus() == BattlePassMissionStatus.MISSION_STATUS_FINISHED) { : LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
this.addPointsDirectly(mission.getData().getAddPoint(), mission.getData().isCycleRefresh()); var nextSundayTime = LocalDateTime.of(nextSundayDate.getYear(), nextSundayDate.getMonthValue(), nextSundayDate.getDayOfMonth(), 23, 59, 59);
mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_POINT_TAKEN);
BattlePassSchedule.Builder schedule = BattlePassSchedule.newBuilder()
updatedMissions.add(mission);
}
}
if (updatedMissions.size() > 0) {
// Save to db
this.save();
// Packet
getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(updatedMissions));
getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer()));
}
}
private void takeRewardsFromSelectChest(ItemData rewardItemData, int index, ItemParamData entry, List<GameItem> rewardItems) {
// Sanity checks.
if (rewardItemData.getItemUse().size() < 1) {
return;
}
// Get possible item choices.
String[] choices = rewardItemData.getItemUse().get(0).getUseParam().get(0).split(",");
if (choices.length < index) {
return;
}
// Get data for the selected item.
// This depends on the type of chest.
int chosenId = Integer.parseInt(choices[index - 1]);
// For ITEM_USE_ADD_SELECT_ITEM chests, we can directly add the item specified in the chest's data.
if (rewardItemData.getItemUse().get(0).getUseOp().equals("ITEM_USE_ADD_SELECT_ITEM")) {
GameItem rewardItem = new GameItem(GameData.getItemDataMap().get(chosenId), entry.getItemCount());
rewardItems.add(rewardItem);
}
// For ITEM_USE_GRANT_SELECT_REWARD chests, we have to again look up reward data.
else if (rewardItemData.getItemUse().get(0).getUseOp().equals("ITEM_USE_GRANT_SELECT_REWARD")) {
RewardData selectedReward = GameData.getRewardDataMap().get(chosenId);
for (var r : selectedReward.getRewardItemList()) {
GameItem rewardItem = new GameItem(GameData.getItemDataMap().get(r.getItemId()), r.getItemCount());
rewardItems.add(rewardItem);
}
}
else {
Grasscutter.getLogger().error("Invalid chest type for BP reward.");
}
}
public void takeReward(List<BattlePassRewardTakeOption> takeOptionList) {
List<BattlePassRewardTakeOption> rewardList = new ArrayList<>();
for (BattlePassRewardTakeOption option : takeOptionList) {
// Duplicate check
if (option.getTag().getRewardId() == 0 || getTakenRewards().containsKey(option.getTag().getRewardId())) {
continue;
}
// Level check
if (option.getTag().getLevel() > this.getLevel()) {
continue;
}
BattlePassRewardData rewardData = GameData.getBattlePassRewardDataMap().get(GameConstants.BATTLE_PASS_CURRENT_INDEX * 100 + option.getTag().getLevel());
// Sanity check with excel data
if (rewardData.getFreeRewardIdList().contains(option.getTag().getRewardId())) {
rewardList.add(option);
} else if (this.isPaid() && rewardData.getPaidRewardIdList().contains(option.getTag().getRewardId())) {
rewardList.add(option);
}
else {
Grasscutter.getLogger().info("Not in rewards list: {}", option.getTag().getRewardId());
}
}
// Get rewards
List<GameItem> rewardItems = null;
if (rewardList.size() > 0) {
rewardItems = new ArrayList<>();
for (var option : rewardList) {
var tag = option.getTag();
int index = option.getOptionIdx();
// Make sure we have reward data.
RewardData reward = GameData.getRewardDataMap().get(tag.getRewardId());
if (reward == null) {
continue;
}
// Add reward items.
for (var entry : reward.getRewardItemList()) {
ItemData rewardItemData = GameData.getItemDataMap().get(entry.getItemId());
// Some rewards are chests where the user can select the item they want.
if (rewardItemData.getMaterialType() == MaterialType.MATERIAL_SELECTABLE_CHEST) {
this.takeRewardsFromSelectChest(rewardItemData, index, entry, rewardItems);
}
// All other rewards directly give us the right item.
else {
GameItem rewardItem = new GameItem(rewardItemData, entry.getItemCount());
rewardItems.add(rewardItem);
}
}
// Construct the reward and set as taken.
BattlePassReward bpReward = new BattlePassReward(tag.getLevel(), tag.getRewardId(), tag.getUnlockStatus() == BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID);
this.getTakenRewards().put(bpReward.getRewardId(), bpReward);
}
// Save to db
this.save();
// Add items and send battle pass schedule packet
getPlayer().getInventory().addItems(rewardItems);
getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer()));
}
getPlayer().sendPacket(new PacketTakeBattlePassRewardRsp(takeOptionList, rewardItems));
}
public int buyLevels(int buyLevel) {
int boughtLevels = Math.min(buyLevel, GameConstants.BATTLE_PASS_MAX_LEVEL - buyLevel);
if (boughtLevels > 0) {
int price = GameConstants.BATTLE_PASS_LEVEL_PRICE * boughtLevels;
if (getPlayer().getPrimogems() < price) {
return 0;
}
this.level += boughtLevels;
this.save();
getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer()));
}
return boughtLevels;
}
public void resetDailyMissions() {
var resetMissions = new ArrayList<BattlePassMission>();
for (var mission : this.missions.values()) {
if (mission.getData().getRefreshType() == null || mission.getData().getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_DAILY) {
mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_UNFINISHED);
mission.setProgress(0);
resetMissions.add(mission);
}
}
this.getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(resetMissions));
this.getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.getPlayer()));
}
public void resetWeeklyMissions() {
var resetMissions = new ArrayList<BattlePassMission>();
for (var mission : this.missions.values()) {
if (mission.getData().getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE) {
mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_UNFINISHED);
mission.setProgress(0);
resetMissions.add(mission);
}
}
this.getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(resetMissions));
this.getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.getPlayer()));
}
//
public BattlePassSchedule getScheduleProto() {
var currentDate = LocalDate.now();
var nextSundayDate = (currentDate.getDayOfWeek() == DayOfWeek.SUNDAY)
? currentDate
: LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
var nextSundayTime = LocalDateTime.of(nextSundayDate.getYear(), nextSundayDate.getMonthValue(), nextSundayDate.getDayOfMonth(), 23, 59, 59);
BattlePassSchedule.Builder schedule = BattlePassSchedule.newBuilder()
.setScheduleId(2700) .setScheduleId(2700)
.setLevel(this.getLevel()) .setLevel(this.getLevel())
.setPoint(this.getPoint()) .setPoint(this.getPoint())
...@@ -366,21 +366,21 @@ public class BattlePassManager extends BasePlayerDataManager { ...@@ -366,21 +366,21 @@ public class BattlePassManager extends BasePlayerDataManager {
.setIsViewed(this.isViewed()) .setIsViewed(this.isViewed())
.setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE) .setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE)
.setJPFMGBEBBBJ(2) // Not bought on Playstation. .setJPFMGBEBBBJ(2) // Not bought on Playstation.
.setCurCyclePoints(this.getCyclePoints()) .setCurCyclePoints(this.getCyclePoints())
.setCurCycle(BattlePassCycle.newBuilder() .setCurCycle(BattlePassCycle.newBuilder()
.setBeginTime(0) .setBeginTime(0)
.setEndTime((int)nextSundayTime.atZone(ZoneId.systemDefault()).toEpochSecond()) .setEndTime((int)nextSundayTime.atZone(ZoneId.systemDefault()).toEpochSecond())
.setCycleIdx(3) .setCycleIdx(3)
); );
for (BattlePassReward reward : getTakenRewards().values()) { for (BattlePassReward reward : getTakenRewards().values()) {
schedule.addRewardTakenList(reward.toProto()); schedule.addRewardTakenList(reward.toProto());
} }
return schedule.build(); return schedule.build();
} }
public void save() { public void save() {
DatabaseHelper.saveBattlePass(this); DatabaseHelper.saveBattlePass(this);
} }
} }
...@@ -16,64 +16,64 @@ import emu.grasscutter.server.game.GameServer; ...@@ -16,64 +16,64 @@ import emu.grasscutter.server.game.GameServer;
import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify; import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify;
public class BattlePassSystem extends BaseGameSystem { public class BattlePassSystem extends BaseGameSystem {
private final Map<WatcherTriggerType, List<BattlePassMissionData>> cachedTriggers; private final Map<WatcherTriggerType, List<BattlePassMissionData>> cachedTriggers;
// BP Mission manager for the server, contains cached triggers so we dont have to load it for each player // BP Mission manager for the server, contains cached triggers so we dont have to load it for each player
public BattlePassSystem(GameServer server) { public BattlePassSystem(GameServer server) {
super(server); super(server);
this.cachedTriggers = new HashMap<>(); this.cachedTriggers = new HashMap<>();
for (BattlePassMissionData missionData : GameData.getBattlePassMissionDataMap().values()) { for (BattlePassMissionData missionData : GameData.getBattlePassMissionDataMap().values()) {
if (missionData.isValidRefreshType()) { if (missionData.isValidRefreshType()) {
List<BattlePassMissionData> triggerList = getTriggers().computeIfAbsent(missionData.getTriggerType(), e -> new ArrayList<>()); List<BattlePassMissionData> triggerList = getTriggers().computeIfAbsent(missionData.getTriggerType(), e -> new ArrayList<>());
triggerList.add(missionData); triggerList.add(missionData);
} }
} }
} }
public GameServer getServer() { public GameServer getServer() {
return server; return server;
} }
private Map<WatcherTriggerType, List<BattlePassMissionData>> getTriggers() { private Map<WatcherTriggerType, List<BattlePassMissionData>> getTriggers() {
return cachedTriggers; return cachedTriggers;
} }
public void triggerMission(Player player, WatcherTriggerType triggerType) { public void triggerMission(Player player, WatcherTriggerType triggerType) {
triggerMission(player, triggerType, 0, 1); triggerMission(player, triggerType, 0, 1);
} }
public void triggerMission(Player player, WatcherTriggerType triggerType, int param, int progress) { public void triggerMission(Player player, WatcherTriggerType triggerType, int param, int progress) {
List<BattlePassMissionData> triggerList = getTriggers().get(triggerType); List<BattlePassMissionData> triggerList = getTriggers().get(triggerType);
if (triggerList == null || triggerList.isEmpty()) return; if (triggerList == null || triggerList.isEmpty()) return;
for (BattlePassMissionData data : triggerList) { for (BattlePassMissionData data : triggerList) {
// Skip params check if param == 0 // Skip params check if param == 0
if (param != 0) { if (param != 0) {
if (!data.getMainParams().contains(param)) { if (!data.getMainParams().contains(param)) {
continue; continue;
} }
} }
// Get mission from player, if it doesnt exist, then we make one // Get mission from player, if it doesnt exist, then we make one
BattlePassMission mission = player.getBattlePassManager().loadMissionById(data.getId()); BattlePassMission mission = player.getBattlePassManager().loadMissionById(data.getId());
if (mission.isFinshed()) continue; if (mission.isFinshed()) continue;
// Add progress // Add progress
mission.addProgress(progress, data.getProgress()); mission.addProgress(progress, data.getProgress());
if (mission.getProgress() >= data.getProgress()) { if (mission.getProgress() >= data.getProgress()) {
mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_FINISHED); mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_FINISHED);
} }
// Save to db // Save to db
player.getBattlePassManager().save(); player.getBattlePassManager().save();
// Packet // Packet
player.sendPacket(new PacketBattlePassMissionUpdateNotify(mission)); player.sendPacket(new PacketBattlePassMissionUpdateNotify(mission));
} }
} }
} }
...@@ -31,59 +31,59 @@ import java.util.List; ...@@ -31,59 +31,59 @@ import java.util.List;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
public class CombineManger extends BaseGameSystem { public class CombineManger extends BaseGameSystem {
private final static Int2ObjectMap<List<Integer>> reliquaryDecomposeData = new Int2ObjectOpenHashMap<>(); private final static Int2ObjectMap<List<Integer>> reliquaryDecomposeData = new Int2ObjectOpenHashMap<>();
public CombineManger(GameServer server) { public CombineManger(GameServer server) {
super(server); super(server);
} }
public static void initialize() { public static void initialize() {
// Read the data we need for strongbox. // Read the data we need for strongbox.
try (Reader fileReader = DataLoader.loadReader("ReliquaryDecompose.json")) { try (Reader fileReader = DataLoader.loadReader("ReliquaryDecompose.json")) {
List<ReliquaryDecomposeEntry> decomposeEntries = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ReliquaryDecomposeEntry.class).getType()); List<ReliquaryDecomposeEntry> decomposeEntries = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ReliquaryDecomposeEntry.class).getType());
for (ReliquaryDecomposeEntry entry : decomposeEntries) { for (ReliquaryDecomposeEntry entry : decomposeEntries) {
reliquaryDecomposeData.put(entry.getConfigId(), entry.getItems()); reliquaryDecomposeData.put(entry.getConfigId(), entry.getItems());
} }
Grasscutter.getLogger().debug("Loaded {} reliquary decompose entries.", reliquaryDecomposeData.size()); Grasscutter.getLogger().debug("Loaded {} reliquary decompose entries.", reliquaryDecomposeData.size());
} }
catch (Exception ex) { catch (Exception ex) {
Grasscutter.getLogger().error("Unable to load reliquary decompose data.", ex); Grasscutter.getLogger().error("Unable to load reliquary decompose data.", ex);
} }
} }
public boolean unlockCombineDiagram(Player player, GameItem diagramItem) { public boolean unlockCombineDiagram(Player player, GameItem diagramItem) {
// Make sure this is actually a diagram. // Make sure this is actually a diagram.
if (!diagramItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COMBINE")) { if (!diagramItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COMBINE")) {
return false; return false;
} }
// Determine the combine item we should unlock. // Determine the combine item we should unlock.
int combineId = Integer.parseInt(diagramItem.getItemData().getItemUse().get(0).getUseParam().get(0)); int combineId = Integer.parseInt(diagramItem.getItemData().getItemUse().get(0).getUseParam().get(0));
// Remove the diagram from the player's inventory. // Remove the diagram from the player's inventory.
// We need to do this here, before sending CombineFormulaDataNotify, or the the combine UI won't correctly // We need to do this here, before sending CombineFormulaDataNotify, or the the combine UI won't correctly
// update when unlocking the diagram. // update when unlocking the diagram.
player.getInventory().removeItem(diagramItem, 1); player.getInventory().removeItem(diagramItem, 1);
// Tell the client that this diagram is now unlocked and add the unlocked item to the player. // Tell the client that this diagram is now unlocked and add the unlocked item to the player.
player.getUnlockedCombines().add(combineId); player.getUnlockedCombines().add(combineId);
player.sendPacket(new PacketCombineFormulaDataNotify(combineId)); player.sendPacket(new PacketCombineFormulaDataNotify(combineId));
return true; return true;
} }
public CombineResult combineItem(Player player, int cid, int count){ public CombineResult combineItem(Player player, int cid, int count) {
// check config exist // check config exist
if(!GameData.getCombineDataMap().containsKey(cid)){ if (!GameData.getCombineDataMap().containsKey(cid)) {
player.getWorld().getHost().sendPacket(new PacketCombineRsp()); player.getWorld().getHost().sendPacket(new PacketCombineRsp());
return null; return null;
} }
CombineData combineData = GameData.getCombineDataMap().get(cid); CombineData combineData = GameData.getCombineDataMap().get(cid);
if(combineData.getPlayerLevel() > player.getLevel()){ if (combineData.getPlayerLevel() > player.getLevel()) {
return null; return null;
} }
...@@ -120,7 +120,7 @@ public class CombineManger extends BaseGameSystem { ...@@ -120,7 +120,7 @@ public class CombineManger extends BaseGameSystem {
player.sendPacket(new PacketReliquaryDecomposeRsp(Retcode.RET_RELIQUARY_DECOMPOSE_PARAM_ERROR)); player.sendPacket(new PacketReliquaryDecomposeRsp(Retcode.RET_RELIQUARY_DECOMPOSE_PARAM_ERROR));
return; return;
} }
// Check if the number of input items matches the output count. // Check if the number of input items matches the output count.
if (input.size() != count * 3) { if (input.size() != count * 3) {
player.sendPacket(new PacketReliquaryDecomposeRsp(Retcode.RET_RELIQUARY_DECOMPOSE_PARAM_ERROR)); player.sendPacket(new PacketReliquaryDecomposeRsp(Retcode.RET_RELIQUARY_DECOMPOSE_PARAM_ERROR));
...@@ -144,7 +144,7 @@ public class CombineManger extends BaseGameSystem { ...@@ -144,7 +144,7 @@ public class CombineManger extends BaseGameSystem {
List<Long> resultItems = new ArrayList<>(); List<Long> resultItems = new ArrayList<>();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
int itemId = Utils.drawRandomListElement(possibleDrops); int itemId = Utils.drawRandomListElement(possibleDrops);
GameItem newReliquary = new GameItem(itemId, 1); GameItem newReliquary = new GameItem(itemId, 1);
player.getInventory().addItem(newReliquary); player.getInventory().addItem(newReliquary);
resultItems.add(newReliquary.getGuid()); resultItems.add(newReliquary.getGuid());
......
...@@ -32,7 +32,7 @@ public class DropSystem extends BaseGameSystem { ...@@ -32,7 +32,7 @@ public class DropSystem extends BaseGameSystem {
this.dropData = new Int2ObjectOpenHashMap<>(); this.dropData = new Int2ObjectOpenHashMap<>();
this.load(); this.load();
} }
public Int2ObjectMap<List<DropData>> getDropData() { public Int2ObjectMap<List<DropData>> getDropData() {
return dropData; return dropData;
} }
...@@ -41,7 +41,7 @@ public class DropSystem extends BaseGameSystem { ...@@ -41,7 +41,7 @@ public class DropSystem extends BaseGameSystem {
try (Reader fileReader = DataLoader.loadReader("Drop.json")) { try (Reader fileReader = DataLoader.loadReader("Drop.json")) {
getDropData().clear(); getDropData().clear();
List<DropInfo> banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, DropInfo.class).getType()); List<DropInfo> banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, DropInfo.class).getType());
if(banners.size() > 0) { if (banners.size() > 0) {
for (DropInfo di : banners) { for (DropInfo di : banners) {
getDropData().put(di.getMonsterId(), di.getDropDataList()); getDropData().put(di.getMonsterId(), di.getDropDataList());
} }
......
...@@ -20,95 +20,95 @@ import emu.grasscutter.utils.Position; ...@@ -20,95 +20,95 @@ import emu.grasscutter.utils.Position;
import java.util.List; import java.util.List;
public class DungeonSystem extends BaseGameSystem { public class DungeonSystem extends BaseGameSystem {
private static final BasicDungeonSettleListener basicDungeonSettleObserver = new BasicDungeonSettleListener(); private static final BasicDungeonSettleListener basicDungeonSettleObserver = new BasicDungeonSettleListener();
public DungeonSystem(GameServer server) { public DungeonSystem(GameServer server) {
super(server); super(server);
} }
public void getEntryInfo(Player player, int pointId) { public void getEntryInfo(Player player, int pointId) {
ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId); ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId);
if (entry == null) { if (entry == null) {
// Error // Error
player.sendPacket(new PacketDungeonEntryInfoRsp()); player.sendPacket(new PacketDungeonEntryInfoRsp());
return; return;
} }
player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData())); player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData()));
} }
public boolean enterDungeon(Player player, int pointId, int dungeonId) { public boolean enterDungeon(Player player, int pointId, int dungeonId) {
DungeonData data = GameData.getDungeonDataMap().get(dungeonId); DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
if (data == null) { if (data == null) {
return false; return false;
} }
Grasscutter.getLogger().info("{}({}) is trying to enter dungeon {}" ,player.getNickname(),player.getUid(),dungeonId); Grasscutter.getLogger().info("{}({}) is trying to enter dungeon {}" ,player.getNickname(),player.getUid(),dungeonId);
int sceneId = data.getSceneId(); int sceneId = data.getSceneId();
player.getScene().setPrevScene(sceneId); player.getScene().setPrevScene(sceneId);
if (player.getWorld().transferPlayerToScene(player, sceneId, data)) { if (player.getWorld().transferPlayerToScene(player, sceneId, data)) {
player.getScene().addDungeonSettleObserver(basicDungeonSettleObserver); player.getScene().addDungeonSettleObserver(basicDungeonSettleObserver);
player.getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_ENTER_DUNGEON, data.getId()); player.getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_ENTER_DUNGEON, data.getId());
} }
player.getScene().setPrevScenePoint(pointId); player.getScene().setPrevScenePoint(pointId);
player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId)); player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId));
return true; return true;
} }
/** /**
* used in tower dungeons handoff * used in tower dungeons handoff
*/ */
public boolean handoffDungeon(Player player, int dungeonId, List<DungeonSettleListener> dungeonSettleListeners) { public boolean handoffDungeon(Player player, int dungeonId, List<DungeonSettleListener> dungeonSettleListeners) {
DungeonData data = GameData.getDungeonDataMap().get(dungeonId); DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
if (data == null) { if (data == null) {
return false; return false;
} }
Grasscutter.getLogger().info("{}({}) is trying to enter tower dungeon {}" ,player.getNickname(),player.getUid(),dungeonId); Grasscutter.getLogger().info("{}({}) is trying to enter tower dungeon {}" ,player.getNickname(),player.getUid(),dungeonId);
if(player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)){ if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) {
dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver); dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver);
} }
return true; return true;
} }
public void exitDungeon(Player player) { public void exitDungeon(Player player) {
Scene scene = player.getScene(); Scene scene = player.getScene();
if (scene==null || scene.getSceneType() != SceneType.SCENE_DUNGEON) { if (scene==null || scene.getSceneType() != SceneType.SCENE_DUNGEON) {
return; return;
} }
// Get previous scene // Get previous scene
int prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3; int prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3;
// Get previous position // Get previous position
DungeonData dungeonData = scene.getDungeonData(); DungeonData dungeonData = scene.getDungeonData();
Position prevPos = new Position(GameConstants.START_POSITION); Position prevPos = new Position(GameConstants.START_POSITION);
if (dungeonData != null) { if (dungeonData != null) {
ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, scene.getPrevScenePoint()); ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, scene.getPrevScenePoint());
if (entry != null) { if (entry != null) {
prevPos.set(entry.getPointData().getTranPos()); prevPos.set(entry.getPointData().getTranPos());
} }
} }
// clean temp team if it has // clean temp team if it has
player.getTeamManager().cleanTemporaryTeam(); player.getTeamManager().cleanTemporaryTeam();
player.getTowerManager().clearEntry(); player.getTowerManager().clearEntry();
// Transfer player back to world // Transfer player back to world
player.getWorld().transferPlayerToScene(player, prevScene, prevPos); player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp)); player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));
} }
public void updateDailyDungeons() { public void updateDailyDungeons() {
for (ScenePointEntry entry : GameData.getScenePointEntries().values()) { for (ScenePointEntry entry : GameData.getScenePointEntries().values()) {
entry.getPointData().updateDailyDungeon(); entry.getPointData().updateDailyDungeon();
} }
} }
} }
...@@ -36,180 +36,180 @@ import com.google.gson.reflect.TypeToken; ...@@ -36,180 +36,180 @@ import com.google.gson.reflect.TypeToken;
public class DungeonChallenge extends WorldChallenge { public class DungeonChallenge extends WorldChallenge {
/** /**
* has more challenge * has more challenge
*/ */
private boolean stage; private boolean stage;
private IntSet rewardedPlayers; private IntSet rewardedPlayers;
private final static Int2ObjectMap<List<DungeonDropEntry>> dungeonDropData = new Int2ObjectOpenHashMap<>(); private final static Int2ObjectMap<List<DungeonDropEntry>> dungeonDropData = new Int2ObjectOpenHashMap<>();
public static void initialize() { public static void initialize() {
// Read the data we need for dungeon rewards drops. // Read the data we need for dungeon rewards drops.
try (Reader fileReader = DataLoader.loadReader("DungeonDrop.json")) { try (Reader fileReader = DataLoader.loadReader("DungeonDrop.json")) {
List<DungeonDrop> dungeonDropList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, DungeonDrop.class).getType()); List<DungeonDrop> dungeonDropList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, DungeonDrop.class).getType());
for (DungeonDrop entry : dungeonDropList) { for (DungeonDrop entry : dungeonDropList) {
dungeonDropData.put(entry.getDungeonId(), entry.getDrops()); dungeonDropData.put(entry.getDungeonId(), entry.getDrops());
} }
Grasscutter.getLogger().debug("Loaded {} dungeon drop data entries.", dungeonDropData.size()); Grasscutter.getLogger().debug("Loaded {} dungeon drop data entries.", dungeonDropData.size());
} }
catch (Exception ex) { catch (Exception ex) {
Grasscutter.getLogger().error("Unable to load dungeon drop data.", ex); Grasscutter.getLogger().error("Unable to load dungeon drop data.", ex);
} }
} }
public DungeonChallenge(Scene scene, SceneGroup group, public DungeonChallenge(Scene scene, SceneGroup group,
int challengeId, int challengeIndex, int challengeId, int challengeIndex,
List<Integer> paramList, List<Integer> paramList,
int timeLimit, int goal, int timeLimit, int goal,
List<ChallengeTrigger> challengeTriggers) { List<ChallengeTrigger> challengeTriggers) {
super(scene, group, challengeId, challengeIndex, paramList, timeLimit, goal, challengeTriggers); super(scene, group, challengeId, challengeIndex, paramList, timeLimit, goal, challengeTriggers);
this.setRewardedPlayers(new IntOpenHashSet()); this.setRewardedPlayers(new IntOpenHashSet());
} }
public boolean isStage() { public boolean isStage() {
return stage; return stage;
} }
public void setStage(boolean stage) { public void setStage(boolean stage) {
this.stage = stage; this.stage = stage;
} }
public IntSet getRewardedPlayers() { public IntSet getRewardedPlayers() {
return rewardedPlayers; return rewardedPlayers;
} }
public void setRewardedPlayers(IntSet rewardedPlayers) { public void setRewardedPlayers(IntSet rewardedPlayers) {
this.rewardedPlayers = rewardedPlayers; this.rewardedPlayers = rewardedPlayers;
} }
@Override @Override
public void done() { public void done() {
super.done(); super.done();
if (this.isSuccess()) { if (this.isSuccess()) {
// Settle // Settle
settle(); settle();
} }
} }
private void settle() { private void settle() {
if(!stage){ if (!stage) {
getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene())); getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene()));
getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE, getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE,
new ScriptArgs(this.isSuccess() ? 1 : 0)); new ScriptArgs(this.isSuccess() ? 1 : 0));
// Battle pass trigger // Battle pass trigger
this.getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON)); this.getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON));
} }
} }
private List<GameItem> rollRewards(boolean useCondensed) { private List<GameItem> rollRewards(boolean useCondensed) {
List<GameItem> rewards = new ArrayList<>(); List<GameItem> rewards = new ArrayList<>();
int dungeonId = this.getScene().getDungeonData().getId(); int dungeonId = this.getScene().getDungeonData().getId();
// If we have specific drop data for this dungeon, we use it. // If we have specific drop data for this dungeon, we use it.
if (dungeonDropData.containsKey(dungeonId)) { if (dungeonDropData.containsKey(dungeonId)) {
List<DungeonDropEntry> dropEntries = dungeonDropData.get(dungeonId); List<DungeonDropEntry> dropEntries = dungeonDropData.get(dungeonId);
// Roll for each drop group. // Roll for each drop group.
for (var entry : dropEntries) { for (var entry : dropEntries) {
// Determine the number of drops we get for this entry. // Determine the number of drops we get for this entry.
int start = entry.getCounts().get(0); int start = entry.getCounts().get(0);
int end = entry.getCounts().get(entry.getCounts().size() - 1); int end = entry.getCounts().get(entry.getCounts().size() - 1);
var candidateAmounts = IntStream.range(start, end + 1).boxed().collect(Collectors.toList()); var candidateAmounts = IntStream.range(start, end + 1).boxed().collect(Collectors.toList());
int amount = Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities()); int amount = Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
if (useCondensed) { if (useCondensed) {
amount += Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities()); amount += Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities());
} }
// Double rewards in multiplay mode, if specified. // Double rewards in multiplay mode, if specified.
if (entry.isMpDouble() && this.getScene().getPlayerCount() > 1) { if (entry.isMpDouble() && this.getScene().getPlayerCount() > 1) {
amount *= 2; amount *= 2;
} }
// Roll items for this group. // Roll items for this group.
// Here, we have to handle stacking, or the client will not display results correctly. // Here, we have to handle stacking, or the client will not display results correctly.
// For now, we use the following logic: If the possible drop item are a list of multiple items, // For now, we use the following logic: If the possible drop item are a list of multiple items,
// we roll them separately. If not, we stack them. This should work out in practice, at least // we roll them separately. If not, we stack them. This should work out in practice, at least
// for the currently existing set of dungeons. // for the currently existing set of dungeons.
if (entry.getItems().size() == 1) { if (entry.getItems().size() == 1) {
rewards.add(new GameItem(entry.getItems().get(0), amount)); rewards.add(new GameItem(entry.getItems().get(0), amount));
} }
else { else {
for (int i = 0; i < amount; i++) { for (int i = 0; i < amount; i++) {
// int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size()); // int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size());
// int itemId = entry.getItems().get(itemIndex); // int itemId = entry.getItems().get(itemIndex);
int itemId = Utils.drawRandomListElement(entry.getItems(), entry.getItemProbabilities()); int itemId = Utils.drawRandomListElement(entry.getItems(), entry.getItemProbabilities());
rewards.add(new GameItem(itemId, 1)); rewards.add(new GameItem(itemId, 1));
} }
} }
} }
} }
// Otherwise, we fall back to the preview data. // Otherwise, we fall back to the preview data.
else { else {
Grasscutter.getLogger().info("No drop data found or dungeon {}, falling back to preview data ...", dungeonId); Grasscutter.getLogger().info("No drop data found or dungeon {}, falling back to preview data ...", dungeonId);
for (ItemParamData param : getScene().getDungeonData().getRewardPreview().getPreviewItems()) { for (ItemParamData param : getScene().getDungeonData().getRewardPreview().getPreviewItems()) {
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1))); rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
} }
} }
return rewards; return rewards;
} }
public void getStatueDrops(Player player, GadgetInteractReq request) { public void getStatueDrops(Player player, GadgetInteractReq request) {
DungeonData dungeonData = getScene().getDungeonData(); DungeonData dungeonData = getScene().getDungeonData();
int resinCost = dungeonData.getStatueCostCount() != 0 ? dungeonData.getStatueCostCount() : 20; int resinCost = dungeonData.getStatueCostCount() != 0 ? dungeonData.getStatueCostCount() : 20;
if (!isSuccess() || dungeonData == null || dungeonData.getRewardPreview() == null || dungeonData.getRewardPreview().getPreviewItems().length == 0) { if (!isSuccess() || dungeonData == null || dungeonData.getRewardPreview() == null || dungeonData.getRewardPreview().getPreviewItems().length == 0) {
return; return;
} }
// Already rewarded // Already rewarded
if (getRewardedPlayers().contains(player.getUid())) { if (getRewardedPlayers().contains(player.getUid())) {
return; return;
} }
// Get rewards. // Get rewards.
List<GameItem> rewards = new ArrayList<>(); List<GameItem> rewards = new ArrayList<>();
if (request.getIsUseCondenseResin()) { if (request.getIsUseCondenseResin()) {
// Check if condensed resin is usable here. // Check if condensed resin is usable here.
// For this, we use the following logic for now: // For this, we use the following logic for now:
// The normal resin cost of the dungeon has to be 20. // The normal resin cost of the dungeon has to be 20.
if (resinCost != 20) { if (resinCost != 20) {
return; return;
} }
// Make sure the player has condensed resin. // Make sure the player has condensed resin.
GameItem condensedResin = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(220007); GameItem condensedResin = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(220007);
if (condensedResin == null || condensedResin.getCount() <= 0) { if (condensedResin == null || condensedResin.getCount() <= 0) {
return; return;
} }
// Deduct. // Deduct.
player.getInventory().removeItem(condensedResin, 1); player.getInventory().removeItem(condensedResin, 1);
// Roll rewards. // Roll rewards.
rewards.addAll(this.rollRewards(true)); rewards.addAll(this.rollRewards(true));
} }
else { else {
// If the player used regular resin, try to deduct. // If the player used regular resin, try to deduct.
// Stop if insufficient resin. // Stop if insufficient resin.
boolean success = player.getResinManager().useResin(resinCost); boolean success = player.getResinManager().useResin(resinCost);
if (!success) { if (!success) {
return; return;
} }
// Roll rewards. // Roll rewards.
rewards.addAll(this.rollRewards(false)); rewards.addAll(this.rollRewards(false));
} }
// Add rewards to player and send notification. // Add rewards to player and send notification.
player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop); player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop);
player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards)); player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards));
getRewardedPlayers().add(player.getUid()); getRewardedPlayers().add(player.getUid());
} }
} }
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