mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-01-10 18:03:20 +08:00
Run spotlessApply
This commit is contained in:
parent
75f163f704
commit
ee298235c2
@ -189,26 +189,33 @@ public final class GameData {
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<CookRecipeData> cookRecipeDataMap =
|
private static final Int2ObjectMap<CookRecipeData> cookRecipeDataMap =
|
||||||
new Int2ObjectOpenHashMap<>();
|
new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<CompoundData> compoundDataMap = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<CompoundData> compoundDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<DailyDungeonData> dailyDungeonDataMap =
|
private static final Int2ObjectMap<DailyDungeonData> dailyDungeonDataMap =
|
||||||
new Int2ObjectOpenHashMap<>();
|
new Int2ObjectOpenHashMap<>();
|
||||||
@Getter private static final Int2ObjectMap<DropTableData> dropTableDataMap = new Int2ObjectOpenHashMap<>();
|
|
||||||
@Getter private static final Int2ObjectMap<DropMaterialData> dropMaterialDataMap = new Int2ObjectOpenHashMap<>();
|
@Getter
|
||||||
|
private static final Int2ObjectMap<DropTableData> dropTableDataMap =
|
||||||
|
new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private static final Int2ObjectMap<DropMaterialData> dropMaterialDataMap =
|
||||||
|
new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<DungeonData> dungeonDataMap = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<DungeonData> dungeonDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<DungeonEntryData> dungeonEntryDataMap =
|
private static final Int2ObjectMap<DungeonEntryData> dungeonEntryDataMap =
|
||||||
new Int2ObjectOpenHashMap<>();
|
new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<EnvAnimalGatherConfigData> envAnimalGatherConfigDataMap =
|
private static final Int2ObjectMap<EnvAnimalGatherConfigData> envAnimalGatherConfigDataMap =
|
||||||
new Int2ObjectOpenHashMap<>();
|
new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<EquipAffixData> equipAffixDataMap =
|
private static final Int2ObjectMap<EquipAffixData> equipAffixDataMap =
|
||||||
|
@ -44,11 +44,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import lombok.val;
|
|
||||||
import org.reflections.Reflections;
|
|
||||||
|
|
||||||
import javax.script.Bindings;
|
import javax.script.Bindings;
|
||||||
import javax.script.CompiledScript;
|
import javax.script.CompiledScript;
|
||||||
|
import lombok.val;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
public final class ResourceLoader {
|
public final class ResourceLoader {
|
||||||
|
|
||||||
@ -666,27 +665,31 @@ public final class ResourceLoader {
|
|||||||
val pattern = Pattern.compile("ConfigLevelEntity_(.+?)\\.json");
|
val pattern = Pattern.compile("ConfigLevelEntity_(.+?)\\.json");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var stream = Files.newDirectoryStream(getResourcePath("BinOutput/LevelEntity/"), "ConfigLevelEntity_*.json");
|
var stream =
|
||||||
stream.forEach(path -> {
|
Files.newDirectoryStream(
|
||||||
val matcher = pattern.matcher(path.getFileName().toString());
|
getResourcePath("BinOutput/LevelEntity/"), "ConfigLevelEntity_*.json");
|
||||||
if (!matcher.find()) return;
|
stream.forEach(
|
||||||
Map<String, ConfigLevelEntity> config;
|
path -> {
|
||||||
|
val matcher = pattern.matcher(path.getFileName().toString());
|
||||||
|
if (!matcher.find()) return;
|
||||||
|
Map<String, ConfigLevelEntity> config;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
config = JsonUtils.loadToMap(path, String.class, ConfigLevelEntity.class);
|
config = JsonUtils.loadToMap(path, String.class, ConfigLevelEntity.class);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error("Error loading player ability embryos:", e);
|
Grasscutter.getLogger().error("Error loading player ability embryos:", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GameData.getConfigLevelEntityDataMap().putAll(config);
|
GameData.getConfigLevelEntityDataMap().putAll(config);
|
||||||
});
|
});
|
||||||
stream.close();
|
stream.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Grasscutter.getLogger().error("Error loading config level entity: no files found");
|
Grasscutter.getLogger().error("Error loading config level entity: no files found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameData.getConfigLevelEntityDataMap() == null || GameData.getConfigLevelEntityDataMap().isEmpty()) {
|
if (GameData.getConfigLevelEntityDataMap() == null
|
||||||
|
|| GameData.getConfigLevelEntityDataMap().isEmpty()) {
|
||||||
Grasscutter.getLogger().error("No config level entity loaded!");
|
Grasscutter.getLogger().error("No config level entity loaded!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -698,33 +701,52 @@ public final class ResourceLoader {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
var bindings = ScriptLoader.getEngine().createBindings();
|
var bindings = ScriptLoader.getEngine().createBindings();
|
||||||
var stream = Files.newDirectoryStream(getResourcePath("Scripts/Quest/Share/"), "Q*ShareConfig.lua");
|
var stream =
|
||||||
stream.forEach(path -> {
|
Files.newDirectoryStream(getResourcePath("Scripts/Quest/Share/"), "Q*ShareConfig.lua");
|
||||||
val matcher = pattern.matcher(path.getFileName().toString());
|
stream.forEach(
|
||||||
if (!matcher.find()) return;
|
path -> {
|
||||||
|
val matcher = pattern.matcher(path.getFileName().toString());
|
||||||
|
if (!matcher.find()) return;
|
||||||
|
|
||||||
var cs = ScriptLoader.getScript("Quest/Share/" + path.getFileName().toString());
|
var cs = ScriptLoader.getScript("Quest/Share/" + path.getFileName().toString());
|
||||||
if (cs == null) return;
|
if (cs == null) return;
|
||||||
|
|
||||||
try{
|
try {
|
||||||
cs.eval(bindings);
|
cs.eval(bindings);
|
||||||
// these are Map<String, class>
|
// these are Map<String, class>
|
||||||
var teleportDataMap = ScriptLoader.getSerializer().toMap(TeleportData.class, bindings.get("quest_data"));
|
var teleportDataMap =
|
||||||
var rewindDataMap = ScriptLoader.getSerializer().toMap(RewindData.class, bindings.get("rewind_data"));
|
ScriptLoader.getSerializer()
|
||||||
// convert them to Map<Integer, class> and cache
|
.toMap(TeleportData.class, bindings.get("quest_data"));
|
||||||
GameData.getTeleportDataMap().putAll(teleportDataMap.entrySet().stream().collect(Collectors.toMap(entry -> Integer.valueOf(entry.getKey()), Entry::getValue)));
|
var rewindDataMap =
|
||||||
GameData.getRewindDataMap().putAll(rewindDataMap.entrySet().stream().collect(Collectors.toMap(entry -> Integer.valueOf(entry.getKey()), Entry::getValue)));
|
ScriptLoader.getSerializer().toMap(RewindData.class, bindings.get("rewind_data"));
|
||||||
} catch (Throwable e){
|
// convert them to Map<Integer, class> and cache
|
||||||
Grasscutter.getLogger().error("Error while loading Quest Share Config: {}", path.getFileName().toString());
|
GameData.getTeleportDataMap()
|
||||||
}
|
.putAll(
|
||||||
});
|
teleportDataMap.entrySet().stream()
|
||||||
|
.collect(
|
||||||
|
Collectors.toMap(
|
||||||
|
entry -> Integer.valueOf(entry.getKey()), Entry::getValue)));
|
||||||
|
GameData.getRewindDataMap()
|
||||||
|
.putAll(
|
||||||
|
rewindDataMap.entrySet().stream()
|
||||||
|
.collect(
|
||||||
|
Collectors.toMap(
|
||||||
|
entry -> Integer.valueOf(entry.getKey()), Entry::getValue)));
|
||||||
|
} catch (Throwable e) {
|
||||||
|
Grasscutter.getLogger()
|
||||||
|
.error(
|
||||||
|
"Error while loading Quest Share Config: {}", path.getFileName().toString());
|
||||||
|
}
|
||||||
|
});
|
||||||
stream.close();
|
stream.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Grasscutter.getLogger().error("Error loading Quest Share Config: no files found");
|
Grasscutter.getLogger().error("Error loading Quest Share Config: no files found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (GameData.getTeleportDataMap() == null || GameData.getTeleportDataMap().isEmpty()
|
if (GameData.getTeleportDataMap() == null
|
||||||
|| GameData.getRewindDataMap() == null || GameData.getRewindDataMap().isEmpty()) {
|
|| GameData.getTeleportDataMap().isEmpty()
|
||||||
|
|| GameData.getRewindDataMap() == null
|
||||||
|
|| GameData.getRewindDataMap().isEmpty()) {
|
||||||
Grasscutter.getLogger().error("No Quest Share Config loaded!");
|
Grasscutter.getLogger().error("No Quest Share Config loaded!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -735,8 +757,9 @@ public final class ResourceLoader {
|
|||||||
val gadgetMap = GameData.getGadgetMappingMap();
|
val gadgetMap = GameData.getGadgetMappingMap();
|
||||||
try {
|
try {
|
||||||
JsonUtils.loadToList(getResourcePath("Server/GadgetMapping.json"), GadgetMapping.class)
|
JsonUtils.loadToList(getResourcePath("Server/GadgetMapping.json"), GadgetMapping.class)
|
||||||
.forEach(entry -> gadgetMap.put(entry.getGadgetId(), entry));
|
.forEach(entry -> gadgetMap.put(entry.getGadgetId(), entry));
|
||||||
} catch (IOException | NullPointerException ignored) {}
|
} catch (IOException | NullPointerException ignored) {
|
||||||
|
}
|
||||||
Grasscutter.getLogger().debug("Loaded {} gadget mappings.", gadgetMap.size());
|
Grasscutter.getLogger().debug("Loaded {} gadget mappings.", gadgetMap.size());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error("Unable to load gadget mappings.", e);
|
Grasscutter.getLogger().error("Unable to load gadget mappings.", e);
|
||||||
@ -747,8 +770,11 @@ public final class ResourceLoader {
|
|||||||
try {
|
try {
|
||||||
val gadgetMap = GameData.getActivityCondGroupMap();
|
val gadgetMap = GameData.getActivityCondGroupMap();
|
||||||
try {
|
try {
|
||||||
JsonUtils.loadToList(getResourcePath("Server/ActivityCondGroups.json"), ActivityCondGroup.class).forEach(entry -> gadgetMap.put(entry.getCondGroupId(), entry));
|
JsonUtils.loadToList(
|
||||||
} catch (IOException | NullPointerException ignored) {}
|
getResourcePath("Server/ActivityCondGroups.json"), ActivityCondGroup.class)
|
||||||
|
.forEach(entry -> gadgetMap.put(entry.getCondGroupId(), entry));
|
||||||
|
} catch (IOException | NullPointerException ignored) {
|
||||||
|
}
|
||||||
Grasscutter.getLogger().debug("Loaded {} ActivityCondGroups.", gadgetMap.size());
|
Grasscutter.getLogger().debug("Loaded {} ActivityCondGroups.", gadgetMap.size());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error("Unable to load ActivityCondGroups.", e);
|
Grasscutter.getLogger().error("Unable to load ActivityCondGroups.", e);
|
||||||
@ -760,40 +786,47 @@ public final class ResourceLoader {
|
|||||||
String pathName = "CustomResources/TrialAvatarExcels/";
|
String pathName = "CustomResources/TrialAvatarExcels/";
|
||||||
try {
|
try {
|
||||||
JsonUtils.loadToList(
|
JsonUtils.loadToList(
|
||||||
getResourcePath(pathName + "TrialAvatarActivityDataExcelConfigData.json"),
|
getResourcePath(pathName + "TrialAvatarActivityDataExcelConfigData.json"),
|
||||||
TrialAvatarActivityDataData.class).forEach(instance -> {
|
TrialAvatarActivityDataData.class)
|
||||||
instance.onLoad();
|
.forEach(
|
||||||
GameData.getTrialAvatarActivityDataCustomData()
|
instance -> {
|
||||||
.put(instance.getTrialAvatarIndexId(), instance);
|
instance.onLoad();
|
||||||
});
|
GameData.getTrialAvatarActivityDataCustomData()
|
||||||
} catch (IOException | NullPointerException ignored) {}
|
.put(instance.getTrialAvatarIndexId(), instance);
|
||||||
|
});
|
||||||
|
} catch (IOException | NullPointerException ignored) {
|
||||||
|
}
|
||||||
Grasscutter.getLogger().debug("Loaded trial activity custom data.");
|
Grasscutter.getLogger().debug("Loaded trial activity custom data.");
|
||||||
try {
|
try {
|
||||||
JsonUtils.loadToList(
|
JsonUtils.loadToList(
|
||||||
getResourcePath(pathName + "TrialAvatarActivityExcelConfigData.json"),
|
getResourcePath(pathName + "TrialAvatarActivityExcelConfigData.json"),
|
||||||
TrialAvatarActivityCustomData.class).forEach(instance -> {
|
TrialAvatarActivityCustomData.class)
|
||||||
instance.onLoad();
|
.forEach(
|
||||||
GameData.getTrialAvatarActivityCustomData()
|
instance -> {
|
||||||
.put(instance.getScheduleId(), instance);
|
instance.onLoad();
|
||||||
});
|
GameData.getTrialAvatarActivityCustomData()
|
||||||
} catch (IOException | NullPointerException ignored) {}
|
.put(instance.getScheduleId(), instance);
|
||||||
|
});
|
||||||
|
} catch (IOException | NullPointerException ignored) {
|
||||||
|
}
|
||||||
Grasscutter.getLogger().debug("Loaded trial activity schedule custom data.");
|
Grasscutter.getLogger().debug("Loaded trial activity schedule custom data.");
|
||||||
try {
|
try {
|
||||||
JsonUtils.loadToList(
|
JsonUtils.loadToList(
|
||||||
getResourcePath(pathName + "TrialAvatarData.json"),
|
getResourcePath(pathName + "TrialAvatarData.json"), TrialAvatarCustomData.class)
|
||||||
TrialAvatarCustomData.class).forEach(instance -> {
|
.forEach(
|
||||||
instance.onLoad();
|
instance -> {
|
||||||
GameData.getTrialAvatarCustomData()
|
instance.onLoad();
|
||||||
.put(instance.getTrialAvatarId(), instance);
|
GameData.getTrialAvatarCustomData().put(instance.getTrialAvatarId(), instance);
|
||||||
});
|
});
|
||||||
} catch (IOException | NullPointerException ignored) {}
|
} catch (IOException | NullPointerException ignored) {
|
||||||
|
}
|
||||||
Grasscutter.getLogger().debug("Loaded trial avatar custom data.");
|
Grasscutter.getLogger().debug("Loaded trial avatar custom data.");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error("Unable to load trial avatar custom data.", e);
|
Grasscutter.getLogger().error("Unable to load trial avatar custom data.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadGroupReplacements(){
|
private static void loadGroupReplacements() {
|
||||||
Bindings bindings = ScriptLoader.getEngine().createBindings();
|
Bindings bindings = ScriptLoader.getEngine().createBindings();
|
||||||
|
|
||||||
CompiledScript cs = ScriptLoader.getScript("Scene/groups_replacement.lua");
|
CompiledScript cs = ScriptLoader.getScript("Scene/groups_replacement.lua");
|
||||||
@ -802,21 +835,29 @@ public final class ResourceLoader {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try {
|
||||||
cs.eval(bindings);
|
cs.eval(bindings);
|
||||||
// these are Map<String, class>
|
// these are Map<String, class>
|
||||||
var replacementsMap = ScriptLoader.getSerializer().toMap(GroupReplacementData.class, bindings.get("replacements"));
|
var replacementsMap =
|
||||||
|
ScriptLoader.getSerializer()
|
||||||
|
.toMap(GroupReplacementData.class, bindings.get("replacements"));
|
||||||
// convert them to Map<Integer, class> and cache
|
// convert them to Map<Integer, class> and cache
|
||||||
GameData.getGroupReplacements().putAll(replacementsMap.entrySet().stream().collect(Collectors.toMap(entry -> Integer.valueOf(entry.getValue().getId()), Entry::getValue)));
|
GameData.getGroupReplacements()
|
||||||
|
.putAll(
|
||||||
|
replacementsMap.entrySet().stream()
|
||||||
|
.collect(
|
||||||
|
Collectors.toMap(
|
||||||
|
entry -> Integer.valueOf(entry.getValue().getId()), Entry::getValue)));
|
||||||
|
|
||||||
} catch (Throwable e){
|
} catch (Throwable e) {
|
||||||
Grasscutter.getLogger().error("Error while loading Group Replacements");
|
Grasscutter.getLogger().error("Error while loading Group Replacements");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameData.getGroupReplacements() == null || GameData.getGroupReplacements().isEmpty()) {
|
if (GameData.getGroupReplacements() == null || GameData.getGroupReplacements().isEmpty()) {
|
||||||
Grasscutter.getLogger().error("No Group Replacements loaded!");
|
Grasscutter.getLogger().error("No Group Replacements loaded!");
|
||||||
} else {
|
} else {
|
||||||
Grasscutter.getLogger().debug("Loaded {} group replacements.", GameData.getGroupReplacements().size());
|
Grasscutter.getLogger()
|
||||||
|
.debug("Loaded {} group replacements.", GameData.getGroupReplacements().size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,8 +5,9 @@ import lombok.Getter;
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class DropItemData {
|
public class DropItemData {
|
||||||
@SerializedName(value="itemId")
|
@SerializedName(value = "itemId")
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
private String countRange;
|
private String countRange;
|
||||||
private int weight;
|
private int weight;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import lombok.Getter;
|
|||||||
public class DropMaterialData extends GameResource {
|
public class DropMaterialData extends GameResource {
|
||||||
@Getter(onMethod_ = @Override)
|
@Getter(onMethod_ = @Override)
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
private boolean useOnGain;
|
private boolean useOnGain;
|
||||||
private boolean disableFirstGainHint;
|
private boolean disableFirstGainHint;
|
||||||
private boolean autoPick;
|
private boolean autoPick;
|
||||||
|
@ -4,15 +4,17 @@ import emu.grasscutter.data.GameResource;
|
|||||||
import emu.grasscutter.data.ResourceType;
|
import emu.grasscutter.data.ResourceType;
|
||||||
import emu.grasscutter.data.ResourceType.LoadPriority;
|
import emu.grasscutter.data.ResourceType.LoadPriority;
|
||||||
import emu.grasscutter.data.common.DropItemData;
|
import emu.grasscutter.data.common.DropItemData;
|
||||||
|
import java.util.List;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.List;
|
@ResourceType(
|
||||||
|
name = {"DropTableExcelConfigData.json", "DropSubTableExcelConfigData.json"},
|
||||||
@ResourceType(name ={"DropTableExcelConfigData.json","DropSubTableExcelConfigData.json"} , loadPriority = LoadPriority.HIGH)
|
loadPriority = LoadPriority.HIGH)
|
||||||
@Getter
|
@Getter
|
||||||
public class DropTableData extends GameResource {
|
public class DropTableData extends GameResource {
|
||||||
@Getter(onMethod_ = @Override)
|
@Getter(onMethod_ = @Override)
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
private int randomType;
|
private int randomType;
|
||||||
private int dropLevel;
|
private int dropLevel;
|
||||||
private List<DropItemData> dropVec;
|
private List<DropItemData> dropVec;
|
||||||
|
@ -5,10 +5,9 @@ import emu.grasscutter.data.GameResource;
|
|||||||
import emu.grasscutter.data.ResourceType;
|
import emu.grasscutter.data.ResourceType;
|
||||||
import emu.grasscutter.data.excels.RewardPreviewData;
|
import emu.grasscutter.data.excels.RewardPreviewData;
|
||||||
import emu.grasscutter.game.dungeons.enums.*;
|
import emu.grasscutter.game.dungeons.enums.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import emu.grasscutter.scripts.data.SceneMeta;
|
import emu.grasscutter.scripts.data.SceneMeta;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
|
import java.util.List;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@ResourceType(name = "DungeonExcelConfigData.json")
|
@ResourceType(name = "DungeonExcelConfigData.json")
|
||||||
|
@ -3,7 +3,6 @@ package emu.grasscutter.data.server;
|
|||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.utils.GridPosition;
|
import emu.grasscutter.utils.GridPosition;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -11,15 +10,11 @@ import java.util.Set;
|
|||||||
|
|
||||||
public class Grid {
|
public class Grid {
|
||||||
public Map<String, Set<Integer>> grid;
|
public Map<String, Set<Integer>> grid;
|
||||||
public Map<GridPosition, Set<Integer>> gridMap
|
public Map<GridPosition, Set<Integer>> gridMap = new LinkedHashMap<>();
|
||||||
= new LinkedHashMap<>();
|
|
||||||
|
|
||||||
/**
|
/** Loads the correct grid map. */
|
||||||
* Loads the correct grid map.
|
|
||||||
*/
|
|
||||||
public void load() {
|
public void load() {
|
||||||
this.grid.forEach((position, groups) ->
|
this.grid.forEach((position, groups) -> this.gridMap.put(new GridPosition(position), groups));
|
||||||
this.gridMap.put(new GridPosition(position), groups));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,7 +45,6 @@ import java.util.*;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@ -138,17 +137,17 @@ public class Avatar {
|
|||||||
|
|
||||||
// Combat properties
|
// Combat properties
|
||||||
Stream.of(FightProperty.values())
|
Stream.of(FightProperty.values())
|
||||||
.map(FightProperty::getId)
|
.map(FightProperty::getId)
|
||||||
.filter(id -> (id > 0) && (id < 3000))
|
.filter(id -> (id > 0) && (id < 3000))
|
||||||
.forEach(id -> this.setFightProperty(id, 0f));
|
.forEach(id -> this.setFightProperty(id, 0f));
|
||||||
|
|
||||||
this.setSkillDepotData(switch (this.getAvatarId()) {
|
this.setSkillDepotData(
|
||||||
case GameConstants.MAIN_CHARACTER_MALE ->
|
switch (this.getAvatarId()) {
|
||||||
GameData.getAvatarSkillDepotDataMap().get(501);
|
case GameConstants.MAIN_CHARACTER_MALE -> GameData.getAvatarSkillDepotDataMap().get(501);
|
||||||
case GameConstants.MAIN_CHARACTER_FEMALE ->
|
case GameConstants.MAIN_CHARACTER_FEMALE -> GameData.getAvatarSkillDepotDataMap()
|
||||||
GameData.getAvatarSkillDepotDataMap().get(701);
|
.get(701);
|
||||||
default -> data.getSkillDepot();
|
default -> data.getSkillDepot();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set stats
|
// Set stats
|
||||||
this.recalcStats();
|
this.recalcStats();
|
||||||
@ -180,10 +179,8 @@ public class Avatar {
|
|||||||
* @return True if the avatar is a main character.
|
* @return True if the avatar is a main character.
|
||||||
*/
|
*/
|
||||||
public boolean isMainCharacter() {
|
public boolean isMainCharacter() {
|
||||||
return List.of(
|
return List.of(GameConstants.MAIN_CHARACTER_MALE, GameConstants.MAIN_CHARACTER_FEMALE)
|
||||||
GameConstants.MAIN_CHARACTER_MALE,
|
.contains(this.getAvatarId());
|
||||||
GameConstants.MAIN_CHARACTER_FEMALE
|
|
||||||
).contains(this.getAvatarId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getPlayer() {
|
public Player getPlayer() {
|
||||||
@ -289,8 +286,8 @@ public class Avatar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the avatar's element to the target element.
|
* Changes the avatar's element to the target element. Only applies if the avatar has the element
|
||||||
* Only applies if the avatar has the element in its 'candSkillDepot's.
|
* in its 'candSkillDepot's.
|
||||||
*
|
*
|
||||||
* @param newElement The new element to change to.
|
* @param newElement The new element to change to.
|
||||||
* @return True if the element was changed, false otherwise.
|
* @return True if the element was changed, false otherwise.
|
||||||
@ -300,8 +297,8 @@ public class Avatar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the avatar's element to the target element.
|
* Changes the avatar's element to the target element. Only applies if the avatar has the element
|
||||||
* Only applies if the avatar has the element in its 'candSkillDepot's.
|
* in its 'candSkillDepot's.
|
||||||
*
|
*
|
||||||
* @param elementTypeToChange The new element to change to.
|
* @param elementTypeToChange The new element to change to.
|
||||||
* @param notify Whether to notify the player of the change.
|
* @param notify Whether to notify the player of the change.
|
||||||
|
@ -18,7 +18,6 @@ import emu.grasscutter.server.game.GameServer;
|
|||||||
import emu.grasscutter.server.packet.send.PacketDropHintNotify;
|
import emu.grasscutter.server.packet.send.PacketDropHintNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify;
|
import emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public final class DropSystem extends BaseGameSystem {
|
public final class DropSystem extends BaseGameSystem {
|
||||||
@ -47,7 +46,8 @@ public final class DropSystem extends BaseGameSystem {
|
|||||||
chestReward.get(i.getIndex()).add(i);
|
chestReward.get(i.getIndex()).add(i);
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
Grasscutter.getLogger().error("Unable to load chest drop data. Please place ChestDrop.json in data folder.");
|
Grasscutter.getLogger()
|
||||||
|
.error("Unable to load chest drop data. Please place ChestDrop.json in data folder.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -59,7 +59,8 @@ public final class DropSystem extends BaseGameSystem {
|
|||||||
monsterDrop.get(i.getIndex()).add(i);
|
monsterDrop.get(i.getIndex()).add(i);
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
Grasscutter.getLogger().error("Unable to load monster drop data. Please place MonsterDrop.json in data folder.");
|
Grasscutter.getLogger()
|
||||||
|
.error("Unable to load monster drop data. Please place MonsterDrop.json in data folder.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +98,8 @@ public final class DropSystem extends BaseGameSystem {
|
|||||||
List<GameItem> items = new ArrayList<>();
|
List<GameItem> items = new ArrayList<>();
|
||||||
processDrop(dropData, 1, items);
|
processDrop(dropData, 1, items);
|
||||||
if (dropData.isFallToGround()) {
|
if (dropData.isFallToGround()) {
|
||||||
dropItems(items, ActionReason.MonsterDie, monster, monster.getScene().getPlayers().get(0), true);
|
dropItems(
|
||||||
|
items, ActionReason.MonsterDie, monster, monster.getScene().getPlayers().get(0), true);
|
||||||
} else {
|
} else {
|
||||||
for (Player p : monster.getScene().getPlayers()) {
|
for (Player p : monster.getScene().getPlayers()) {
|
||||||
p.getInventory().addItems(items, ActionReason.MonsterDie);
|
p.getInventory().addItems(items, ActionReason.MonsterDie);
|
||||||
@ -137,8 +139,8 @@ public final class DropSystem extends BaseGameSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processDrop(DropTableData dropData, int count, List<GameItem> items) {
|
private void processDrop(DropTableData dropData, int count, List<GameItem> items) {
|
||||||
//TODO:Not clear on the meaning of some fields,like "dropLevel".Will ignore them.
|
// TODO:Not clear on the meaning of some fields,like "dropLevel".Will ignore them.
|
||||||
//TODO:solve drop limits,like everydayLimit.
|
// TODO:solve drop limits,like everydayLimit.
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
for (int i = 0; i < count; i++) processDrop(dropData, 1, items);
|
for (int i = 0; i < count; i++) processDrop(dropData, 1, items);
|
||||||
return;
|
return;
|
||||||
@ -158,7 +160,7 @@ public final class DropSystem extends BaseGameSystem {
|
|||||||
if (id == 0) continue;
|
if (id == 0) continue;
|
||||||
sum += i.getWeight();
|
sum += i.getWeight();
|
||||||
if (weight < sum) {
|
if (weight < sum) {
|
||||||
//win the item
|
// win the item
|
||||||
int amount = calculateDropAmount(i) * count;
|
int amount = calculateDropAmount(i) * count;
|
||||||
if (amount <= 0) break;
|
if (amount <= 0) break;
|
||||||
if (dropTable.containsKey(id)) {
|
if (dropTable.containsKey(id)) {
|
||||||
@ -220,17 +222,25 @@ public final class DropSystem extends BaseGameSystem {
|
|||||||
/**
|
/**
|
||||||
* @param share Whether other players in the scene could see the drop items.
|
* @param share Whether other players in the scene could see the drop items.
|
||||||
*/
|
*/
|
||||||
private void dropItem(GameItem item, ActionReason reason, Player player, GameEntity bornFrom, boolean share) {
|
private void dropItem(
|
||||||
|
GameItem item, ActionReason reason, Player player, GameEntity bornFrom, boolean share) {
|
||||||
DropMaterialData drop = GameData.getDropMaterialDataMap().get(item.getItemId());
|
DropMaterialData drop = GameData.getDropMaterialDataMap().get(item.getItemId());
|
||||||
if ((drop != null && drop.isAutoPick()) || (item.getItemData().getItemType() == ItemType.ITEM_VIRTUAL && item.getItemData().getGadgetId() == 0)) {
|
if ((drop != null && drop.isAutoPick())
|
||||||
|
|| (item.getItemData().getItemType() == ItemType.ITEM_VIRTUAL
|
||||||
|
&& item.getItemData().getGadgetId() == 0)) {
|
||||||
giveItem(item, reason, player, share);
|
giveItem(item, reason, player, share);
|
||||||
} else {
|
} else {
|
||||||
//TODO:solve share problem
|
// TODO:solve share problem
|
||||||
player.getScene().addDropEntity(item, bornFrom, player, share);
|
player.getScene().addDropEntity(item, bornFrom, player, share);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dropItems(List<GameItem> items, ActionReason reason, GameEntity bornFrom, Player player, boolean share) {
|
private void dropItems(
|
||||||
|
List<GameItem> items,
|
||||||
|
ActionReason reason,
|
||||||
|
GameEntity bornFrom,
|
||||||
|
Player player,
|
||||||
|
boolean share) {
|
||||||
for (var i : items) {
|
for (var i : items) {
|
||||||
dropItem(i, reason, player, bornFrom, share);
|
dropItem(i, reason, player, bornFrom, share);
|
||||||
}
|
}
|
||||||
@ -249,7 +259,7 @@ public final class DropSystem extends BaseGameSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void giveItems(List<GameItem> items, ActionReason reason, Player player, boolean share) {
|
private void giveItems(List<GameItem> items, ActionReason reason, Player player, boolean share) {
|
||||||
//don't know whether we need PacketDropHintNotify.
|
// don't know whether we need PacketDropHintNotify.
|
||||||
if (share) {
|
if (share) {
|
||||||
for (var p : player.getScene().getPlayers()) {
|
for (var p : player.getScene().getPlayers()) {
|
||||||
p.getInventory().addItems(items, reason);
|
p.getInventory().addItems(items, reason);
|
||||||
@ -260,5 +270,4 @@ public final class DropSystem extends BaseGameSystem {
|
|||||||
player.sendPacket(new PacketDropHintNotify(items, player.getPosition().toProto()));
|
player.sendPacket(new PacketDropHintNotify(items, player.getPosition().toProto()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ import emu.grasscutter.utils.Position;
|
|||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class DropSystemLegacy extends BaseGameSystem {
|
public class DropSystemLegacy extends BaseGameSystem {
|
||||||
@ -49,20 +48,27 @@ public class DropSystemLegacy extends BaseGameSystem {
|
|||||||
Grasscutter.getLogger().error("Unable to load drop data.", e);
|
Grasscutter.getLogger().error("Unable to load drop data.", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void addDropEntity(DropData dd, Scene dropScene, ItemData itemData, Position pos, int num, Player target) {
|
|
||||||
if (!dd.isGive() && (itemData.getItemType() != ItemType.ITEM_VIRTUAL || itemData.getGadgetId() != 0)) {
|
private void addDropEntity(
|
||||||
|
DropData dd, Scene dropScene, ItemData itemData, Position pos, int num, Player target) {
|
||||||
|
if (!dd.isGive()
|
||||||
|
&& (itemData.getItemType() != ItemType.ITEM_VIRTUAL || itemData.getGadgetId() != 0)) {
|
||||||
EntityItem entity = new EntityItem(dropScene, target, itemData, pos, num, dd.isShare());
|
EntityItem entity = new EntityItem(dropScene, target, itemData, pos, num, dd.isShare());
|
||||||
if (!dd.isShare())
|
if (!dd.isShare()) dropScene.addEntityToSingleClient(target, entity);
|
||||||
dropScene.addEntityToSingleClient(target, entity);
|
else dropScene.addEntity(entity);
|
||||||
else
|
|
||||||
dropScene.addEntity(entity);
|
|
||||||
} else {
|
} else {
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
target.getInventory().addItem(new GameItem(itemData, num), ActionReason.SubfieldDrop, true);
|
target.getInventory().addItem(new GameItem(itemData, num), ActionReason.SubfieldDrop, true);
|
||||||
} else {
|
} else {
|
||||||
// target is null if items will be added are shared. no one could pick it up because of the combination(give + shared)
|
// target is null if items will be added are shared. no one could pick it up because of the
|
||||||
|
// combination(give + shared)
|
||||||
// so it will be sent to all players' inventories directly.
|
// so it will be sent to all players' inventories directly.
|
||||||
dropScene.getPlayers().forEach(x -> x.getInventory().addItem(new GameItem(itemData, num), ActionReason.SubfieldDrop, true));
|
dropScene
|
||||||
|
.getPlayers()
|
||||||
|
.forEach(
|
||||||
|
x ->
|
||||||
|
x.getInventory()
|
||||||
|
.addItem(new GameItem(itemData, num), ActionReason.SubfieldDrop, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,8 +99,7 @@ public class DropSystemLegacy extends BaseGameSystem {
|
|||||||
int id = em.getMonsterData().getId();
|
int id = em.getMonsterData().getId();
|
||||||
if (getDropData().containsKey(id)) {
|
if (getDropData().containsKey(id)) {
|
||||||
for (DropData dd : getDropData().get(id)) {
|
for (DropData dd : getDropData().get(id)) {
|
||||||
if (dd.isShare())
|
if (dd.isShare()) processDrop(dd, em, null);
|
||||||
processDrop(dd, em, null);
|
|
||||||
else {
|
else {
|
||||||
for (Player gp : em.getScene().getPlayers()) {
|
for (Player gp : em.getScene().getPlayers()) {
|
||||||
processDrop(dd, em, gp);
|
processDrop(dd, em, gp);
|
||||||
|
@ -28,31 +28,46 @@ public class GadgetChest extends GadgetContent {
|
|||||||
* @return Whether we should remove the gadget.
|
* @return Whether we should remove the gadget.
|
||||||
*/
|
*/
|
||||||
public boolean onInteract(Player player, GadgetInteractReq req) {
|
public boolean onInteract(Player player, GadgetInteractReq req) {
|
||||||
//If bigWorldScript enabled,use new drop system.
|
// If bigWorldScript enabled,use new drop system.
|
||||||
if (Grasscutter.getConfig().server.game.enableScriptInBigWorld) {
|
if (Grasscutter.getConfig().server.game.enableScriptInBigWorld) {
|
||||||
SceneGadget chest = getGadget().getMetaGadget();
|
SceneGadget chest = getGadget().getMetaGadget();
|
||||||
DropSystem dropSystem = player.getServer().getDropSystem();
|
DropSystem dropSystem = player.getServer().getDropSystem();
|
||||||
if (chest.boss_chest != null && chest.drop_tag != null) {
|
if (chest.boss_chest != null && chest.drop_tag != null) {
|
||||||
//Boss chest drop
|
// Boss chest drop
|
||||||
//TODO:check for blossom chests
|
// TODO:check for blossom chests
|
||||||
if (req.getOpType() == InterOpType.INTER_OP_TYPE_START) {
|
if (req.getOpType() == InterOpType.INTER_OP_TYPE_START) {
|
||||||
//Two steps
|
// Two steps
|
||||||
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_START));
|
player.sendPacket(
|
||||||
|
new PacketGadgetInteractRsp(
|
||||||
|
getGadget(),
|
||||||
|
InteractType.INTERACT_TYPE_OPEN_CHEST,
|
||||||
|
InterOpType.INTER_OP_TYPE_START));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
//TODO:check for take_num.(some boss rewards can only be claimed once a week.). Handle boss respawn.
|
// TODO:check for take_num.(some boss rewards can only be claimed once a week.). Handle boss
|
||||||
//TODO:should return Retcode.RET_RESIN_NOT_ENOUGH ?
|
// respawn.
|
||||||
if (player.getResinManager().useResin(chest.boss_chest.resin) && dropSystem.handleBossChestDrop(chest.drop_tag, player)) {
|
// TODO:should return Retcode.RET_RESIN_NOT_ENOUGH ?
|
||||||
//Is it correct?
|
if (player.getResinManager().useResin(chest.boss_chest.resin)
|
||||||
player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_WORLD_BOSS_REWARD, chest.boss_chest.monster_config_id, 1);
|
&& dropSystem.handleBossChestDrop(chest.drop_tag, player)) {
|
||||||
|
// Is it correct?
|
||||||
|
player
|
||||||
|
.getBattlePassManager()
|
||||||
|
.triggerMission(
|
||||||
|
WatcherTriggerType.TRIGGER_WORLD_BOSS_REWARD,
|
||||||
|
chest.boss_chest.monster_config_id,
|
||||||
|
1);
|
||||||
getGadget().updateState(ScriptGadgetState.ChestOpened);
|
getGadget().updateState(ScriptGadgetState.ChestOpened);
|
||||||
player.sendPacket(new PacketGadgetInteractRsp(this.getGadget(), InteractTypeOuterClass.InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_FINISH));
|
player.sendPacket(
|
||||||
|
new PacketGadgetInteractRsp(
|
||||||
|
this.getGadget(),
|
||||||
|
InteractTypeOuterClass.InteractType.INTERACT_TYPE_OPEN_CHEST,
|
||||||
|
InterOpType.INTER_OP_TYPE_FINISH));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//if failed,fallback to legacy drop system.
|
// if failed,fallback to legacy drop system.
|
||||||
} else {
|
} else {
|
||||||
//Normal chest drop
|
// Normal chest drop
|
||||||
//only the owner of the world can open chests.
|
// only the owner of the world can open chests.
|
||||||
if (player != player.getWorld().getHost()) return false;
|
if (player != player.getWorld().getHost()) return false;
|
||||||
boolean status = false;
|
boolean status = false;
|
||||||
if (chest.drop_tag != null) {
|
if (chest.drop_tag != null) {
|
||||||
@ -62,31 +77,56 @@ public class GadgetChest extends GadgetContent {
|
|||||||
}
|
}
|
||||||
if (status) {
|
if (status) {
|
||||||
getGadget().updateState(ScriptGadgetState.ChestOpened);
|
getGadget().updateState(ScriptGadgetState.ChestOpened);
|
||||||
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_FINISH));
|
player.sendPacket(
|
||||||
player.sendPacket(new PacketWorldChestOpenNotify(getGadget().getGroupId(), player.getSceneId(), chest.config_id));
|
new PacketGadgetInteractRsp(
|
||||||
|
getGadget(),
|
||||||
|
InteractType.INTERACT_TYPE_OPEN_CHEST,
|
||||||
|
InterOpType.INTER_OP_TYPE_FINISH));
|
||||||
|
player.sendPacket(
|
||||||
|
new PacketWorldChestOpenNotify(
|
||||||
|
getGadget().getGroupId(), player.getSceneId(), chest.config_id));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//if failed,fallback to legacy drop system.
|
// if failed,fallback to legacy drop system.
|
||||||
}
|
}
|
||||||
Grasscutter.getLogger().warn("Can not solve chest drop: chest_drop_id = {} , drop_tag = {}.Fallback to legacy drop system.", chest.chest_drop_id, chest.drop_tag);
|
Grasscutter.getLogger()
|
||||||
|
.warn(
|
||||||
|
"Can not solve chest drop: chest_drop_id = {} , drop_tag = {}.Fallback to legacy drop system.",
|
||||||
|
chest.chest_drop_id,
|
||||||
|
chest.drop_tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Legacy chest drop system
|
// Legacy chest drop system
|
||||||
var chestInteractHandlerMap = getGadget().getScene().getWorld().getServer().getWorldDataSystem().getChestInteractHandlerMap();
|
var chestInteractHandlerMap =
|
||||||
|
getGadget()
|
||||||
|
.getScene()
|
||||||
|
.getWorld()
|
||||||
|
.getServer()
|
||||||
|
.getWorldDataSystem()
|
||||||
|
.getChestInteractHandlerMap();
|
||||||
var handler = chestInteractHandlerMap.get(getGadget().getGadgetData().getJsonName());
|
var handler = chestInteractHandlerMap.get(getGadget().getGadgetData().getJsonName());
|
||||||
if (handler == null) {
|
if (handler == null) {
|
||||||
Grasscutter.getLogger().warn("Could not found the handler of this type of Chests {}", getGadget().getGadgetData().getJsonName());
|
Grasscutter.getLogger()
|
||||||
|
.warn(
|
||||||
|
"Could not found the handler of this type of Chests {}",
|
||||||
|
getGadget().getGadgetData().getJsonName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.getOpType() == InterOpType.INTER_OP_TYPE_START && handler.isTwoStep()) {
|
if (req.getOpType() == InterOpType.INTER_OP_TYPE_START && handler.isTwoStep()) {
|
||||||
player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_START));
|
player.sendPacket(
|
||||||
|
new PacketGadgetInteractRsp(
|
||||||
|
getGadget(), InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_START));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
boolean success;
|
boolean success;
|
||||||
if (handler instanceof BossChestInteractHandler bossChestInteractHandler) {
|
if (handler instanceof BossChestInteractHandler bossChestInteractHandler) {
|
||||||
success = bossChestInteractHandler.onInteract(this, player,
|
success =
|
||||||
req.getResinCostType() == ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE);
|
bossChestInteractHandler.onInteract(
|
||||||
|
this,
|
||||||
|
player,
|
||||||
|
req.getResinCostType()
|
||||||
|
== ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE);
|
||||||
} else {
|
} else {
|
||||||
success = handler.onInteract(this, player);
|
success = handler.onInteract(this, player);
|
||||||
}
|
}
|
||||||
@ -95,7 +135,11 @@ public class GadgetChest extends GadgetContent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getGadget().updateState(ScriptGadgetState.ChestOpened);
|
getGadget().updateState(ScriptGadgetState.ChestOpened);
|
||||||
player.sendPacket(new PacketGadgetInteractRsp(this.getGadget(), InteractTypeOuterClass.InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_FINISH));
|
player.sendPacket(
|
||||||
|
new PacketGadgetInteractRsp(
|
||||||
|
this.getGadget(),
|
||||||
|
InteractTypeOuterClass.InteractType.INTERACT_TYPE_OPEN_CHEST,
|
||||||
|
InterOpType.INTER_OP_TYPE_FINISH));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -110,13 +154,13 @@ public class GadgetChest extends GadgetContent {
|
|||||||
if (bossChest != null) {
|
if (bossChest != null) {
|
||||||
var players = getGadget().getScene().getPlayers().stream().map(Player::getUid).toList();
|
var players = getGadget().getScene().getPlayers().stream().map(Player::getUid).toList();
|
||||||
|
|
||||||
gadgetInfo.setBossChest(BossChestInfo.newBuilder()
|
gadgetInfo.setBossChest(
|
||||||
.setMonsterConfigId(bossChest.monster_config_id)
|
BossChestInfo.newBuilder()
|
||||||
.setResin(bossChest.resin)
|
.setMonsterConfigId(bossChest.monster_config_id)
|
||||||
.addAllQualifyUidList(players)
|
.setResin(bossChest.resin)
|
||||||
.addAllRemainUidList(players)
|
.addAllQualifyUidList(players)
|
||||||
.build());
|
.addAllRemainUidList(players)
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package emu.grasscutter.game.managers;
|
package emu.grasscutter.game.managers;
|
||||||
|
|
||||||
|
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||||
|
|
||||||
import emu.grasscutter.game.inventory.GameItem;
|
import emu.grasscutter.game.inventory.GameItem;
|
||||||
import emu.grasscutter.game.player.BasePlayerManager;
|
import emu.grasscutter.game.player.BasePlayerManager;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
@ -11,12 +13,10 @@ import emu.grasscutter.server.packet.send.PacketItemAddHintNotify;
|
|||||||
import emu.grasscutter.server.packet.send.PacketResinChangeNotify;
|
import emu.grasscutter.server.packet.send.PacketResinChangeNotify;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
|
||||||
|
|
||||||
public class ResinManager extends BasePlayerManager {
|
public class ResinManager extends BasePlayerManager {
|
||||||
public static final int MAX_RESIN_BUYING_COUNT = 6;
|
public static final int MAX_RESIN_BUYING_COUNT = 6;
|
||||||
public static final int AMOUNT_TO_ADD = 60;
|
public static final int AMOUNT_TO_ADD = 60;
|
||||||
public static final int[] HCOIN_NUM_TO_BUY_RESIN = new int[]{50, 100, 100, 150, 200, 200};
|
public static final int[] HCOIN_NUM_TO_BUY_RESIN = new int[] {50, 100, 100, 150, 200, 200};
|
||||||
|
|
||||||
public ResinManager(Player player) {
|
public ResinManager(Player player) {
|
||||||
super(player);
|
super(player);
|
||||||
@ -53,7 +53,10 @@ public class ResinManager extends BasePlayerManager {
|
|||||||
this.player.sendPacket(new PacketResinChangeNotify(this.player));
|
this.player.sendPacket(new PacketResinChangeNotify(this.player));
|
||||||
|
|
||||||
// Battle Pass trigger
|
// Battle Pass trigger
|
||||||
this.player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, 106, amount); // Resin item id = 106
|
this.player
|
||||||
|
.getBattlePassManager()
|
||||||
|
.triggerMission(
|
||||||
|
WatcherTriggerType.TRIGGER_COST_MATERIAL, 106, amount); // Resin item id = 106
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -110,7 +113,11 @@ public class ResinManager extends BasePlayerManager {
|
|||||||
// Calculate how much resin we need to refill and update player.
|
// Calculate how much resin we need to refill and update player.
|
||||||
// Note that this can be more than one in case the player
|
// Note that this can be more than one in case the player
|
||||||
// logged off with uncapped resin and is now logging in again.
|
// logged off with uncapped resin and is now logging in again.
|
||||||
int recharge = 1 + (int)((currentTime - this.player.getNextResinRefresh()) / GAME_OPTIONS.resinOptions.rechargeTime);
|
int recharge =
|
||||||
|
1
|
||||||
|
+ (int)
|
||||||
|
((currentTime - this.player.getNextResinRefresh())
|
||||||
|
/ GAME_OPTIONS.resinOptions.rechargeTime);
|
||||||
int newResin = Math.min(GAME_OPTIONS.resinOptions.cap, currentResin + recharge);
|
int newResin = Math.min(GAME_OPTIONS.resinOptions.cap, currentResin + recharge);
|
||||||
int resinChange = newResin - currentResin;
|
int resinChange = newResin - currentResin;
|
||||||
|
|
||||||
@ -120,9 +127,9 @@ public class ResinManager extends BasePlayerManager {
|
|||||||
// Set to zero to disable recharge (because on/over cap.)
|
// Set to zero to disable recharge (because on/over cap.)
|
||||||
if (newResin >= GAME_OPTIONS.resinOptions.cap) {
|
if (newResin >= GAME_OPTIONS.resinOptions.cap) {
|
||||||
this.player.setNextResinRefresh(0);
|
this.player.setNextResinRefresh(0);
|
||||||
}
|
} else {
|
||||||
else {
|
int nextRecharge =
|
||||||
int nextRecharge = this.player.getNextResinRefresh() + resinChange * GAME_OPTIONS.resinOptions.rechargeTime;
|
this.player.getNextResinRefresh() + resinChange * GAME_OPTIONS.resinOptions.rechargeTime;
|
||||||
this.player.setNextResinRefresh(nextRecharge);
|
this.player.setNextResinRefresh(nextRecharge);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +165,10 @@ public class ResinManager extends BasePlayerManager {
|
|||||||
return RetcodeOuterClass.Retcode.RET_RESIN_BOUGHT_COUNT_EXCEEDED_VALUE;
|
return RetcodeOuterClass.Retcode.RET_RESIN_BOUGHT_COUNT_EXCEEDED_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
var res = this.player.getInventory().payItem(201, HCOIN_NUM_TO_BUY_RESIN[this.player.getResinBuyCount()]);
|
var res =
|
||||||
|
this.player
|
||||||
|
.getInventory()
|
||||||
|
.payItem(201, HCOIN_NUM_TO_BUY_RESIN[this.player.getResinBuyCount()]);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
return RetcodeOuterClass.Retcode.RET_HCOIN_NOT_ENOUGH_VALUE;
|
return RetcodeOuterClass.Retcode.RET_HCOIN_NOT_ENOUGH_VALUE;
|
||||||
}
|
}
|
||||||
@ -166,7 +176,8 @@ public class ResinManager extends BasePlayerManager {
|
|||||||
this.player.setResinBuyCount(this.player.getResinBuyCount() + 1);
|
this.player.setResinBuyCount(this.player.getResinBuyCount() + 1);
|
||||||
this.player.setProperty(PlayerProperty.PROP_PLAYER_WAIT_SUB_HCOIN, 0);
|
this.player.setProperty(PlayerProperty.PROP_PLAYER_WAIT_SUB_HCOIN, 0);
|
||||||
this.addResin(AMOUNT_TO_ADD);
|
this.addResin(AMOUNT_TO_ADD);
|
||||||
this.player.sendPacket(new PacketItemAddHintNotify(new GameItem(106, AMOUNT_TO_ADD), ActionReason.BuyResin));
|
this.player.sendPacket(
|
||||||
|
new PacketItemAddHintNotify(new GameItem(106, AMOUNT_TO_ADD), ActionReason.BuyResin));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,15 @@ public class ItemUseAddItem extends ItemUseInt {
|
|||||||
super(useParam);
|
super(useParam);
|
||||||
try {
|
try {
|
||||||
this.count = Integer.parseInt(useParam[1]);
|
this.count = Integer.parseInt(useParam[1]);
|
||||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
|
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean useItem(UseItemParams params) {
|
public boolean useItem(UseItemParams params) {
|
||||||
return params.player.getInventory().addItem(this.i, this.count * params.count, ActionReason.PlayerUseItem);
|
return params
|
||||||
|
.player
|
||||||
|
.getInventory()
|
||||||
|
.addItem(this.i, this.count * params.count, ActionReason.PlayerUseItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,7 +303,15 @@ public class GameMainQuest {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasTeleportPostion(int subId, List<Position> posAndRot) {
|
/**
|
||||||
|
* Checks if the quest has a teleport position. Returns true if it does & adds the target position
|
||||||
|
* & rotation to the list.
|
||||||
|
*
|
||||||
|
* @param subId The sub-quest ID.
|
||||||
|
* @param posAndRot A list which will contain the position & rotation if the quest has a teleport.
|
||||||
|
* @return True if the quest has a teleport position. False otherwise.
|
||||||
|
*/
|
||||||
|
public boolean hasTeleportPosition(int subId, List<Position> posAndRot) {
|
||||||
TeleportData questTransmit = GameData.getTeleportDataMap().get(subId);
|
TeleportData questTransmit = GameData.getTeleportDataMap().get(subId);
|
||||||
if (questTransmit == null) return false;
|
if (questTransmit == null) return false;
|
||||||
|
|
||||||
@ -338,7 +346,7 @@ public class GameMainQuest {
|
|||||||
1,
|
1,
|
||||||
new Position(
|
new Position(
|
||||||
transmitPosRot.get(0), transmitPosRot.get(1), transmitPosRot.get(2))); // rotation
|
transmitPosRot.get(0), transmitPosRot.get(1), transmitPosRot.get(2))); // rotation
|
||||||
Grasscutter.getLogger().info("Succesfully loaded teleport data for subQuest {}", subId);
|
Grasscutter.getLogger().debug("Successfully loaded teleport data for sub-quest {}.", subId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,12 +20,11 @@ import emu.grasscutter.server.packet.send.PacketChapterStateNotify;
|
|||||||
import emu.grasscutter.server.packet.send.PacketDelQuestNotify;
|
import emu.grasscutter.server.packet.send.PacketDelQuestNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify;
|
import emu.grasscutter.server.packet.send.PacketQuestListUpdateNotify;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntIntImmutablePair;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.script.Bindings;
|
import javax.script.Bindings;
|
||||||
|
|
||||||
import it.unimi.dsi.fastutil.ints.IntIntImmutablePair;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
@ -227,8 +226,9 @@ public class GameQuest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Give items for completing the quest.
|
// Give items for completing the quest.
|
||||||
this.getQuestData().getGainItems().forEach(item ->
|
this.getQuestData()
|
||||||
this.getOwner().getInventory().addItem(item, ActionReason.QuestItem));
|
.getGainItems()
|
||||||
|
.forEach(item -> this.getOwner().getInventory().addItem(item, ActionReason.QuestItem));
|
||||||
|
|
||||||
this.save();
|
this.save();
|
||||||
Grasscutter.getLogger().debug("Quest {} was completed.", subQuestId);
|
Grasscutter.getLogger().debug("Quest {} was completed.", subQuestId);
|
||||||
@ -283,23 +283,26 @@ public class GameQuest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A list of dungeon IDs associated with the quest's 'QUEST_CONTENT_ENTER_DUNGEON' triggers.
|
* @return A list of dungeon IDs associated with the quest's 'QUEST_CONTENT_ENTER_DUNGEON'
|
||||||
* The first element of the pair is the dungeon ID.
|
* triggers. The first element of the pair is the dungeon ID. The second element of the pair
|
||||||
* The second element of the pair is the dungeon's scene point.
|
* is the dungeon's scene point.
|
||||||
*/
|
*/
|
||||||
public List<IntIntImmutablePair> getDungeonIds() {
|
public List<IntIntImmutablePair> getDungeonIds() {
|
||||||
var conditions = this.getQuestData().getFinishCond().stream()
|
var conditions =
|
||||||
.filter(cond -> cond.getType() == QuestContent.QUEST_CONTENT_ENTER_DUNGEON)
|
this.getQuestData().getFinishCond().stream()
|
||||||
.toList();
|
.filter(cond -> cond.getType() == QuestContent.QUEST_CONTENT_ENTER_DUNGEON)
|
||||||
|
.toList();
|
||||||
|
|
||||||
return conditions.stream()
|
return conditions.stream()
|
||||||
.map(condition -> {
|
.map(
|
||||||
var params = condition.getParam();
|
condition -> {
|
||||||
// The first parameter is the ID of the dungeon.
|
var params = condition.getParam();
|
||||||
// The second parameter is the dungeon entry's scene point.
|
// The first parameter is the ID of the dungeon.
|
||||||
// ex. [1, 1] = dungeon ID 1, scene point 1 or 'KaeyaDungeon'.
|
// The second parameter is the dungeon entry's scene point.
|
||||||
return new IntIntImmutablePair(params[0], params[1]);
|
// ex. [1, 1] = dungeon ID 1, scene point 1 or 'KaeyaDungeon'.
|
||||||
}).toList();
|
return new IntIntImmutablePair(params[0], params[1]);
|
||||||
|
})
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
|
@ -52,7 +52,9 @@ public class ExecNotifyGroupLua extends QuestExecHandler {
|
|||||||
quest.getState() == QuestState.QUEST_STATE_FINISHED
|
quest.getState() == QuestState.QUEST_STATE_FINISHED
|
||||||
? EventType.EVENT_QUEST_FINISH
|
? EventType.EVENT_QUEST_FINISH
|
||||||
: EventType.EVENT_QUEST_START;
|
: EventType.EVENT_QUEST_START;
|
||||||
scriptManager.callEvent(new ScriptArgs(groupId, eventType, quest.getSubQuestId()).setEventSource(String.valueOf(quest.getSubQuestId())));
|
scriptManager.callEvent(
|
||||||
|
new ScriptArgs(groupId, eventType, quest.getSubQuestId())
|
||||||
|
.setEventSource(String.valueOf(quest.getSubQuestId())));
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -40,17 +40,11 @@ import emu.grasscutter.server.packet.send.*;
|
|||||||
import emu.grasscutter.utils.KahnsSort;
|
import emu.grasscutter.utils.KahnsSort;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import lombok.val;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
@ -311,8 +305,7 @@ public final class Scene {
|
|||||||
// TODO:optimize EntityItem.java. Maybe we should make other players can't see
|
// TODO:optimize EntityItem.java. Maybe we should make other players can't see
|
||||||
// the ItemEntity.
|
// the ItemEntity.
|
||||||
ItemData itemData = GameData.getItemDataMap().get(item.getItemId());
|
ItemData itemData = GameData.getItemDataMap().get(item.getItemId());
|
||||||
if (itemData == null)
|
if (itemData == null) return;
|
||||||
return;
|
|
||||||
if (itemData.isEquip()) {
|
if (itemData.isEquip()) {
|
||||||
float range = (1.5f + (.05f * item.getCount()));
|
float range = (1.5f + (.05f * item.getCount()));
|
||||||
for (int j = 0; j < item.getCount(); j++) {
|
for (int j = 0; j < item.getCount(); j++) {
|
||||||
@ -321,11 +314,16 @@ public final class Scene {
|
|||||||
addEntity(entity);
|
addEntity(entity);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
EntityItem entity = new EntityItem(this, player, itemData, bornForm.getPosition().clone().addY(0.5f),
|
EntityItem entity =
|
||||||
item.getCount(), share);
|
new EntityItem(
|
||||||
|
this,
|
||||||
|
player,
|
||||||
|
itemData,
|
||||||
|
bornForm.getPosition().clone().addY(0.5f),
|
||||||
|
item.getCount(),
|
||||||
|
share);
|
||||||
addEntity(entity);
|
addEntity(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addEntities(Collection<? extends GameEntity> entities) {
|
public void addEntities(Collection<? extends GameEntity> entities) {
|
||||||
@ -333,7 +331,7 @@ public final class Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void addEntities(
|
public synchronized void addEntities(
|
||||||
Collection<? extends GameEntity> entities, VisionType visionType) {
|
Collection<? extends GameEntity> entities, VisionType visionType) {
|
||||||
if (entities == null || entities.isEmpty()) {
|
if (entities == null || entities.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -448,8 +446,13 @@ public final class Scene {
|
|||||||
// Reward drop
|
// Reward drop
|
||||||
var world = this.getWorld();
|
var world = this.getWorld();
|
||||||
if (target instanceof EntityMonster monster && this.getSceneType() != SceneType.SCENE_DUNGEON) {
|
if (target instanceof EntityMonster monster && this.getSceneType() != SceneType.SCENE_DUNGEON) {
|
||||||
if (monster.getMetaMonster() != null && !world.getServer().getDropSystem().handleMonsterDrop(monster)) {
|
if (monster.getMetaMonster() != null
|
||||||
Grasscutter.getLogger().debug("Can not solve monster drop: drop_id = {}, drop_tag = {}. Falling back to legacy drop system.", monster.getMetaMonster().drop_id, monster.getMetaMonster().drop_tag);
|
&& !world.getServer().getDropSystem().handleMonsterDrop(monster)) {
|
||||||
|
Grasscutter.getLogger()
|
||||||
|
.debug(
|
||||||
|
"Can not solve monster drop: drop_id = {}, drop_tag = {}. Falling back to legacy drop system.",
|
||||||
|
monster.getMetaMonster().drop_id,
|
||||||
|
monster.getMetaMonster().drop_tag);
|
||||||
getWorld().getServer().getDropSystemLegacy().callDrop(monster);
|
getWorld().getServer().getDropSystemLegacy().callDrop(monster);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,10 +279,10 @@ public class World implements Iterable<Player> {
|
|||||||
|
|
||||||
val sceneData = GameData.getSceneDataMap().get(sceneId);
|
val sceneData = GameData.getSceneDataMap().get(sceneId);
|
||||||
if (dungeonData != null) {
|
if (dungeonData != null) {
|
||||||
teleportProps.teleportTo(dungeonData.getStartPosition())
|
teleportProps
|
||||||
.teleportRot(dungeonData.getStartRotation());
|
.teleportTo(dungeonData.getStartPosition())
|
||||||
teleportProps.enterType(EnterType.ENTER_TYPE_DUNGEON)
|
.teleportRot(dungeonData.getStartRotation());
|
||||||
.enterReason(EnterReason.DungeonEnter);
|
teleportProps.enterType(EnterType.ENTER_TYPE_DUNGEON).enterReason(EnterReason.DungeonEnter);
|
||||||
} else if (player.getSceneId() == sceneId) {
|
} else if (player.getSceneId() == sceneId) {
|
||||||
teleportProps.enterType(EnterType.ENTER_TYPE_GOTO);
|
teleportProps.enterType(EnterType.ENTER_TYPE_GOTO);
|
||||||
} else if (sceneData != null && sceneData.getSceneType() == SceneType.SCENE_HOME_WORLD) {
|
} else if (sceneData != null && sceneData.getSceneType() == SceneType.SCENE_HOME_WORLD) {
|
||||||
|
@ -8,8 +8,6 @@ import java.io.IOException;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import javax.script.Bindings;
|
|
||||||
import javax.script.CompiledScript;
|
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
public class EntityControllerScriptManager {
|
public class EntityControllerScriptManager {
|
||||||
@ -21,23 +19,23 @@ public class EntityControllerScriptManager {
|
|||||||
|
|
||||||
private static void cacheGadgetControllers() {
|
private static void cacheGadgetControllers() {
|
||||||
try (var stream = Files.newDirectoryStream(getScriptPath("Gadget/"), "*.lua")) {
|
try (var stream = Files.newDirectoryStream(getScriptPath("Gadget/"), "*.lua")) {
|
||||||
stream.forEach(path -> {
|
stream.forEach(
|
||||||
val fileName = path.getFileName().toString();
|
path -> {
|
||||||
if (!fileName.endsWith(".lua")) return;
|
val fileName = path.getFileName().toString();
|
||||||
|
if (!fileName.endsWith(".lua")) return;
|
||||||
|
|
||||||
val controllerName = fileName.substring(0, fileName.length() - 4);
|
val controllerName = fileName.substring(0, fileName.length() - 4);
|
||||||
var cs = ScriptLoader.getScript("Gadget/" + fileName);
|
var cs = ScriptLoader.getScript("Gadget/" + fileName);
|
||||||
var bindings = ScriptLoader.getEngine().createBindings();
|
var bindings = ScriptLoader.getEngine().createBindings();
|
||||||
if (cs == null) return;
|
if (cs == null) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cs.eval(bindings);
|
cs.eval(bindings);
|
||||||
gadgetController.put(controllerName, new EntityController(cs, bindings));
|
gadgetController.put(controllerName, new EntityController(cs, bindings));
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Grasscutter.getLogger()
|
Grasscutter.getLogger().error("Error while loading gadget controller: {}.", fileName);
|
||||||
.error("Error while loading gadget controller: {}.", fileName);
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
Grasscutter.getLogger().debug("Loaded {} gadget controllers", gadgetController.size());
|
Grasscutter.getLogger().debug("Loaded {} gadget controllers", gadgetController.size());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Grasscutter.getLogger().error("Error loading gadget controller Lua scripts.");
|
Grasscutter.getLogger().error("Error loading gadget controller Lua scripts.");
|
||||||
|
@ -21,11 +21,13 @@ public class SceneGadget extends SceneObject {
|
|||||||
public SceneBossChest boss_chest;
|
public SceneBossChest boss_chest;
|
||||||
public int interact_id;
|
public int interact_id;
|
||||||
/**
|
/**
|
||||||
* Note: this field indicates whether the gadget should disappear permanently.
|
* Note: this field indicates whether the gadget should disappear permanently. For example, if
|
||||||
* For example, if isOneOff=true, like most chests, it will disappear permanently after interacted.
|
* isOneOff=true, like most chests, it will disappear permanently after interacted. If
|
||||||
* If isOneOff=false, like investigation points, it will disappear temporarily, and appear again in next big world resource refresh routine.
|
* isOneOff=false, like investigation points, it will disappear temporarily, and appear again in
|
||||||
|
* next big world resource refresh routine.
|
||||||
*/
|
*/
|
||||||
public boolean isOneoff;
|
public boolean isOneoff;
|
||||||
|
|
||||||
public int area_id;
|
public int area_id;
|
||||||
public int draft_id;
|
public int draft_id;
|
||||||
public int route_id;
|
public int route_id;
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package emu.grasscutter.server.game;
|
package emu.grasscutter.server.game;
|
||||||
|
|
||||||
|
import static emu.grasscutter.config.Configuration.GAME_INFO;
|
||||||
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.database.DatabaseHelper;
|
import emu.grasscutter.database.DatabaseHelper;
|
||||||
@ -34,18 +37,14 @@ import emu.grasscutter.server.event.internal.ServerStopEvent;
|
|||||||
import emu.grasscutter.server.event.types.ServerEvent;
|
import emu.grasscutter.server.event.types.ServerEvent;
|
||||||
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
|
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
|
||||||
import emu.grasscutter.task.TaskMap;
|
import emu.grasscutter.task.TaskMap;
|
||||||
import kcp.highway.ChannelConfig;
|
|
||||||
import kcp.highway.KcpServer;
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import kcp.highway.ChannelConfig;
|
||||||
import static emu.grasscutter.config.Configuration.GAME_INFO;
|
import kcp.highway.KcpServer;
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public final class GameServer extends KcpServer {
|
public final class GameServer extends KcpServer {
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package emu.grasscutter.server.http.dispatch;
|
package emu.grasscutter.server.http.dispatch;
|
||||||
|
|
||||||
|
import static emu.grasscutter.config.Configuration.*;
|
||||||
|
|
||||||
import com.google.protobuf.ByteString;
|
import com.google.protobuf.ByteString;
|
||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.Grasscutter.ServerRunMode;
|
import emu.grasscutter.Grasscutter.ServerRunMode;
|
||||||
import emu.grasscutter.net.proto.QueryRegionListHttpRspOuterClass.QueryRegionListHttpRsp;
|
|
||||||
import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp;
|
import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp;
|
||||||
import emu.grasscutter.net.proto.RegionSimpleInfoOuterClass.RegionSimpleInfo;
|
import emu.grasscutter.net.proto.QueryRegionListHttpRspOuterClass.QueryRegionListHttpRsp;
|
||||||
import emu.grasscutter.net.proto.RegionInfoOuterClass.RegionInfo;
|
import emu.grasscutter.net.proto.RegionInfoOuterClass.RegionInfo;
|
||||||
|
import emu.grasscutter.net.proto.RegionSimpleInfoOuterClass.RegionSimpleInfo;
|
||||||
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
||||||
import emu.grasscutter.net.proto.StopServerInfoOuterClass.StopServerInfo;
|
import emu.grasscutter.net.proto.StopServerInfoOuterClass.StopServerInfo;
|
||||||
import emu.grasscutter.server.event.dispatch.QueryAllRegionsEvent;
|
import emu.grasscutter.server.event.dispatch.QueryAllRegionsEvent;
|
||||||
@ -18,23 +20,13 @@ import emu.grasscutter.utils.Crypto;
|
|||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
import io.javalin.Javalin;
|
import io.javalin.Javalin;
|
||||||
import io.javalin.http.Context;
|
import io.javalin.http.Context;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import javax.crypto.Cipher;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.security.Signature;
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.*;
|
/** Handles requests related to region queries. */
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles requests related to region queries.
|
|
||||||
*/
|
|
||||||
public final class RegionHandler implements Router {
|
public final class RegionHandler implements Router {
|
||||||
private static final Map<String, RegionData> regions = new ConcurrentHashMap<>();
|
private static final Map<String, RegionData> regions = new ConcurrentHashMap<>();
|
||||||
private static String regionListResponse;
|
private static String regionListResponse;
|
||||||
@ -48,13 +40,15 @@ public final class RegionHandler implements Router {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Configures region data according to configuration. */
|
||||||
* Configures region data according to configuration.
|
|
||||||
*/
|
|
||||||
private void initialize() {
|
private void initialize() {
|
||||||
String dispatchDomain = "http" + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + "://"
|
String dispatchDomain =
|
||||||
+ lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + ":"
|
"http"
|
||||||
+ lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort);
|
+ (HTTP_ENCRYPTION.useInRouting ? "s" : "")
|
||||||
|
+ "://"
|
||||||
|
+ lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress)
|
||||||
|
+ ":"
|
||||||
|
+ lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort);
|
||||||
|
|
||||||
// Create regions.
|
// Create regions.
|
||||||
List<RegionSimpleInfo> servers = new ArrayList<>();
|
List<RegionSimpleInfo> servers = new ArrayList<>();
|
||||||
@ -62,61 +56,84 @@ public final class RegionHandler implements Router {
|
|||||||
|
|
||||||
var configuredRegions = new ArrayList<>(List.of(DISPATCH_INFO.regions));
|
var configuredRegions = new ArrayList<>(List.of(DISPATCH_INFO.regions));
|
||||||
if (SERVER.runMode != ServerRunMode.HYBRID && configuredRegions.size() == 0) {
|
if (SERVER.runMode != ServerRunMode.HYBRID && configuredRegions.size() == 0) {
|
||||||
Grasscutter.getLogger().error("[Dispatch] There are no game servers available. Exiting due to unplayable state.");
|
Grasscutter.getLogger()
|
||||||
|
.error(
|
||||||
|
"[Dispatch] There are no game servers available. Exiting due to unplayable state.");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
} else if (configuredRegions.size() == 0)
|
} else if (configuredRegions.size() == 0)
|
||||||
configuredRegions.add(new Region("os_usa", DISPATCH_INFO.defaultName,
|
configuredRegions.add(
|
||||||
lr(GAME_INFO.accessAddress, GAME_INFO.bindAddress),
|
new Region(
|
||||||
lr(GAME_INFO.accessPort, GAME_INFO.bindPort)));
|
"os_usa",
|
||||||
|
DISPATCH_INFO.defaultName,
|
||||||
|
lr(GAME_INFO.accessAddress, GAME_INFO.bindAddress),
|
||||||
|
lr(GAME_INFO.accessPort, GAME_INFO.bindPort)));
|
||||||
|
|
||||||
configuredRegions.forEach(region -> {
|
configuredRegions.forEach(
|
||||||
if (usedNames.contains(region.Name)) {
|
region -> {
|
||||||
Grasscutter.getLogger().error("Region name already in use.");
|
if (usedNames.contains(region.Name)) {
|
||||||
return;
|
Grasscutter.getLogger().error("Region name already in use.");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a region identifier.
|
// Create a region identifier.
|
||||||
var identifier = RegionSimpleInfo.newBuilder()
|
var identifier =
|
||||||
.setName(region.Name).setTitle(region.Title).setType("DEV_PUBLIC")
|
RegionSimpleInfo.newBuilder()
|
||||||
.setDispatchUrl(dispatchDomain + "/query_cur_region/" + region.Name)
|
.setName(region.Name)
|
||||||
.build();
|
.setTitle(region.Title)
|
||||||
usedNames.add(region.Name); servers.add(identifier);
|
.setType("DEV_PUBLIC")
|
||||||
|
.setDispatchUrl(dispatchDomain + "/query_cur_region/" + region.Name)
|
||||||
|
.build();
|
||||||
|
usedNames.add(region.Name);
|
||||||
|
servers.add(identifier);
|
||||||
|
|
||||||
// Create a region info object.
|
// Create a region info object.
|
||||||
var regionInfo = RegionInfo.newBuilder()
|
var regionInfo =
|
||||||
.setGateserverIp(region.Ip).setGateserverPort(region.Port)
|
RegionInfo.newBuilder()
|
||||||
.setSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
|
.setGateserverIp(region.Ip)
|
||||||
.build();
|
.setGateserverPort(region.Port)
|
||||||
// Create an updated region query.
|
.setSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
|
||||||
var updatedQuery = QueryCurrRegionHttpRsp.newBuilder().setRegionInfo(regionInfo).build();
|
.build();
|
||||||
regions.put(region.Name, new RegionData(updatedQuery, Utils.base64Encode(updatedQuery.toByteString().toByteArray())));
|
// Create an updated region query.
|
||||||
});
|
var updatedQuery = QueryCurrRegionHttpRsp.newBuilder().setRegionInfo(regionInfo).build();
|
||||||
|
regions.put(
|
||||||
|
region.Name,
|
||||||
|
new RegionData(
|
||||||
|
updatedQuery, Utils.base64Encode(updatedQuery.toByteString().toByteArray())));
|
||||||
|
});
|
||||||
|
|
||||||
// Create a config object.
|
// Create a config object.
|
||||||
byte[] customConfig = "{\"sdkenv\":\"2\",\"checkdevice\":\"false\",\"loadPatch\":\"false\",\"showexception\":\"false\",\"regionConfig\":\"pm|fk|add\",\"downloadMode\":\"0\"}".getBytes();
|
byte[] customConfig =
|
||||||
|
"{\"sdkenv\":\"2\",\"checkdevice\":\"false\",\"loadPatch\":\"false\",\"showexception\":\"false\",\"regionConfig\":\"pm|fk|add\",\"downloadMode\":\"0\"}"
|
||||||
|
.getBytes();
|
||||||
Crypto.xor(customConfig, Crypto.DISPATCH_KEY); // XOR the config with the key.
|
Crypto.xor(customConfig, Crypto.DISPATCH_KEY); // XOR the config with the key.
|
||||||
|
|
||||||
// Create an updated region list.
|
// Create an updated region list.
|
||||||
QueryRegionListHttpRsp updatedRegionList = QueryRegionListHttpRsp.newBuilder()
|
QueryRegionListHttpRsp updatedRegionList =
|
||||||
.addAllRegionList(servers)
|
QueryRegionListHttpRsp.newBuilder()
|
||||||
.setClientSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
|
.addAllRegionList(servers)
|
||||||
.setClientCustomConfigEncrypted(ByteString.copyFrom(customConfig))
|
.setClientSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
|
||||||
.setEnableLoginPc(true).build();
|
.setClientCustomConfigEncrypted(ByteString.copyFrom(customConfig))
|
||||||
|
.setEnableLoginPc(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
// Set the region list response.
|
// Set the region list response.
|
||||||
regionListResponse = Utils.base64Encode(updatedRegionList.toByteString().toByteArray());
|
regionListResponse = Utils.base64Encode(updatedRegionList.toByteString().toByteArray());
|
||||||
|
|
||||||
// CN
|
// CN
|
||||||
// Create a config object.
|
// Create a config object.
|
||||||
byte[] customConfigcn = "{\"sdkenv\":\"0\",\"checkdevice\":\"true\",\"loadPatch\":\"false\",\"showexception\":\"false\",\"regionConfig\":\"pm|fk|add\",\"downloadMode\":\"0\"}".getBytes();
|
byte[] customConfigcn =
|
||||||
|
"{\"sdkenv\":\"0\",\"checkdevice\":\"true\",\"loadPatch\":\"false\",\"showexception\":\"false\",\"regionConfig\":\"pm|fk|add\",\"downloadMode\":\"0\"}"
|
||||||
|
.getBytes();
|
||||||
Crypto.xor(customConfigcn, Crypto.DISPATCH_KEY); // XOR the config with the key.
|
Crypto.xor(customConfigcn, Crypto.DISPATCH_KEY); // XOR the config with the key.
|
||||||
|
|
||||||
// Create an updated region list.
|
// Create an updated region list.
|
||||||
QueryRegionListHttpRsp updatedRegionListcn = QueryRegionListHttpRsp.newBuilder()
|
QueryRegionListHttpRsp updatedRegionListcn =
|
||||||
.addAllRegionList(servers)
|
QueryRegionListHttpRsp.newBuilder()
|
||||||
.setClientSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
|
.addAllRegionList(servers)
|
||||||
.setClientCustomConfigEncrypted(ByteString.copyFrom(customConfigcn))
|
.setClientSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED))
|
||||||
.setEnableLoginPc(true).build();
|
.setClientCustomConfigEncrypted(ByteString.copyFrom(customConfigcn))
|
||||||
|
.setEnableLoginPc(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
// Set the region list response.
|
// Set the region list response.
|
||||||
regionListResponsecn = Utils.base64Encode(updatedRegionListcn.toByteString().toByteArray());
|
regionListResponsecn = Utils.base64Encode(updatedRegionListcn.toByteString().toByteArray());
|
||||||
@ -143,7 +160,8 @@ public final class RegionHandler implements Router {
|
|||||||
String platformName = ctx.queryParam("platform");
|
String platformName = ctx.queryParam("platform");
|
||||||
|
|
||||||
// Determine the region list to use based on the version and platform.
|
// Determine the region list to use based on the version and platform.
|
||||||
if ("CNRELiOS".equals(versionCode) || "CNRELWin".equals(versionCode)
|
if ("CNRELiOS".equals(versionCode)
|
||||||
|
|| "CNRELWin".equals(versionCode)
|
||||||
|| "CNRELAndroid".equals(versionCode)) {
|
|| "CNRELAndroid".equals(versionCode)) {
|
||||||
// Use the CN region list.
|
// Use the CN region list.
|
||||||
QueryAllRegionsEvent event = new QueryAllRegionsEvent(regionListResponsecn);
|
QueryAllRegionsEvent event = new QueryAllRegionsEvent(regionListResponsecn);
|
||||||
@ -152,7 +170,8 @@ public final class RegionHandler implements Router {
|
|||||||
|
|
||||||
// Respond with the event result.
|
// Respond with the event result.
|
||||||
ctx.result(event.getRegionList());
|
ctx.result(event.getRegionList());
|
||||||
} else if ("OSRELiOS".equals(versionCode) || "OSRELWin".equals(versionCode)
|
} else if ("OSRELiOS".equals(versionCode)
|
||||||
|
|| "OSRELWin".equals(versionCode)
|
||||||
|| "OSRELAndroid".equals(versionCode)) {
|
|| "OSRELAndroid".equals(versionCode)) {
|
||||||
// Use the OS region list.
|
// Use the OS region list.
|
||||||
QueryAllRegionsEvent event = new QueryAllRegionsEvent(regionListResponse);
|
QueryAllRegionsEvent event = new QueryAllRegionsEvent(regionListResponse);
|
||||||
@ -187,7 +206,8 @@ public final class RegionHandler implements Router {
|
|||||||
ctx.result(event.getRegionList());
|
ctx.result(event.getRegionList());
|
||||||
}
|
}
|
||||||
// Log the request to the console.
|
// Log the request to the console.
|
||||||
Grasscutter.getLogger().info(String.format("[Dispatch] Client %s request: query_region_list", ctx.ip()));
|
Grasscutter.getLogger()
|
||||||
|
.info(String.format("[Dispatch] Client %s request: query_region_list", ctx.ip()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -202,39 +222,53 @@ public final class RegionHandler implements Router {
|
|||||||
// Get region data.
|
// Get region data.
|
||||||
String regionData = "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw==";
|
String regionData = "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw==";
|
||||||
if (ctx.queryParamMap().values().size() > 0) {
|
if (ctx.queryParamMap().values().size() > 0) {
|
||||||
if (region != null)
|
if (region != null) regionData = region.getBase64();
|
||||||
regionData = region.getBase64();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String clientVersion = versionName.replaceAll(Pattern.compile("[a-zA-Z]").pattern(), "");
|
String clientVersion = versionName.replaceAll(Pattern.compile("[a-zA-Z]").pattern(), "");
|
||||||
String[] versionCode = clientVersion.split("\\.");
|
String[] versionCode = clientVersion.split("\\.");
|
||||||
int versionMajor = Integer.parseInt(versionCode[0]);
|
int versionMajor = Integer.parseInt(versionCode[0]);
|
||||||
int versionMinor = Integer.parseInt(versionCode[1]);
|
int versionMinor = Integer.parseInt(versionCode[1]);
|
||||||
int versionFix = Integer.parseInt(versionCode[2]);
|
int versionFix = Integer.parseInt(versionCode[2]);
|
||||||
|
|
||||||
if (versionMajor >= 3 || (versionMajor == 2 && versionMinor == 7 && versionFix >= 50) || (versionMajor == 2 && versionMinor == 8)) {
|
if (versionMajor >= 3
|
||||||
|
|| (versionMajor == 2 && versionMinor == 7 && versionFix >= 50)
|
||||||
|
|| (versionMajor == 2 && versionMinor == 8)) {
|
||||||
try {
|
try {
|
||||||
QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData); event.call();
|
QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData);
|
||||||
|
event.call();
|
||||||
|
|
||||||
String key_id = ctx.queryParam("key_id");
|
String key_id = ctx.queryParam("key_id");
|
||||||
|
|
||||||
if (!clientVersion.equals(GameConstants.VERSION)) { // Reject clients when there is a version mismatch
|
if (!clientVersion.equals(
|
||||||
|
GameConstants.VERSION)) { // Reject clients when there is a version mismatch
|
||||||
|
|
||||||
boolean updateClient = GameConstants.VERSION.compareTo(clientVersion) > 0;
|
boolean updateClient = GameConstants.VERSION.compareTo(clientVersion) > 0;
|
||||||
|
|
||||||
QueryCurrRegionHttpRsp rsp = QueryCurrRegionHttpRsp.newBuilder()
|
QueryCurrRegionHttpRsp rsp =
|
||||||
.setRetcode(Retcode.RET_STOP_SERVER_VALUE)
|
QueryCurrRegionHttpRsp.newBuilder()
|
||||||
.setMsg("Connection Failed!")
|
.setRetcode(Retcode.RET_STOP_SERVER_VALUE)
|
||||||
.setRegionInfo(RegionInfo.newBuilder())
|
.setMsg("Connection Failed!")
|
||||||
.setStopServer(StopServerInfo.newBuilder()
|
.setRegionInfo(RegionInfo.newBuilder())
|
||||||
.setUrl("https://discord.gg/grasscutters")
|
.setStopServer(
|
||||||
.setStopBeginTime((int) Instant.now().getEpochSecond())
|
StopServerInfo.newBuilder()
|
||||||
.setStopEndTime((int) Instant.now().getEpochSecond()*2)
|
.setUrl("https://discord.gg/grasscutters")
|
||||||
.setContentMsg(updateClient ? "\nVersion mismatch outdated client! \n\nServer version: %s\nClient version: %s".formatted(GameConstants.VERSION, clientVersion) : "\nVersion mismatch outdated server! \n\nServer version: %s\nClient version: %s".formatted(GameConstants.VERSION, clientVersion))
|
.setStopBeginTime((int) Instant.now().getEpochSecond())
|
||||||
.build())
|
.setStopEndTime((int) Instant.now().getEpochSecond() * 2)
|
||||||
.buildPartial();
|
.setContentMsg(
|
||||||
|
updateClient
|
||||||
|
? "\nVersion mismatch outdated client! \n\nServer version: %s\nClient version: %s"
|
||||||
|
.formatted(GameConstants.VERSION, clientVersion)
|
||||||
|
: "\nVersion mismatch outdated server! \n\nServer version: %s\nClient version: %s"
|
||||||
|
.formatted(GameConstants.VERSION, clientVersion))
|
||||||
|
.build())
|
||||||
|
.buildPartial();
|
||||||
|
|
||||||
Grasscutter.getLogger().info(String.format("Connection denied for %s due to %s", ctx.ip(), updateClient ? "outdated client!" : "outdated server!"));
|
Grasscutter.getLogger()
|
||||||
|
.info(
|
||||||
|
String.format(
|
||||||
|
"Connection denied for %s due to %s",
|
||||||
|
ctx.ip(), updateClient ? "outdated client!" : "outdated server!"));
|
||||||
|
|
||||||
ctx.json(Crypto.encryptAndSignRegionData(rsp.toByteArray(), key_id));
|
ctx.json(Crypto.encryptAndSignRegionData(rsp.toByteArray(), key_id));
|
||||||
return;
|
return;
|
||||||
@ -251,28 +285,25 @@ public final class RegionHandler implements Router {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var regionInfo = Utils.base64Decode(event.getRegionInfo());
|
var regionInfo = Utils.base64Decode(event.getRegionInfo());
|
||||||
|
|
||||||
ctx.json(Crypto.encryptAndSignRegionData(regionInfo, key_id));
|
ctx.json(Crypto.encryptAndSignRegionData(regionInfo, key_id));
|
||||||
}
|
} catch (Exception e) {
|
||||||
catch (Exception e) {
|
|
||||||
Grasscutter.getLogger().error("An error occurred while handling query_cur_region.", e);
|
Grasscutter.getLogger().error("An error occurred while handling query_cur_region.", e);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Invoke event.
|
// Invoke event.
|
||||||
QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData); event.call();
|
QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData);
|
||||||
|
event.call();
|
||||||
// Respond with event result.
|
// Respond with event result.
|
||||||
ctx.result(event.getRegionInfo());
|
ctx.result(event.getRegionInfo());
|
||||||
}
|
}
|
||||||
// Log to console.
|
// Log to console.
|
||||||
Grasscutter.getLogger().info(String.format("Client %s request: query_cur_region/%s", ctx.ip(), regionName));
|
Grasscutter.getLogger()
|
||||||
|
.info(String.format("Client %s request: query_cur_region/%s", ctx.ip(), regionName));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Region data container. */
|
||||||
* Region data container.
|
|
||||||
*/
|
|
||||||
public static class RegionData {
|
public static class RegionData {
|
||||||
private final QueryCurrRegionHttpRsp regionQuery;
|
private final QueryCurrRegionHttpRsp regionQuery;
|
||||||
private final String base64;
|
private final String base64;
|
||||||
@ -293,6 +324,7 @@ public final class RegionHandler implements Router {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the current region query.
|
* Gets the current region query.
|
||||||
|
*
|
||||||
* @return A {@link QueryCurrRegionHttpRsp} object.
|
* @return A {@link QueryCurrRegionHttpRsp} object.
|
||||||
*/
|
*/
|
||||||
public static QueryCurrRegionHttpRsp getCurrentRegion() {
|
public static QueryCurrRegionHttpRsp getCurrentRegion() {
|
||||||
|
@ -15,6 +15,8 @@ public class HandlerChangeGameTimeReq extends PacketHandler {
|
|||||||
var req = ChangeGameTimeReq.parseFrom(payload);
|
var req = ChangeGameTimeReq.parseFrom(payload);
|
||||||
|
|
||||||
session.getPlayer().getWorld().changeTime(req.getGameTime(), req.getExtraDays());
|
session.getPlayer().getWorld().changeTime(req.getGameTime(), req.getExtraDays());
|
||||||
session.getPlayer().sendPacket(new PacketChangeGameTimeRsp(session.getPlayer(), req.getExtraDays()));
|
session
|
||||||
|
.getPlayer()
|
||||||
|
.sendPacket(new PacketChangeGameTimeRsp(session.getPlayer(), req.getExtraDays()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,8 +94,10 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// as long as one of these two packets be forwarded to client, the animation of avatar will be interrupted
|
// as long as one of these two packets be forwarded to client, the animation of avatar
|
||||||
if (motionState == MotionState.MOTION_STATE_NOTIFY || motionState == MotionState.MOTION_STATE_FIGHT) {
|
// will be interrupted
|
||||||
|
if (motionState == MotionState.MOTION_STATE_NOTIFY
|
||||||
|
|| motionState == MotionState.MOTION_STATE_FIGHT) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,9 @@ public class HandlerDungeonEntryInfoReq extends PacketHandler {
|
|||||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
DungeonEntryInfoReq req = DungeonEntryInfoReq.parseFrom(payload);
|
DungeonEntryInfoReq req = DungeonEntryInfoReq.parseFrom(payload);
|
||||||
|
|
||||||
session.getServer().getDungeonSystem().sendEntryInfoFor(session.getPlayer(), req.getPointId(), req.getSceneId());
|
session
|
||||||
|
.getServer()
|
||||||
|
.getDungeonSystem()
|
||||||
|
.sendEntryInfoFor(session.getPlayer(), req.getPointId(), req.getSceneId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,13 @@ public class HandlerPlayerEnterDungeonReq extends PacketHandler {
|
|||||||
// Auto template
|
// Auto template
|
||||||
PlayerEnterDungeonReq req = PlayerEnterDungeonReq.parseFrom(payload);
|
PlayerEnterDungeonReq req = PlayerEnterDungeonReq.parseFrom(payload);
|
||||||
|
|
||||||
var success = session
|
var success =
|
||||||
.getServer()
|
session
|
||||||
.getDungeonSystem()
|
.getServer()
|
||||||
.enterDungeon(session.getPlayer(), req.getPointId(), req.getDungeonId());
|
.getDungeonSystem()
|
||||||
|
.enterDungeon(session.getPlayer(), req.getPointId(), req.getDungeonId());
|
||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.sendPacket(new PacketPlayerEnterDungeonRsp(req.getPointId(), req.getDungeonId(), success));
|
.sendPacket(new PacketPlayerEnterDungeonRsp(req.getPointId(), req.getDungeonId(), success));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.game.props.SceneType;
|
|
||||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
@ -17,8 +16,9 @@ public class HandlerPostEnterSceneReq extends PacketHandler {
|
|||||||
var scene = player.getScene();
|
var scene = player.getScene();
|
||||||
var questManager = player.getQuestManager();
|
var questManager = player.getQuestManager();
|
||||||
|
|
||||||
switch (session.getPlayer().getScene().getSceneType()){
|
switch (session.getPlayer().getScene().getSceneType()) {
|
||||||
case SCENE_ROOM -> questManager.queueEvent(QuestContent.QUEST_CONTENT_ENTER_ROOM, scene.getId(), 0);
|
case SCENE_ROOM -> questManager.queueEvent(
|
||||||
|
QuestContent.QUEST_CONTENT_ENTER_ROOM, scene.getId(), 0);
|
||||||
case SCENE_WORLD -> {
|
case SCENE_WORLD -> {
|
||||||
questManager.queueEvent(QuestContent.QUEST_CONTENT_ENTER_MY_WORLD, scene.getId());
|
questManager.queueEvent(QuestContent.QUEST_CONTENT_ENTER_MY_WORLD, scene.getId());
|
||||||
questManager.queueEvent(QuestContent.QUEST_CONTENT_ENTER_MY_WORLD_SCENE, scene.getId());
|
questManager.queueEvent(QuestContent.QUEST_CONTENT_ENTER_MY_WORLD_SCENE, scene.getId());
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.game.quest.GameMainQuest;
|
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
@ -10,21 +9,18 @@ import emu.grasscutter.server.game.GameSession;
|
|||||||
import emu.grasscutter.server.packet.send.PacketQuestTransmitRsp;
|
import emu.grasscutter.server.packet.send.PacketQuestTransmitRsp;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
|
||||||
import lombok.val;
|
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.QuestTransmitReq)
|
@Opcodes(PacketOpcodes.QuestTransmitReq)
|
||||||
public class HandlerQuestTransmitReq extends PacketHandler {
|
public class HandlerQuestTransmitReq extends PacketHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
val req = QuestTransmitReq.parseFrom(payload);
|
var req = QuestTransmitReq.parseFrom(payload);
|
||||||
GameMainQuest mainQuest =
|
var mainQuest = session.getPlayer().getQuestManager().getMainQuestById(req.getQuestId() / 100);
|
||||||
session.getPlayer().getQuestManager().getMainQuestById(req.getQuestId() / 100);
|
|
||||||
List<Position> posAndRot = new ArrayList<>();
|
var posAndRot = new ArrayList<Position>();
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
if (mainQuest.hasTeleportPostion(req.getQuestId(), posAndRot)) {
|
if (mainQuest.hasTeleportPosition(req.getQuestId(), posAndRot)) {
|
||||||
int sceneId =
|
var sceneId =
|
||||||
GameData.getTeleportDataMap()
|
GameData.getTeleportDataMap()
|
||||||
.get(req.getQuestId())
|
.get(req.getQuestId())
|
||||||
.getTransmit_points()
|
.getTransmit_points()
|
||||||
@ -36,6 +32,7 @@ public class HandlerQuestTransmitReq extends PacketHandler {
|
|||||||
.getWorld()
|
.getWorld()
|
||||||
.transferPlayerToScene(session.getPlayer(), sceneId, posAndRot.get(0));
|
.transferPlayerToScene(session.getPlayer(), sceneId, posAndRot.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
session.send(new PacketQuestTransmitRsp(result, req));
|
session.send(new PacketQuestTransmitRsp(result, req));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
|
|
||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import javax.lang.model.type.TypeMirror;
|
|
||||||
|
|
||||||
import emu.grasscutter.net.packet.Opcodes;
|
import emu.grasscutter.net.packet.Opcodes;
|
||||||
import emu.grasscutter.net.packet.PacketHandler;
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
@ -24,8 +21,9 @@ public class HandlerSceneAudioNotify extends PacketHandler {
|
|||||||
int type = notify.getType();
|
int type = notify.getType();
|
||||||
List<Integer> param1 = notify.getParam1List();
|
List<Integer> param1 = notify.getParam1List();
|
||||||
|
|
||||||
session.getPlayer().getScene().broadcastPacket(new PacketSceneAudioNotify(sourceUid, param2, param3, type, param1));
|
session
|
||||||
|
.getPlayer()
|
||||||
|
.getScene()
|
||||||
|
.broadcastPacket(new PacketSceneAudioNotify(sourceUid, param2, param3, type, param1));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ public class HandlerSetPlayerBornDataReq extends PacketHandler {
|
|||||||
// Check if the default Anemo skill should be given.
|
// Check if the default Anemo skill should be given.
|
||||||
if (!GAME_OPTIONS.questing) {
|
if (!GAME_OPTIONS.questing) {
|
||||||
mainCharacter.setSkillDepotData(
|
mainCharacter.setSkillDepotData(
|
||||||
GameData.getAvatarSkillDepotDataMap().get(startingSkillDepot));
|
GameData.getAvatarSkillDepotDataMap().get(startingSkillDepot));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manually handle adding to team
|
// Manually handle adding to team
|
||||||
|
@ -17,9 +17,7 @@ public class HandlerUnlockPersonalLineReq extends PacketHandler {
|
|||||||
var req = UnlockPersonalLineReq.parseFrom(payload);
|
var req = UnlockPersonalLineReq.parseFrom(payload);
|
||||||
var data = GameData.getPersonalLineDataMap().get(req.getPersonalLineId());
|
var data = GameData.getPersonalLineDataMap().get(req.getPersonalLineId());
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
session.send(
|
session.send(new PacketUnlockPersonalLineRsp(req.getPersonalLineId(), Retcode.RET_FAIL));
|
||||||
new PacketUnlockPersonalLineRsp(
|
|
||||||
req.getPersonalLineId(), Retcode.RET_FAIL));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import emu.grasscutter.game.props.FightProperty;
|
|||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.AvatarFightPropUpdateNotifyOuterClass.AvatarFightPropUpdateNotify;
|
import emu.grasscutter.net.proto.AvatarFightPropUpdateNotifyOuterClass.AvatarFightPropUpdateNotify;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class PacketAvatarFightPropUpdateNotify extends BasePacket {
|
public class PacketAvatarFightPropUpdateNotify extends BasePacket {
|
||||||
|
@ -14,11 +14,14 @@ public class PacketAvatarTeamUpdateNotify extends BasePacket {
|
|||||||
|
|
||||||
var teamManager = player.getTeamManager();
|
var teamManager = player.getTeamManager();
|
||||||
if (teamManager.isUsingTrialTeam()) {
|
if (teamManager.isUsingTrialTeam()) {
|
||||||
proto.addAllTempAvatarGuidList(teamManager.getActiveTeam().stream()
|
proto.addAllTempAvatarGuidList(
|
||||||
.map(entity -> entity.getAvatar().getGuid()).toList());
|
teamManager.getActiveTeam().stream()
|
||||||
|
.map(entity -> entity.getAvatar().getGuid())
|
||||||
|
.toList());
|
||||||
} else {
|
} else {
|
||||||
teamManager.getTeams().forEach((key, value) ->
|
teamManager
|
||||||
proto.putAvatarTeamMap(key, value.toProto(player)));
|
.getTeams()
|
||||||
|
.forEach((key, value) -> proto.putAvatarTeamMap(key, value.toProto(player)));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
|
@ -10,9 +10,10 @@ public class PacketBuyResinRsp extends BasePacket {
|
|||||||
public PacketBuyResinRsp(Player player, int ret) {
|
public PacketBuyResinRsp(Player player, int ret) {
|
||||||
super(PacketOpcodes.BuyResinRsp);
|
super(PacketOpcodes.BuyResinRsp);
|
||||||
|
|
||||||
this.setData(BuyResinRspOuterClass.BuyResinRsp.newBuilder()
|
this.setData(
|
||||||
.setCurValue(player.getProperty(PlayerProperty.PROP_PLAYER_RESIN))
|
BuyResinRspOuterClass.BuyResinRsp.newBuilder()
|
||||||
.setRetcode(ret)
|
.setCurValue(player.getProperty(PlayerProperty.PROP_PLAYER_RESIN))
|
||||||
.build());
|
.setRetcode(ret)
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,9 @@ public class PacketChangeGameTimeRsp extends BasePacket {
|
|||||||
|
|
||||||
ChangeGameTimeRsp proto =
|
ChangeGameTimeRsp proto =
|
||||||
ChangeGameTimeRsp.newBuilder()
|
ChangeGameTimeRsp.newBuilder()
|
||||||
.setCurGameTime(player.getWorld().getGameTime())
|
.setCurGameTime(player.getWorld().getGameTime())
|
||||||
.setExtraDays(extraDays)
|
.setExtraDays(extraDays)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,7 @@ public class PacketDropHintNotify extends BasePacket {
|
|||||||
public PacketDropHintNotify(int itemId, Vector position) {
|
public PacketDropHintNotify(int itemId, Vector position) {
|
||||||
super(PacketOpcodes.DropHintNotify);
|
super(PacketOpcodes.DropHintNotify);
|
||||||
|
|
||||||
var proto = DropHintNotify.newBuilder()
|
var proto = DropHintNotify.newBuilder().addItemIdList(itemId).setPosition(position);
|
||||||
.addItemIdList(itemId)
|
|
||||||
.setPosition(position);
|
|
||||||
this.setData(proto.build());
|
this.setData(proto.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ import emu.grasscutter.net.packet.BasePacket;
|
|||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.DungeonEntryInfoOuterClass.DungeonEntryInfo;
|
import emu.grasscutter.net.proto.DungeonEntryInfoOuterClass.DungeonEntryInfo;
|
||||||
import emu.grasscutter.net.proto.DungeonEntryInfoRspOuterClass.DungeonEntryInfoRsp;
|
import emu.grasscutter.net.proto.DungeonEntryInfoRspOuterClass.DungeonEntryInfoRsp;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -36,19 +35,18 @@ public class PacketDungeonEntryInfoRsp extends BasePacket {
|
|||||||
public PacketDungeonEntryInfoRsp(PointData pointData, List<Integer> additional) {
|
public PacketDungeonEntryInfoRsp(PointData pointData, List<Integer> additional) {
|
||||||
super(PacketOpcodes.DungeonEntryInfoRsp);
|
super(PacketOpcodes.DungeonEntryInfoRsp);
|
||||||
|
|
||||||
var packet = DungeonEntryInfoRsp.newBuilder()
|
var packet = DungeonEntryInfoRsp.newBuilder().setPointId(pointData.getId());
|
||||||
.setPointId(pointData.getId());
|
|
||||||
|
|
||||||
// Add dungeon IDs from the point data.
|
// Add dungeon IDs from the point data.
|
||||||
if (pointData.getDungeonIds() != null) {
|
if (pointData.getDungeonIds() != null) {
|
||||||
Arrays.stream(pointData.getDungeonIds())
|
Arrays.stream(pointData.getDungeonIds())
|
||||||
.forEach(id -> packet.addDungeonEntryList(
|
.forEach(
|
||||||
DungeonEntryInfo.newBuilder().setDungeonId(id)));
|
id -> packet.addDungeonEntryList(DungeonEntryInfo.newBuilder().setDungeonId(id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add additional dungeon IDs.
|
// Add additional dungeon IDs.
|
||||||
additional.forEach(id -> packet.addDungeonEntryList(
|
additional.forEach(
|
||||||
DungeonEntryInfo.newBuilder().setDungeonId(id)));
|
id -> packet.addDungeonEntryList(DungeonEntryInfo.newBuilder().setDungeonId(id)));
|
||||||
|
|
||||||
this.setData(packet);
|
this.setData(packet);
|
||||||
}
|
}
|
||||||
|
@ -8,14 +8,15 @@ import emu.grasscutter.net.proto.ResinChangeNotifyOuterClass.ResinChangeNotify;
|
|||||||
|
|
||||||
public class PacketResinChangeNotify extends BasePacket {
|
public class PacketResinChangeNotify extends BasePacket {
|
||||||
|
|
||||||
public PacketResinChangeNotify(Player player) {
|
public PacketResinChangeNotify(Player player) {
|
||||||
super(PacketOpcodes.ResinChangeNotify);
|
super(PacketOpcodes.ResinChangeNotify);
|
||||||
|
|
||||||
ResinChangeNotify proto = ResinChangeNotify.newBuilder()
|
ResinChangeNotify proto =
|
||||||
.setCurValue(player.getProperty(PlayerProperty.PROP_PLAYER_RESIN))
|
ResinChangeNotify.newBuilder()
|
||||||
.setNextAddTimestamp(player.getNextResinRefresh())
|
.setCurValue(player.getProperty(PlayerProperty.PROP_PLAYER_RESIN))
|
||||||
.setCurBuyCount(player.getResinBuyCount())
|
.setNextAddTimestamp(player.getNextResinRefresh())
|
||||||
.build();
|
.setCurBuyCount(player.getResinBuyCount())
|
||||||
|
.build();
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
|
@ -7,17 +7,19 @@ import java.util.List;
|
|||||||
|
|
||||||
public class PacketSceneAudioNotify extends BasePacket {
|
public class PacketSceneAudioNotify extends BasePacket {
|
||||||
|
|
||||||
public PacketSceneAudioNotify(int sourceUid, List<Float> param2, List<String> param3, int type, List<Integer> param1) {
|
public PacketSceneAudioNotify(
|
||||||
|
int sourceUid, List<Float> param2, List<String> param3, int type, List<Integer> param1) {
|
||||||
super(PacketOpcodes.SceneAudioNotify);
|
super(PacketOpcodes.SceneAudioNotify);
|
||||||
|
|
||||||
SceneAudioNotifyOuterClass.SceneAudioNotify proto = SceneAudioNotifyOuterClass.SceneAudioNotify.newBuilder()
|
SceneAudioNotifyOuterClass.SceneAudioNotify proto =
|
||||||
.setSourceUid(sourceUid)
|
SceneAudioNotifyOuterClass.SceneAudioNotify.newBuilder()
|
||||||
.addAllParam2(param2)
|
.setSourceUid(sourceUid)
|
||||||
.addAllParam3(param3)
|
.addAllParam2(param2)
|
||||||
.setType(type)
|
.addAllParam3(param3)
|
||||||
.addAllParam1(param1)
|
.setType(type)
|
||||||
.build();
|
.addAllParam1(param1)
|
||||||
|
.build();
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,10 @@ public final class PacketServerGlobalValueChangeNotify extends BasePacket {
|
|||||||
public PacketServerGlobalValueChangeNotify(GameEntity entity, String abilityHash, int value) {
|
public PacketServerGlobalValueChangeNotify(GameEntity entity, String abilityHash, int value) {
|
||||||
super(PacketOpcodes.ServerGlobalValueChangeNotify);
|
super(PacketOpcodes.ServerGlobalValueChangeNotify);
|
||||||
|
|
||||||
this.setData(ServerGlobalValueChangeNotify.newBuilder()
|
this.setData(
|
||||||
.setEntityId(entity.getId()).setValue(value)
|
ServerGlobalValueChangeNotify.newBuilder()
|
||||||
.setKeyHash(Utils.abilityHash(abilityHash)));
|
.setEntityId(entity.getId())
|
||||||
|
.setValue(value)
|
||||||
|
.setKeyHash(Utils.abilityHash(abilityHash)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,14 @@ import emu.grasscutter.net.packet.PacketOpcodes;
|
|||||||
import emu.grasscutter.net.proto.WorldChestOpenNotifyOuterClass.WorldChestOpenNotify;
|
import emu.grasscutter.net.proto.WorldChestOpenNotifyOuterClass.WorldChestOpenNotify;
|
||||||
|
|
||||||
public class PacketWorldChestOpenNotify extends BasePacket {
|
public class PacketWorldChestOpenNotify extends BasePacket {
|
||||||
public PacketWorldChestOpenNotify(int groupId,int sceneId,int configId){
|
public PacketWorldChestOpenNotify(int groupId, int sceneId, int configId) {
|
||||||
super(PacketOpcodes.WorldChestOpenNotify);
|
super(PacketOpcodes.WorldChestOpenNotify);
|
||||||
|
|
||||||
this.setData(WorldChestOpenNotify.newBuilder()
|
this.setData(
|
||||||
.setGroupId(groupId)
|
WorldChestOpenNotify.newBuilder()
|
||||||
.setSceneId(sceneId)
|
.setGroupId(groupId)
|
||||||
.setConfigId(configId)
|
.setSceneId(sceneId)
|
||||||
.build());
|
.setConfigId(configId)
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,8 @@ public final class AnnouncementTask extends TaskHandler {
|
|||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
Grasscutter.getGameServer().getAnnouncementSystem().broadcast(toSend);
|
Grasscutter.getGameServer().getAnnouncementSystem().broadcast(toSend);
|
||||||
Grasscutter.getLogger().trace("Broadcast {} announcement(s) to all online players", toSend.size());
|
Grasscutter.getLogger()
|
||||||
|
.trace("Broadcast {} announcement(s) to all online players", toSend.size());
|
||||||
|
|
||||||
// clear the interval count
|
// clear the interval count
|
||||||
toSend.forEach(i -> intervalMap.put(i.getTemplateId(), 0));
|
toSend.forEach(i -> intervalMap.put(i.getTemplateId(), 0));
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package emu.grasscutter.utils;
|
package emu.grasscutter.utils;
|
||||||
|
|
||||||
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.server.http.objects.QueryCurRegionRspJson;
|
import emu.grasscutter.server.http.objects.QueryCurRegionRspJson;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.security.KeyFactory;
|
import java.security.KeyFactory;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
@ -12,11 +12,9 @@ import java.security.Signature;
|
|||||||
import java.security.spec.PKCS8EncodedKeySpec;
|
import java.security.spec.PKCS8EncodedKeySpec;
|
||||||
import java.security.spec.X509EncodedKeySpec;
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
|
|
||||||
public final class Crypto {
|
public final class Crypto {
|
||||||
@ -42,8 +40,10 @@ public final class Crypto {
|
|||||||
ENCRYPT_SEED_BUFFER = FileUtils.readResource("/keys/secretKeyBuffer.bin");
|
ENCRYPT_SEED_BUFFER = FileUtils.readResource("/keys/secretKeyBuffer.bin");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CUR_SIGNING_KEY = KeyFactory.getInstance("RSA")
|
CUR_SIGNING_KEY =
|
||||||
.generatePrivate(new PKCS8EncodedKeySpec(FileUtils.readResource("/keys/SigningKey.der")));
|
KeyFactory.getInstance("RSA")
|
||||||
|
.generatePrivate(
|
||||||
|
new PKCS8EncodedKeySpec(FileUtils.readResource("/keys/SigningKey.der")));
|
||||||
|
|
||||||
Pattern pattern = Pattern.compile("([0-9]*)_Pub\\.der");
|
Pattern pattern = Pattern.compile("([0-9]*)_Pub\\.der");
|
||||||
for (Path path : FileUtils.getPathsFromResource("/keys/game_keys")) {
|
for (Path path : FileUtils.getPathsFromResource("/keys/game_keys")) {
|
||||||
@ -52,8 +52,9 @@ public final class Crypto {
|
|||||||
var m = pattern.matcher(path.getFileName().toString());
|
var m = pattern.matcher(path.getFileName().toString());
|
||||||
|
|
||||||
if (m.matches()) {
|
if (m.matches()) {
|
||||||
var key = KeyFactory.getInstance("RSA")
|
var key =
|
||||||
.generatePublic(new X509EncodedKeySpec(FileUtils.read(path)));
|
KeyFactory.getInstance("RSA")
|
||||||
|
.generatePublic(new X509EncodedKeySpec(FileUtils.read(path)));
|
||||||
|
|
||||||
EncryptionKeys.put(Integer.valueOf(m.group(1)), key);
|
EncryptionKeys.put(Integer.valueOf(m.group(1)), key);
|
||||||
}
|
}
|
||||||
@ -80,7 +81,8 @@ public final class Crypto {
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static QueryCurRegionRspJson encryptAndSignRegionData(byte[] regionInfo, String key_id) throws Exception {
|
public static QueryCurRegionRspJson encryptAndSignRegionData(byte[] regionInfo, String key_id)
|
||||||
|
throws Exception {
|
||||||
if (key_id == null) {
|
if (key_id == null) {
|
||||||
throw new Exception("Key ID was not set");
|
throw new Exception("Key ID was not set");
|
||||||
}
|
}
|
||||||
@ -88,17 +90,18 @@ public final class Crypto {
|
|||||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, EncryptionKeys.get(Integer.valueOf(key_id)));
|
cipher.init(Cipher.ENCRYPT_MODE, EncryptionKeys.get(Integer.valueOf(key_id)));
|
||||||
|
|
||||||
//Encrypt regionInfo in chunks
|
// Encrypt regionInfo in chunks
|
||||||
ByteArrayOutputStream encryptedRegionInfoStream = new ByteArrayOutputStream();
|
ByteArrayOutputStream encryptedRegionInfoStream = new ByteArrayOutputStream();
|
||||||
|
|
||||||
//Thank you so much GH Copilot
|
// Thank you so much GH Copilot
|
||||||
int chunkSize = 256 - 11;
|
int chunkSize = 256 - 11;
|
||||||
int regionInfoLength = regionInfo.length;
|
int regionInfoLength = regionInfo.length;
|
||||||
int numChunks = (int) Math.ceil(regionInfoLength / (double) chunkSize);
|
int numChunks = (int) Math.ceil(regionInfoLength / (double) chunkSize);
|
||||||
|
|
||||||
for (int i = 0; i < numChunks; i++) {
|
for (int i = 0; i < numChunks; i++) {
|
||||||
byte[] chunk = Arrays.copyOfRange(regionInfo, i * chunkSize,
|
byte[] chunk =
|
||||||
Math.min((i + 1) * chunkSize, regionInfoLength));
|
Arrays.copyOfRange(
|
||||||
|
regionInfo, i * chunkSize, Math.min((i + 1) * chunkSize, regionInfoLength));
|
||||||
byte[] encryptedChunk = cipher.doFinal(chunk);
|
byte[] encryptedChunk = cipher.doFinal(chunk);
|
||||||
encryptedRegionInfoStream.write(encryptedChunk);
|
encryptedRegionInfoStream.write(encryptedChunk);
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package emu.grasscutter.utils;
|
package emu.grasscutter.utils;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.FALLBACK_LANGUAGE;
|
import static emu.grasscutter.config.Configuration.FALLBACK_LANGUAGE;
|
||||||
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
|
||||||
import static emu.grasscutter.utils.FileUtils.getCachePath;
|
import static emu.grasscutter.utils.FileUtils.getCachePath;
|
||||||
|
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
@ -19,7 +19,6 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.FileAlreadyExistsException;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.StandardOpenOption;
|
import java.nio.file.StandardOpenOption;
|
||||||
@ -290,8 +289,10 @@ public final class Language {
|
|||||||
|
|
||||||
private static void saveTextMapsCache(Int2ObjectMap<TextStrings> input) throws IOException {
|
private static void saveTextMapsCache(Int2ObjectMap<TextStrings> input) throws IOException {
|
||||||
Files.createDirectories(TEXTMAP_CACHE_PATH.getParent());
|
Files.createDirectories(TEXTMAP_CACHE_PATH.getParent());
|
||||||
try (var file = new ObjectOutputStream(new BufferedOutputStream(
|
try (var file =
|
||||||
Files.newOutputStream(TEXTMAP_CACHE_PATH, StandardOpenOption.CREATE), 0x100000))) {
|
new ObjectOutputStream(
|
||||||
|
new BufferedOutputStream(
|
||||||
|
Files.newOutputStream(TEXTMAP_CACHE_PATH, StandardOpenOption.CREATE), 0x100000))) {
|
||||||
file.writeInt(TEXTMAP_CACHE_VERSION);
|
file.writeInt(TEXTMAP_CACHE_VERSION);
|
||||||
file.writeObject(input);
|
file.writeObject(input);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user