mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-02-11 14:13:20 +08:00
Continue updating/refactoring classes
Most code is matched from `Grasscutter-Quests`.
This commit is contained in:
parent
772532515e
commit
9fbb7fb3be
@ -117,7 +117,7 @@ public final class EntityCommand implements CommandHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void callHPEvents(GameEntity entity, EntityDamageEvent event) {
|
private void callHPEvents(GameEntity entity, EntityDamageEvent event) {
|
||||||
entity.callLuaHPEvent(event);
|
entity.runLuaCallbacks(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setFightProperty(
|
private void setFightProperty(
|
||||||
|
@ -180,9 +180,9 @@ public final class SetPropCommand implements CommandHandler {
|
|||||||
private boolean setBool(Player sender, Player targetPlayer, PseudoProp pseudoProp, int value) {
|
private boolean setBool(Player sender, Player targetPlayer, PseudoProp pseudoProp, int value) {
|
||||||
boolean enabled =
|
boolean enabled =
|
||||||
switch (pseudoProp) {
|
switch (pseudoProp) {
|
||||||
case GOD_MODE -> targetPlayer.inGodmode();
|
case GOD_MODE -> targetPlayer.isInGodMode();
|
||||||
case UNLIMITED_STAMINA -> targetPlayer.getUnlimitedStamina();
|
case UNLIMITED_STAMINA -> targetPlayer.isUnlimitedStamina();
|
||||||
case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().getEnergyUsage();
|
case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().isEnergyUsage();
|
||||||
default -> false;
|
default -> false;
|
||||||
};
|
};
|
||||||
enabled =
|
enabled =
|
||||||
@ -194,7 +194,7 @@ public final class SetPropCommand implements CommandHandler {
|
|||||||
|
|
||||||
switch (pseudoProp) {
|
switch (pseudoProp) {
|
||||||
case GOD_MODE:
|
case GOD_MODE:
|
||||||
targetPlayer.setGodmode(enabled);
|
targetPlayer.setInGodMode(enabled);
|
||||||
break;
|
break;
|
||||||
case UNLIMITED_STAMINA:
|
case UNLIMITED_STAMINA:
|
||||||
targetPlayer.setUnlimitedStamina(enabled);
|
targetPlayer.setUnlimitedStamina(enabled);
|
||||||
|
@ -6,11 +6,12 @@ import emu.grasscutter.Grasscutter;
|
|||||||
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
||||||
import emu.grasscutter.Grasscutter.ServerRunMode;
|
import emu.grasscutter.Grasscutter.ServerRunMode;
|
||||||
import emu.grasscutter.utils.JsonUtils;
|
import emu.grasscutter.utils.JsonUtils;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static emu.grasscutter.Grasscutter.config;
|
import static emu.grasscutter.Grasscutter.config;
|
||||||
|
|
||||||
@ -18,14 +19,6 @@ import static emu.grasscutter.Grasscutter.config;
|
|||||||
* *when your JVM fails*
|
* *when your JVM fails*
|
||||||
*/
|
*/
|
||||||
public class ConfigContainer {
|
public class ConfigContainer {
|
||||||
public Structure folderStructure = new Structure();
|
|
||||||
public Database databaseInfo = new Database();
|
|
||||||
public Language language = new Language();
|
|
||||||
public Account account = new Account();
|
|
||||||
public Server server = new Server();
|
|
||||||
// DO NOT. TOUCH. THE VERSION NUMBER.
|
|
||||||
public int version = version();
|
|
||||||
|
|
||||||
private static int version() {
|
private static int version() {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
@ -40,8 +33,7 @@ public class ConfigContainer {
|
|||||||
Grasscutter.getLogger().info("Updating legacy ..");
|
Grasscutter.getLogger().info("Updating legacy ..");
|
||||||
Grasscutter.saveConfig(null);
|
Grasscutter.saveConfig(null);
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) { }
|
||||||
}
|
|
||||||
|
|
||||||
var existing = config.version;
|
var existing = config.version;
|
||||||
var latest = version();
|
var latest = version();
|
||||||
@ -59,8 +51,7 @@ public class ConfigContainer {
|
|||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
Grasscutter.getLogger().error("Failed to update a configuration field.", exception);
|
Grasscutter.getLogger().error("Failed to update a configuration field.", exception);
|
||||||
}
|
}
|
||||||
});
|
}); updated.version = version();
|
||||||
updated.version = version();
|
|
||||||
|
|
||||||
try { // Save configuration & reload.
|
try { // Save configuration & reload.
|
||||||
Grasscutter.saveConfig(updated);
|
Grasscutter.saveConfig(updated);
|
||||||
@ -70,6 +61,15 @@ public class ConfigContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Structure folderStructure = new Structure();
|
||||||
|
public Database databaseInfo = new Database();
|
||||||
|
public Language language = new Language();
|
||||||
|
public Account account = new Account();
|
||||||
|
public Server server = new Server();
|
||||||
|
|
||||||
|
// DO NOT. TOUCH. THE VERSION NUMBER.
|
||||||
|
public int version = version();
|
||||||
|
|
||||||
/* Option containers. */
|
/* Option containers. */
|
||||||
|
|
||||||
public static class Database {
|
public static class Database {
|
||||||
@ -145,7 +145,7 @@ public class ConfigContainer {
|
|||||||
public int accessPort = 0;
|
public int accessPort = 0;
|
||||||
|
|
||||||
/* Entities within a certain range will be loaded for the player */
|
/* Entities within a certain range will be loaded for the player */
|
||||||
public int loadEntitiesForPlayerRange = 100;
|
public int loadEntitiesForPlayerRange = 300;
|
||||||
public boolean enableScriptInBigWorld = false;
|
public boolean enableScriptInBigWorld = false;
|
||||||
public boolean enableConsole = true;
|
public boolean enableConsole = true;
|
||||||
|
|
||||||
@ -154,13 +154,24 @@ public class ConfigContainer {
|
|||||||
/* Controls whether packets should be logged in console or not */
|
/* Controls whether packets should be logged in console or not */
|
||||||
public ServerDebugMode logPackets = ServerDebugMode.NONE;
|
public ServerDebugMode logPackets = ServerDebugMode.NONE;
|
||||||
/* Show packet payload in console or no (in any case the payload is shown in encrypted view) */
|
/* Show packet payload in console or no (in any case the payload is shown in encrypted view) */
|
||||||
public Boolean isShowPacketPayload = false;
|
public boolean isShowPacketPayload = false;
|
||||||
/* Show annoying loop packets or no */
|
/* Show annoying loop packets or no */
|
||||||
public Boolean isShowLoopPackets = false;
|
public boolean isShowLoopPackets = false;
|
||||||
|
|
||||||
|
public boolean cacheSceneEntitiesEveryRun = false;
|
||||||
|
|
||||||
public GameOptions gameOptions = new GameOptions();
|
public GameOptions gameOptions = new GameOptions();
|
||||||
public JoinOptions joinOptions = new JoinOptions();
|
public JoinOptions joinOptions = new JoinOptions();
|
||||||
public ConsoleAccount serverAccount = new ConsoleAccount();
|
public ConsoleAccount serverAccount = new ConsoleAccount();
|
||||||
|
|
||||||
|
public VisionOptions[] visionOptions = new VisionOptions[] {
|
||||||
|
new VisionOptions("VISION_LEVEL_NORMAL" , 80 , 20),
|
||||||
|
new VisionOptions("VISION_LEVEL_LITTLE_REMOTE" , 16 , 40),
|
||||||
|
new VisionOptions("VISION_LEVEL_REMOTE" , 1000 , 250),
|
||||||
|
new VisionOptions("VISION_LEVEL_SUPER" , 4000 , 1000),
|
||||||
|
new VisionOptions("VISION_LEVEL_NEARBY" , 40 , 20),
|
||||||
|
new VisionOptions("VISION_LEVEL_SUPER_NEARBY" , 20 , 20)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Data containers. */
|
/* Data containers. */
|
||||||
@ -188,10 +199,10 @@ public class ConfigContainer {
|
|||||||
public ServerDebugMode logPackets = ServerDebugMode.ALL;
|
public ServerDebugMode logPackets = ServerDebugMode.ALL;
|
||||||
|
|
||||||
/* Show packet payload in console or no (in any case the payload is shown in encrypted view) */
|
/* Show packet payload in console or no (in any case the payload is shown in encrypted view) */
|
||||||
public Boolean isShowPacketPayload = false;
|
public boolean isShowPacketPayload = false;
|
||||||
|
|
||||||
/* Show annoying loop packets or no */
|
/* Show annoying loop packets or no */
|
||||||
public Boolean isShowLoopPackets = false;
|
public boolean isShowLoopPackets = false;
|
||||||
|
|
||||||
/* Controls whether http requests should be logged in console or not */
|
/* Controls whether http requests should be logged in console or not */
|
||||||
public ServerDebugMode logRequests = ServerDebugMode.ALL;
|
public ServerDebugMode logRequests = ServerDebugMode.ALL;
|
||||||
@ -224,6 +235,7 @@ public class ConfigContainer {
|
|||||||
public boolean staminaUsage = true;
|
public boolean staminaUsage = true;
|
||||||
public boolean energyUsage = true;
|
public boolean energyUsage = true;
|
||||||
public boolean fishhookTeleport = true;
|
public boolean fishhookTeleport = true;
|
||||||
|
public boolean questing = false;
|
||||||
public ResinOptions resinOptions = new ResinOptions();
|
public ResinOptions resinOptions = new ResinOptions();
|
||||||
public Rates rates = new Rates();
|
public Rates rates = new Rates();
|
||||||
|
|
||||||
@ -253,6 +265,18 @@ public class ConfigContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class VisionOptions {
|
||||||
|
public String name;
|
||||||
|
public int visionRange;
|
||||||
|
public int gridWidth;
|
||||||
|
|
||||||
|
public VisionOptions(String name, int visionRange, int gridWidth) {
|
||||||
|
this.name = name;
|
||||||
|
this.visionRange = visionRange;
|
||||||
|
this.gridWidth = gridWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class JoinOptions {
|
public static class JoinOptions {
|
||||||
public int[] welcomeEmotes = {2007, 1002, 4010};
|
public int[] welcomeEmotes = {2007, 1002, 4010};
|
||||||
public String welcomeMessage = "Welcome to a Grasscutter server.";
|
public String welcomeMessage = "Welcome to a Grasscutter server.";
|
||||||
@ -292,13 +316,13 @@ public class ConfigContainer {
|
|||||||
|
|
||||||
/* Objects. */
|
/* Objects. */
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
public static class Region {
|
public static class Region {
|
||||||
public String Name = "os_usa";
|
public String Name = "os_usa";
|
||||||
public String Title = "Grasscutter";
|
public String Title = "Grasscutter";
|
||||||
public String Ip = "127.0.0.1";
|
public String Ip = "127.0.0.1";
|
||||||
public int Port = 22102;
|
public int Port = 22102;
|
||||||
public Region() {
|
|
||||||
}
|
|
||||||
public Region(
|
public Region(
|
||||||
String name, String title,
|
String name, String title,
|
||||||
String address, int port
|
String address, int port
|
||||||
|
@ -48,7 +48,10 @@ public final class GameData {
|
|||||||
@Getter
|
@Getter
|
||||||
private static final Map<String, AbilityModifierEntry> abilityModifiers = new HashMap<>();
|
private static final Map<String, AbilityModifierEntry> abilityModifiers = new HashMap<>();
|
||||||
|
|
||||||
@Getter private static final Map<String, ConfigGadget> gadgetConfigData = new HashMap<>();
|
@Getter private static final Map<String, ConfigEntityAvatar> avatarConfigData = new HashMap<>();
|
||||||
|
@Getter private static final Map<String, ConfigEntityGadget> gadgetConfigData = new HashMap<>();
|
||||||
|
@Getter private static final Map<String, ConfigEntityMonster> monsterConfigData = new HashMap<>();
|
||||||
|
|
||||||
@Getter private static final Map<String, OpenConfigEntry> openConfigEntries = new HashMap<>();
|
@Getter private static final Map<String, OpenConfigEntry> openConfigEntries = new HashMap<>();
|
||||||
|
|
||||||
private static final Int2ObjectMap<MainQuestData> mainQuestData = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<MainQuestData> mainQuestData = new Int2ObjectOpenHashMap<>();
|
||||||
@ -102,6 +105,8 @@ public final class GameData {
|
|||||||
private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataMap =
|
private static final Int2ObjectMap<AvatarCostumeData> avatarCostumeDataMap =
|
||||||
new Int2ObjectLinkedOpenHashMap<>();
|
new Int2ObjectLinkedOpenHashMap<>();
|
||||||
|
|
||||||
|
@Getter private static final Int2ObjectMap<AvatarReplaceCostumeData> avatarReplaceCostumeDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<AvatarCurveData> avatarCurveDataMap =
|
private static final Int2ObjectMap<AvatarCurveData> avatarCurveDataMap =
|
||||||
new Int2ObjectLinkedOpenHashMap<>();
|
new Int2ObjectLinkedOpenHashMap<>();
|
||||||
@ -221,6 +226,8 @@ public final class GameData {
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<GatherData> gatherDataMap = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<GatherData> gatherDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
@Getter @Deprecated // This is to prevent people from using this map. This is for the resource loader only!
|
||||||
|
private static final Int2ObjectMap<GuideTriggerData> guideTriggerDataMap = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<HomeWorldBgmData> homeWorldBgmDataMap =
|
private static final Int2ObjectMap<HomeWorldBgmData> homeWorldBgmDataMap =
|
||||||
@ -246,6 +253,8 @@ public final class GameData {
|
|||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<MonsterDescribeData> monsterDescribeDataMap =
|
private static final Int2ObjectMap<MonsterDescribeData> monsterDescribeDataMap =
|
||||||
new Int2ObjectOpenHashMap<>();
|
new Int2ObjectOpenHashMap<>();
|
||||||
|
@Getter private static final Int2ObjectMap<MonsterSpecialNameData> monsterSpecialNameDataMap =
|
||||||
|
new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<MusicGameBasicData> musicGameBasicDataMap =
|
private static final Int2ObjectMap<MusicGameBasicData> musicGameBasicDataMap =
|
||||||
@ -403,9 +412,8 @@ public final class GameData {
|
|||||||
@Getter private static final List<OpenStateData> openStateList = new ArrayList<>();
|
@Getter private static final List<OpenStateData> openStateList = new ArrayList<>();
|
||||||
@Getter private static final Map<Integer, List<Integer>> scenePointsPerScene = new HashMap<>();
|
@Getter private static final Map<Integer, List<Integer>> scenePointsPerScene = new HashMap<>();
|
||||||
@Getter private static final Map<String, ScriptSceneData> scriptSceneDataMap = new HashMap<>();
|
@Getter private static final Map<String, ScriptSceneData> scriptSceneDataMap = new HashMap<>();
|
||||||
|
@Getter private static final Map<String, GuideTriggerData> guideTriggerDataStringMap = new HashMap<>();
|
||||||
@Getter
|
@Getter private static final Map<String, ConfigLevelEntity> configLevelEntityDataMap = new HashMap<>();
|
||||||
private static final Map<String, ConfigLevelEntity> configLevelEntityDataMap = new HashMap<>();
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final Int2ObjectMap<IntSet> proudSkillGroupLevels = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<IntSet> proudSkillGroupLevels = new Int2ObjectOpenHashMap<>();
|
||||||
|
@ -8,6 +8,10 @@ import com.google.gson.annotations.SerializedName;
|
|||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.data.binout.*;
|
import emu.grasscutter.data.binout.*;
|
||||||
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
|
import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction;
|
||||||
|
import emu.grasscutter.data.binout.config.ConfigEntityAvatar;
|
||||||
|
import emu.grasscutter.data.binout.config.ConfigEntityBase;
|
||||||
|
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
||||||
|
import emu.grasscutter.data.binout.config.ConfigEntityMonster;
|
||||||
import emu.grasscutter.data.common.PointData;
|
import emu.grasscutter.data.common.PointData;
|
||||||
import emu.grasscutter.game.managers.blossom.BlossomConfig;
|
import emu.grasscutter.game.managers.blossom.BlossomConfig;
|
||||||
import emu.grasscutter.game.quest.QuestEncryptionKey;
|
import emu.grasscutter.game.quest.QuestEncryptionKey;
|
||||||
@ -85,6 +89,7 @@ public class ResourceLoader {
|
|||||||
if (loadedAll) return;
|
if (loadedAll) return;
|
||||||
Grasscutter.getLogger().info(translate("messages.status.resources.loading"));
|
Grasscutter.getLogger().info(translate("messages.status.resources.loading"));
|
||||||
|
|
||||||
|
loadConfigData();
|
||||||
// Load ability lists
|
// Load ability lists
|
||||||
loadAbilityEmbryos();
|
loadAbilityEmbryos();
|
||||||
loadOpenConfig();
|
loadOpenConfig();
|
||||||
@ -94,7 +99,6 @@ public class ResourceLoader {
|
|||||||
// Process into depots
|
// Process into depots
|
||||||
GameDepot.load();
|
GameDepot.load();
|
||||||
// Load spawn data and quests
|
// Load spawn data and quests
|
||||||
loadGadgetConfigData();
|
|
||||||
loadSpawnData();
|
loadSpawnData();
|
||||||
loadQuests();
|
loadQuests();
|
||||||
loadScriptSceneData();
|
loadScriptSceneData();
|
||||||
@ -575,24 +579,44 @@ public class ResourceLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadGadgetConfigData() {
|
private static void loadConfigData(){
|
||||||
|
loadConfigData(GameData.getAvatarConfigData(), "BinOutput/Avatar/", ConfigEntityAvatar.class);
|
||||||
|
loadConfigData(GameData.getMonsterConfigData(), "BinOutput/Monster/", ConfigEntityMonster.class);
|
||||||
|
loadConfigDataMap(GameData.getGadgetConfigData(), "BinOutput/Gadget/", ConfigEntityGadget.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends ConfigEntityBase> void loadConfigData(Map<String,T> targetMap, String folderPath, Class<T> configClass) {
|
||||||
|
val className = configClass.getName();
|
||||||
|
try(val stream = Files.newDirectoryStream(getResourcePath(folderPath), "*.json")) {
|
||||||
|
stream.forEach(path -> {
|
||||||
try {
|
try {
|
||||||
Files.newDirectoryStream(getResourcePath("BinOutput/Gadget/"), "*.json")
|
val name = path.getFileName().toString().replace(".json", "");
|
||||||
.forEach(
|
targetMap.put(name, JsonUtils.loadToClass(path, configClass));
|
||||||
path -> {
|
|
||||||
try {
|
|
||||||
GameData.getGadgetConfigData()
|
|
||||||
.putAll(JsonUtils.loadToMap(path, String.class, ConfigGadget.class));
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger()
|
Grasscutter.getLogger().error("failed to load {} entries for {}", className, path.toString(), e);
|
||||||
.error("failed to load ConfigGadget entries for " + path.toString(), e);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Grasscutter.getLogger()
|
Grasscutter.getLogger().debug("Loaded {} {} entries.", GameData.getMonsterConfigData().size(), className);
|
||||||
.debug("Loaded {} ConfigGadget entries.", GameData.getGadgetConfigData().size());
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Grasscutter.getLogger().error("Failed to load ConfigGadget folder.");
|
Grasscutter.getLogger().error("Failed to load {} folder.", className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends ConfigEntityBase> void loadConfigDataMap(Map<String,T> targetMap, String folderPath, Class<T> configClass) {
|
||||||
|
val className = configClass.getName();
|
||||||
|
try(val stream = Files.newDirectoryStream(getResourcePath(folderPath), "*.json")) {
|
||||||
|
stream.forEach(path -> {
|
||||||
|
try {
|
||||||
|
targetMap.putAll(JsonUtils.loadToMap(path, String.class, configClass));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Grasscutter.getLogger().error("failed to load {} entries for {}", className, path.toString(), e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Grasscutter.getLogger().debug("Loaded {} {} entries.", GameData.getMonsterConfigData().size(), className);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Grasscutter.getLogger().error("Failed to load {} folder.", className);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package emu.grasscutter.data.common;
|
package emu.grasscutter.data.common;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.excels.dungeon.DailyDungeonData;
|
import emu.grasscutter.data.excels.dungeon.DailyDungeonData;
|
||||||
@ -10,29 +11,25 @@ import it.unimi.dsi.fastutil.ints.IntList;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
public class PointData {
|
public final class PointData {
|
||||||
@Getter @Setter private int id;
|
@Getter @Setter private int id;
|
||||||
private String $type;
|
private String $type;
|
||||||
@Getter private Position tranPos;
|
@Getter private Position tranPos;
|
||||||
|
@Getter private Position pos;
|
||||||
|
@Getter private Position rot;
|
||||||
|
@Getter private Position size;
|
||||||
|
|
||||||
@SerializedName(
|
@SerializedName(value="dungeonIds", alternate={"JHHFPGJNMIN"})
|
||||||
value = "dungeonIds",
|
@Getter private int[] dungeonIds;
|
||||||
alternate = {"JHHFPGJNMIN"})
|
|
||||||
@Getter
|
|
||||||
private int[] dungeonIds;
|
|
||||||
|
|
||||||
@SerializedName(
|
@SerializedName(value="dungeonRandomList", alternate={"OIBKFJNBLHO"})
|
||||||
value = "dungeonRandomList",
|
@Getter private int[] dungeonRandomList;
|
||||||
alternate = {"OIBKFJNBLHO"})
|
|
||||||
@Getter
|
|
||||||
private int[] dungeonRandomList;
|
|
||||||
|
|
||||||
@SerializedName(
|
@SerializedName(value="groupIDs", alternate={"HFOBOOHKBGF"})
|
||||||
value = "tranSceneId",
|
@Getter private int[] groupIDs;
|
||||||
alternate = {"JHBICGBAPIH"})
|
|
||||||
@Getter
|
@SerializedName(value="tranSceneId", alternate={"JHBICGBAPIH"})
|
||||||
@Setter
|
@Getter @Setter private int tranSceneId;
|
||||||
private int tranSceneId;
|
|
||||||
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return $type;
|
return $type;
|
||||||
|
@ -7,7 +7,7 @@ import lombok.Getter;
|
|||||||
|
|
||||||
@ResourceType(name = "GadgetExcelConfigData.json")
|
@ResourceType(name = "GadgetExcelConfigData.json")
|
||||||
@Getter
|
@Getter
|
||||||
public class GadgetData extends GameResource {
|
public final class GadgetData extends GameResource {
|
||||||
@Getter(onMethod_ = @Override)
|
@Getter(onMethod_ = @Override)
|
||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
@ -17,5 +17,6 @@ public class GadgetData extends GameResource {
|
|||||||
private String[] tags;
|
private String[] tags;
|
||||||
private String itemJsonName;
|
private String itemJsonName;
|
||||||
private long nameTextMapHash;
|
private long nameTextMapHash;
|
||||||
private int campID;
|
private int campId;
|
||||||
|
private String visionLevel;
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ public class AvatarData extends GameResource {
|
|||||||
@Getter
|
@Getter
|
||||||
private int staminaRecoverSpeed;
|
private int staminaRecoverSpeed;
|
||||||
@Getter
|
@Getter
|
||||||
private List<String> candSkillDepotIds;
|
private List<Integer> candSkillDepotIds;
|
||||||
@Getter
|
@Getter
|
||||||
private String avatarIdentityType;
|
private String avatarIdentityType;
|
||||||
@Getter
|
@Getter
|
||||||
|
@ -1,6 +1,11 @@
|
|||||||
package emu.grasscutter.data.excels.monster;
|
package emu.grasscutter.data.excels.monster;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.GameResource;
|
import emu.grasscutter.data.GameResource;
|
||||||
import emu.grasscutter.data.ResourceType;
|
import emu.grasscutter.data.ResourceType;
|
||||||
@ -9,26 +14,12 @@ import emu.grasscutter.data.common.PropGrowCurve;
|
|||||||
import emu.grasscutter.data.excels.GadgetData;
|
import emu.grasscutter.data.excels.GadgetData;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.props.MonsterType;
|
import emu.grasscutter.game.props.MonsterType;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@ResourceType(name = "MonsterExcelConfigData.json", loadPriority = LoadPriority.LOW)
|
@ResourceType(name = "MonsterExcelConfigData.json", loadPriority = LoadPriority.LOW)
|
||||||
@Getter
|
@Getter
|
||||||
public class MonsterData extends GameResource {
|
public class MonsterData extends GameResource {
|
||||||
public static Set<FightProperty> definedFightProperties =
|
static public Set<FightProperty> definedFightProperties = Set.of(FightProperty.FIGHT_PROP_BASE_HP, FightProperty.FIGHT_PROP_BASE_ATTACK, FightProperty.FIGHT_PROP_BASE_DEFENSE, FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, FightProperty.FIGHT_PROP_FIRE_SUB_HURT, FightProperty.FIGHT_PROP_ELEC_SUB_HURT, FightProperty.FIGHT_PROP_WATER_SUB_HURT, FightProperty.FIGHT_PROP_GRASS_SUB_HURT, FightProperty.FIGHT_PROP_WIND_SUB_HURT, FightProperty.FIGHT_PROP_ROCK_SUB_HURT, FightProperty.FIGHT_PROP_ICE_SUB_HURT);
|
||||||
Set.of(
|
|
||||||
FightProperty.FIGHT_PROP_BASE_HP,
|
|
||||||
FightProperty.FIGHT_PROP_BASE_ATTACK,
|
|
||||||
FightProperty.FIGHT_PROP_BASE_DEFENSE,
|
|
||||||
FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT,
|
|
||||||
FightProperty.FIGHT_PROP_FIRE_SUB_HURT,
|
|
||||||
FightProperty.FIGHT_PROP_ELEC_SUB_HURT,
|
|
||||||
FightProperty.FIGHT_PROP_WATER_SUB_HURT,
|
|
||||||
FightProperty.FIGHT_PROP_GRASS_SUB_HURT,
|
|
||||||
FightProperty.FIGHT_PROP_WIND_SUB_HURT,
|
|
||||||
FightProperty.FIGHT_PROP_ROCK_SUB_HURT,
|
|
||||||
FightProperty.FIGHT_PROP_ICE_SUB_HURT);
|
|
||||||
|
|
||||||
@Getter(onMethod_ = @Override)
|
@Getter(onMethod_ = @Override)
|
||||||
private int id;
|
private int id;
|
||||||
@ -51,10 +42,8 @@ public class MonsterData extends GameResource {
|
|||||||
|
|
||||||
@SerializedName("hpBase")
|
@SerializedName("hpBase")
|
||||||
private float baseHp;
|
private float baseHp;
|
||||||
|
|
||||||
@SerializedName("attackBase")
|
@SerializedName("attackBase")
|
||||||
private float baseAttack;
|
private float baseAttack;
|
||||||
|
|
||||||
@SerializedName("defenseBase")
|
@SerializedName("defenseBase")
|
||||||
private float baseDefense;
|
private float baseDefense;
|
||||||
|
|
||||||
@ -74,6 +63,38 @@ public class MonsterData extends GameResource {
|
|||||||
private int weaponId;
|
private int weaponId;
|
||||||
private MonsterDescribeData describeData;
|
private MonsterDescribeData describeData;
|
||||||
|
|
||||||
|
private int specialNameId; // will only be set if describe data is available
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLoad() {
|
||||||
|
for (int id : this.equips) {
|
||||||
|
if (id == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GadgetData gadget = GameData.getGadgetDataMap().get(id);
|
||||||
|
if (gadget == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gadget.getItemJsonName().equals("Default_MonsterWeapon")) {
|
||||||
|
this.weaponId = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.describeData = GameData.getMonsterDescribeDataMap().get(this.getDescribeId());
|
||||||
|
|
||||||
|
if (this.describeData == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for(Entry<Integer, MonsterSpecialNameData> entry: GameData.getMonsterSpecialNameDataMap().entrySet()) {
|
||||||
|
if (entry.getValue().getSpecialNameLabId() == this.getDescribeData().getSpecialNameLabId()){
|
||||||
|
this.specialNameId = entry.getKey();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public float getFightProperty(FightProperty prop) {
|
public float getFightProperty(FightProperty prop) {
|
||||||
return switch (prop) {
|
return switch (prop) {
|
||||||
case FIGHT_PROP_BASE_HP -> this.baseHp;
|
case FIGHT_PROP_BASE_HP -> this.baseHp;
|
||||||
@ -91,24 +112,6 @@ public class MonsterData extends GameResource {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLoad() {
|
|
||||||
this.describeData = GameData.getMonsterDescribeDataMap().get(this.getDescribeId());
|
|
||||||
|
|
||||||
for (int id : this.equips) {
|
|
||||||
if (id == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
GadgetData gadget = GameData.getGadgetDataMap().get(id);
|
|
||||||
if (gadget == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (gadget.getItemJsonName().equals("Default_MonsterWeapon")) {
|
|
||||||
this.weaponId = id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
public class HpDrops {
|
public class HpDrops {
|
||||||
private int DropId;
|
private int DropId;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package emu.grasscutter.data.excels.monster;
|
package emu.grasscutter.data.excels.monster;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
import emu.grasscutter.data.GameResource;
|
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;
|
||||||
@ -12,6 +13,9 @@ public class MonsterDescribeData extends GameResource {
|
|||||||
private int id;
|
private int id;
|
||||||
|
|
||||||
private long nameTextMapHash;
|
private long nameTextMapHash;
|
||||||
private int titleID;
|
@SerializedName(value = "titleId", alternate={"titleID"})
|
||||||
private int specialNameLabID;
|
private int titleId;
|
||||||
|
@SerializedName(value = "specialNameLabId", alternate={"specialNameLabID"})
|
||||||
|
private int specialNameLabId;
|
||||||
|
private MonsterSpecialNameData specialNameData;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ import emu.grasscutter.game.inventory.GameItem;
|
|||||||
import emu.grasscutter.game.mail.Mail;
|
import emu.grasscutter.game.mail.Mail;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.quest.GameMainQuest;
|
import emu.grasscutter.game.quest.GameMainQuest;
|
||||||
|
import emu.grasscutter.game.world.SceneGroupInstance;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@ -449,4 +451,14 @@ public final class DatabaseHelper {
|
|||||||
public static void saveAchievementData(Achievements achievements) {
|
public static void saveAchievementData(Achievements achievements) {
|
||||||
DatabaseManager.getGameDatastore().save(achievements);
|
DatabaseManager.getGameDatastore().save(achievements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void saveGroupInstance(SceneGroupInstance instance) {
|
||||||
|
DatabaseManager.getGameDatastore().save(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SceneGroupInstance loadGroupInstance(int groupId, Player owner) {
|
||||||
|
return DatabaseManager.getGameDatastore().find(SceneGroupInstance.class)
|
||||||
|
.filter(Filters.and(Filters.eq("ownerUid", owner.getUid()),
|
||||||
|
Filters.eq("groupId", groupId))).first();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,13 @@ public class PlayerActivityData {
|
|||||||
int curProgress;
|
int curProgress;
|
||||||
boolean isTakenReward;
|
boolean isTakenReward;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True when the progress of this watcher has reached the total progress.
|
||||||
|
*/
|
||||||
|
public boolean isFinished(){
|
||||||
|
return this.curProgress >= this.totalProgress;
|
||||||
|
}
|
||||||
|
|
||||||
public static WatcherInfo init(ActivityWatcher watcher) {
|
public static WatcherInfo init(ActivityWatcher watcher) {
|
||||||
return WatcherInfo.of()
|
return WatcherInfo.of()
|
||||||
.watcherId(watcher.getWatcherId())
|
.watcherId(watcher.getWatcherId())
|
||||||
|
@ -49,6 +49,8 @@ import lombok.Setter;
|
|||||||
import lombok.val;
|
import lombok.val;
|
||||||
import org.bson.types.ObjectId;
|
import org.bson.types.ObjectId;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
@Entity(value = "avatars", useDiscriminator = false)
|
@Entity(value = "avatars", useDiscriminator = false)
|
||||||
public class Avatar {
|
public class Avatar {
|
||||||
@Transient @Getter private final Int2ObjectMap<GameItem> equips;
|
@Transient @Getter private final Int2ObjectMap<GameItem> equips;
|
||||||
@ -234,7 +236,23 @@ public class Avatar {
|
|||||||
this.skillDepot = skillDepot; // Used while loading this from the database
|
this.skillDepot = skillDepot; // Used while loading this from the database
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes this avatar's skill depot.
|
||||||
|
* Does not notify the player of the change.
|
||||||
|
*
|
||||||
|
* @param skillDepot The new skill depot.
|
||||||
|
*/
|
||||||
public void setSkillDepotData(AvatarSkillDepotData skillDepot) {
|
public void setSkillDepotData(AvatarSkillDepotData skillDepot) {
|
||||||
|
this.setSkillDepotData(skillDepot, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes this avatar's skill depot.
|
||||||
|
*
|
||||||
|
* @param skillDepot The new skill depot.
|
||||||
|
* @param notify Whether to notify the player of the change.
|
||||||
|
*/
|
||||||
|
public void setSkillDepotData(AvatarSkillDepotData skillDepot, boolean notify) {
|
||||||
// Set id and depot
|
// Set id and depot
|
||||||
this.skillDepotId = skillDepot.getId();
|
this.skillDepotId = skillDepot.getId();
|
||||||
this.skillDepot = skillDepot;
|
this.skillDepot = skillDepot;
|
||||||
@ -251,6 +269,38 @@ public class Avatar {
|
|||||||
.filter(proudSkillId -> GameData.getProudSkillDataMap().containsKey(proudSkillId))
|
.filter(proudSkillId -> GameData.getProudSkillDataMap().containsKey(proudSkillId))
|
||||||
.forEach(proudSkillId -> this.proudSkillList.add(proudSkillId));
|
.forEach(proudSkillId -> this.proudSkillList.add(proudSkillId));
|
||||||
this.recalcStats();
|
this.recalcStats();
|
||||||
|
|
||||||
|
// Send the depot change notification.
|
||||||
|
if (notify) this.owner.sendPacket(new PacketAvatarSkillDepotChangeNotify(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the avatar's element to the target element, if the character has values for it set in the candSkillDepot
|
||||||
|
*
|
||||||
|
* @param elementTypeToChange element to change to
|
||||||
|
* @return false if failed or already using that element, true if it actually changed
|
||||||
|
*/
|
||||||
|
public boolean changeElement(@Nonnull ElementType elementTypeToChange) {
|
||||||
|
var candSkillDepotIdsList = this.avatarData.getCandSkillDepotIds();
|
||||||
|
var candSkillDepotIndex = elementTypeToChange.getDepotIndex();
|
||||||
|
|
||||||
|
// if no candidate skill to change or index out of bound
|
||||||
|
if (candSkillDepotIdsList == null ||
|
||||||
|
candSkillDepotIndex >= candSkillDepotIdsList.size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var candSkillDepotId = candSkillDepotIdsList.get(candSkillDepotIndex);
|
||||||
|
|
||||||
|
// Sanity checks for skill depots
|
||||||
|
val skillDepot = GameData.getAvatarSkillDepotDataMap().get(candSkillDepotId);
|
||||||
|
if (skillDepot == null || skillDepot.getId() == skillDepotId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set skill depot
|
||||||
|
setSkillDepotData(skillDepot, true);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Integer> getFetterList() {
|
public List<Integer> getFetterList() {
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
package emu.grasscutter.game.dungeons;
|
package emu.grasscutter.game.dungeons;
|
||||||
|
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
||||||
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
|
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
|
||||||
import emu.grasscutter.utils.Utils;
|
|
||||||
|
|
||||||
public class BasicDungeonSettleListener implements DungeonSettleListener {
|
public class BasicDungeonSettleListener implements DungeonSettleListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDungeonSettle(Scene scene) {
|
public void onDungeonSettle(DungeonManager dungeonManager, BaseDungeonResult.DungeonEndReason endReason) {
|
||||||
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
|
var scene = dungeonManager.getScene();
|
||||||
scene.broadcastPacket(new PacketDungeonSettleNotify(scene.getChallenge()));
|
var dungeonData = dungeonManager.getDungeonData();
|
||||||
|
var time = scene.getSceneTimeSeconds() - dungeonManager.getStartSceneTime() ;
|
||||||
|
// TODO time taken and chests handling
|
||||||
|
DungeonEndStats stats = new DungeonEndStats(scene.getKilledMonsterCount(), time, 0, endReason);
|
||||||
|
|
||||||
|
scene.broadcastPacket(new PacketDungeonSettleNotify(new BaseDungeonResult(dungeonData, stats)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,20 +24,22 @@ import emu.grasscutter.utils.Position;
|
|||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.IntStream;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
/**
|
import javax.annotation.Nullable;
|
||||||
* TODO handle time limits TODO handle respawn points TODO handle team wipes and respawns TODO check
|
import java.util.*;
|
||||||
* monster level and levelConfigMap
|
import java.util.stream.Collectors;
|
||||||
*/
|
import java.util.stream.IntStream;
|
||||||
public class DungeonManager {
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO handle time limits
|
||||||
|
* TODO handle respawn points
|
||||||
|
* TODO handle team wipes and respawns
|
||||||
|
* TODO check monster level and levelConfigMap
|
||||||
|
*/
|
||||||
|
public final class DungeonManager {
|
||||||
@Getter private final Scene scene;
|
@Getter private final Scene scene;
|
||||||
@Getter private final DungeonData dungeonData;
|
@Getter private final DungeonData dungeonData;
|
||||||
@Getter private final DungeonPassConfigData passConfigData;
|
@Getter private final DungeonPassConfigData passConfigData;
|
||||||
@ -69,12 +71,14 @@ public class DungeonManager {
|
|||||||
if (getScene().getWorld().getServer().getDungeonSystem().triggerCondition(cond, params)) {
|
if (getScene().getWorld().getServer().getDungeonSystem().triggerCondition(cond, params)) {
|
||||||
finishedConditions[i] = 1;
|
finishedConditions[i] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFinishedSuccessfully()) {
|
if (isFinishedSuccessfully()) {
|
||||||
finishDungeon();
|
finishDungeon();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFinishedSuccessfully() {
|
public boolean isFinishedSuccessfully() {
|
||||||
@ -82,7 +86,7 @@ public class DungeonManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getLevelForMonster(int id) {
|
public int getLevelForMonster(int id) {
|
||||||
// TODO should use levelConfigMap? and how?
|
//TODO should use levelConfigMap? and how?
|
||||||
return dungeonData.getShowLevel();
|
return dungeonData.getShowLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,20 +98,19 @@ public class DungeonManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
scene.broadcastPacket(
|
scene.broadcastPacket(new PacketDungeonWayPointNotify(activeDungeonWayPoints.add(pointId), activeDungeonWayPoints));
|
||||||
new PacketDungeonWayPointNotify(
|
|
||||||
activeDungeonWayPoints.add(pointId), activeDungeonWayPoints));
|
|
||||||
newestWayPoint = pointId;
|
newestWayPoint = pointId;
|
||||||
|
|
||||||
Grasscutter.getLogger().debug("[unimplemented respawn] activated respawn point {}", pointId);
|
Grasscutter.getLogger().debug("[unimplemented respawn] activated respawn point {}", pointId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable public Position getRespawnLocation() {
|
@Nullable
|
||||||
|
public Position getRespawnLocation() {
|
||||||
if (newestWayPoint == 0) { // validity is checked before setting it, so if != 0 its always valid
|
if (newestWayPoint == 0) { // validity is checked before setting it, so if != 0 its always valid
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
val pointData = GameData.getScenePointEntryById(scene.getId(), newestWayPoint).getPointData();
|
var pointData = GameData.getScenePointEntryById(scene.getId(), newestWayPoint).getPointData();
|
||||||
return pointData.getTranPos() != null ? pointData.getTranPos() : pointData.getPos();
|
return pointData.getTranPos() != null ? pointData.getTranPos() : pointData.getPos();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,9 +123,7 @@ public class DungeonManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean getStatueDrops(Player player, boolean useCondensed, int groupId) {
|
public boolean getStatueDrops(Player player, boolean useCondensed, int groupId) {
|
||||||
if (!isFinishedSuccessfully()
|
if (!isFinishedSuccessfully() || dungeonData.getRewardPreviewData() == null || dungeonData.getRewardPreviewData().getPreviewItems().length == 0) {
|
||||||
|| dungeonData.getRewardPreviewData() == null
|
|
||||||
|| dungeonData.getRewardPreviewData().getPreviewItems().length == 0) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +132,7 @@ public class DungeonManager {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!handleCost(player, useCondensed)) {
|
if (!handleCost(player, useCondensed)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -196,10 +198,8 @@ public class DungeonManager {
|
|||||||
|
|
||||||
// Roll items for this group.
|
// Roll items for this group.
|
||||||
// Here, we have to handle stacking, or the client will not display results correctly.
|
// Here, we have to handle stacking, or the client will not display results correctly.
|
||||||
// For now, we use the following logic: If the possible drop item are a list of multiple
|
// For now, we use the following logic: If the possible drop item are a list of multiple items,
|
||||||
// items,
|
// we roll them separately. If not, we stack them. This should work out in practice, at least
|
||||||
// we roll them separately. If not, we stack them. This should work out in practice, at
|
|
||||||
// least
|
|
||||||
// for the currently existing set of dungeons.
|
// for the currently existing set of dungeons.
|
||||||
if (entry.getItems().size() == 1) {
|
if (entry.getItems().size() == 1) {
|
||||||
rewards.add(new GameItem(entry.getItems().get(0), amount));
|
rewards.add(new GameItem(entry.getItems().get(0), amount));
|
||||||
@ -207,8 +207,7 @@ public class DungeonManager {
|
|||||||
for (int i = 0; i < amount; i++) {
|
for (int i = 0; i < amount; i++) {
|
||||||
// int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size());
|
// int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size());
|
||||||
// int itemId = entry.getItems().get(itemIndex);
|
// int itemId = entry.getItems().get(itemIndex);
|
||||||
int itemId =
|
int itemId = Utils.drawRandomListElement(entry.getItems(), entry.getItemProbabilities());
|
||||||
Utils.drawRandomListElement(entry.getItems(), entry.getItemProbabilities());
|
|
||||||
rewards.add(new GameItem(itemId, 1));
|
rewards.add(new GameItem(itemId, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,8 +215,7 @@ public class DungeonManager {
|
|||||||
}
|
}
|
||||||
// Otherwise, we fall back to the preview data.
|
// Otherwise, we fall back to the preview data.
|
||||||
else {
|
else {
|
||||||
Grasscutter.getLogger()
|
Grasscutter.getLogger().info("No drop data found or dungeon {}, falling back to preview data ...", dungeonId);
|
||||||
.info("No drop data found or dungeon {}, falling back to preview data ...", dungeonId);
|
|
||||||
for (ItemParamData param : dungeonData.getRewardPreviewData().getPreviewItems()) {
|
for (ItemParamData param : dungeonData.getRewardPreviewData().getPreviewItems()) {
|
||||||
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
|
rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1)));
|
||||||
}
|
}
|
||||||
@ -234,40 +232,32 @@ public class DungeonManager {
|
|||||||
case DUNGEON_ACTIVITY -> {
|
case DUNGEON_ACTIVITY -> {
|
||||||
switch (getDungeonData().getPlayType()) {
|
switch (getDungeonData().getPlayType()) {
|
||||||
case DUNGEON_PLAY_TYPE_TRIAL_AVATAR -> {
|
case DUNGEON_PLAY_TYPE_TRIAL_AVATAR -> {
|
||||||
val activityHandler =
|
val activityHandler = player.getActivityManager()
|
||||||
player
|
.getActivityHandlerAs(ActivityType.NEW_ACTIVITY_TRIAL_AVATAR, TrialAvatarActivityHandler.class);
|
||||||
.getActivityManager()
|
activityHandler.ifPresent(trialAvatarActivityHandler ->
|
||||||
.getActivityHandlerAs(
|
|
||||||
ActivityType.NEW_ACTIVITY_TRIAL_AVATAR, TrialAvatarActivityHandler.class);
|
|
||||||
activityHandler.ifPresent(
|
|
||||||
trialAvatarActivityHandler ->
|
|
||||||
this.trialTeam = trialAvatarActivityHandler.getTrialAvatarDungeonTeam());
|
this.trialTeam = trialAvatarActivityHandler.getTrialAvatarDungeonTeam());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case DUNGEON_ELEMENT_CHALLENGE -> {} // TODO
|
case DUNGEON_ELEMENT_CHALLENGE -> {} // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.trialTeam != null) {
|
if (this.trialTeam != null) {
|
||||||
player.getTeamManager().addTrialAvatars(trialTeam.trialAvatarIds);
|
player.getTeamManager().addTrialAvatars(trialTeam.trialAvatarIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void unsetTrialTeam(Player player) {
|
public void unsetTrialTeam(Player player){
|
||||||
if (this.trialTeam == null) {
|
if (this.trialTeam == null) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
player.getTeamManager().removeTrialAvatar();
|
player.getTeamManager().removeTrialAvatar();
|
||||||
this.trialTeam = null;
|
this.trialTeam = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startDungeon() {
|
public void startDungeon() {
|
||||||
this.startSceneTime = scene.getSceneTimeSeconds();
|
this.startSceneTime = scene.getSceneTimeSeconds();
|
||||||
scene
|
scene.getPlayers().forEach(p -> {
|
||||||
.getPlayers()
|
p.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_ENTER_DUNGEON, dungeonData.getId());
|
||||||
.forEach(
|
|
||||||
p -> {
|
|
||||||
p.getQuestManager()
|
|
||||||
.queueEvent(QuestContent.QUEST_CONTENT_ENTER_DUNGEON, dungeonData.getId());
|
|
||||||
applyTrialTeam(p);
|
applyTrialTeam(p);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -278,16 +268,10 @@ public class DungeonManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void notifyEndDungeon(boolean successfully) {
|
public void notifyEndDungeon(boolean successfully) {
|
||||||
scene
|
scene.getPlayers().forEach(p -> {
|
||||||
.getPlayers()
|
|
||||||
.forEach(
|
|
||||||
p -> {
|
|
||||||
// Quest trigger
|
// Quest trigger
|
||||||
p.getQuestManager()
|
p.getQuestManager().queueEvent(successfully ?
|
||||||
.queueEvent(
|
QuestContent.QUEST_CONTENT_FINISH_DUNGEON : QuestContent.QUEST_CONTENT_FAIL_DUNGEON,
|
||||||
successfully
|
|
||||||
? QuestContent.QUEST_CONTENT_FINISH_DUNGEON
|
|
||||||
: QuestContent.QUEST_CONTENT_FAIL_DUNGEON,
|
|
||||||
dungeonData.getId());
|
dungeonData.getId());
|
||||||
|
|
||||||
// Battle pass trigger
|
// Battle pass trigger
|
||||||
@ -295,9 +279,7 @@ public class DungeonManager {
|
|||||||
p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON);
|
p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
scene
|
scene.getScriptManager().callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0));
|
||||||
.getScriptManager()
|
|
||||||
.callEvent(new ScriptArgs(0, EventType.EVENT_DUNGEON_SETTLE, successfully ? 1 : 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void quitDungeon() {
|
public void quitDungeon() {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package emu.grasscutter.game.dungeons;
|
package emu.grasscutter.game.dungeons;
|
||||||
|
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
||||||
|
|
||||||
public interface DungeonSettleListener {
|
public interface DungeonSettleListener {
|
||||||
void onDungeonSettle(Scene scene);
|
void onDungeonSettle(DungeonManager dungeonManager, BaseDungeonResult.DungeonEndReason endReason);
|
||||||
}
|
}
|
||||||
|
@ -3,27 +3,63 @@ package emu.grasscutter.game.dungeons;
|
|||||||
import emu.grasscutter.GameConstants;
|
import emu.grasscutter.GameConstants;
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
|
import emu.grasscutter.data.binout.ScenePointEntry;
|
||||||
|
import emu.grasscutter.data.excels.dungeon.DungeonData;
|
||||||
|
import emu.grasscutter.data.excels.dungeon.DungeonPassConfigData;
|
||||||
|
import emu.grasscutter.game.dungeons.handlers.DungeonBaseHandler;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.SceneType;
|
import emu.grasscutter.game.props.SceneType;
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
|
||||||
import emu.grasscutter.server.game.BaseGameSystem;
|
import emu.grasscutter.server.game.BaseGameSystem;
|
||||||
import emu.grasscutter.server.game.GameServer;
|
import emu.grasscutter.server.game.GameServer;
|
||||||
import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
|
import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp;
|
||||||
import emu.grasscutter.server.packet.send.PacketPlayerEnterDungeonRsp;
|
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
|
import lombok.val;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public final class DungeonSystem extends BaseGameSystem {
|
public class DungeonSystem extends BaseGameSystem {
|
||||||
private static final BasicDungeonSettleListener basicDungeonSettleObserver =
|
private static final BasicDungeonSettleListener basicDungeonSettleObserver = new BasicDungeonSettleListener();
|
||||||
new BasicDungeonSettleListener();
|
private final Int2ObjectMap<DungeonBaseHandler> passCondHandlers;
|
||||||
|
|
||||||
public DungeonSystem(GameServer server) {
|
public DungeonSystem(GameServer server) {
|
||||||
super(server);
|
super(server);
|
||||||
|
this.passCondHandlers = new Int2ObjectOpenHashMap<>();
|
||||||
|
registerHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerHandlers() {
|
||||||
|
this.registerHandlers(this.passCondHandlers, "emu.grasscutter.game.dungeons.pass_condition", DungeonBaseHandler.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void registerHandlers(Int2ObjectMap<T> map, String packageName, Class<T> clazz) {
|
||||||
|
Reflections reflections = new Reflections(packageName);
|
||||||
|
var handlerClasses = reflections.getSubTypesOf(clazz);
|
||||||
|
|
||||||
|
for (var obj : handlerClasses) {
|
||||||
|
this.registerPacketHandler(map, obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> void registerPacketHandler(Int2ObjectMap<T> map, Class<? extends T> handlerClass) {
|
||||||
|
try {
|
||||||
|
DungeonValue opcode = handlerClass.getAnnotation(DungeonValue.class);
|
||||||
|
|
||||||
|
if (opcode == null || opcode.value() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
map.put(opcode.value().ordinal(), handlerClass.getDeclaredConstructor().newInstance());
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getEntryInfo(Player player, int pointId) {
|
public void getEntryInfo(Player player, int pointId) {
|
||||||
var entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId);
|
ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId);
|
||||||
|
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
// Error
|
// Error
|
||||||
@ -34,82 +70,88 @@ public final class DungeonSystem extends BaseGameSystem {
|
|||||||
player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData()));
|
player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean enterDungeon(Player player, int pointId, int dungeonId) {
|
public boolean triggerCondition(DungeonPassConfigData.DungeonPassCondition condition, int... params) {
|
||||||
var data = GameData.getDungeonDataMap().get(dungeonId);
|
var handler = passCondHandlers.get(condition.getCondType().ordinal());
|
||||||
if (data == null) {
|
|
||||||
|
if (handler == null) {
|
||||||
|
Grasscutter.getLogger().debug("Could not trigger condition {} at {}", condition.getCondType(), params);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Grasscutter.getLogger()
|
return handler.execute(condition, params);
|
||||||
.debug(
|
|
||||||
"{}({}) is trying to enter dungeon {}",
|
|
||||||
player.getNickname(),
|
|
||||||
player.getUid(),
|
|
||||||
dungeonId);
|
|
||||||
|
|
||||||
var sceneId = data.getSceneId();
|
|
||||||
player.getScene().setPrevScene(sceneId);
|
|
||||||
|
|
||||||
if (player.getWorld().transferPlayerToScene(player, sceneId, data)) {
|
|
||||||
player.getScene().addDungeonSettleObserver(basicDungeonSettleObserver);
|
|
||||||
player.getQuestManager().triggerEvent(QuestContent.QUEST_CONTENT_ENTER_DUNGEON, data.getId());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
player.getScene().setPrevScenePoint(pointId);
|
public boolean enterDungeon(Player player, int pointId, int dungeonId) {
|
||||||
player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId));
|
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
|
||||||
|
|
||||||
|
if (data == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Grasscutter.getLogger().info("{}({}) is trying to enter dungeon {}" ,player.getNickname(),player.getUid(),dungeonId);
|
||||||
|
|
||||||
|
int sceneId = data.getSceneId();
|
||||||
|
var scene = player.getScene();
|
||||||
|
scene.setPrevScene(sceneId);
|
||||||
|
|
||||||
|
if (player.getWorld().transferPlayerToScene(player, sceneId, data)) {
|
||||||
|
scene = player.getScene();
|
||||||
|
scene.addDungeonSettleObserver(basicDungeonSettleObserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
scene.setPrevScenePoint(pointId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** used in tower dungeons handoff */
|
/**
|
||||||
public boolean handoffDungeon(
|
* used in tower dungeons handoff
|
||||||
Player player, int dungeonId, List<DungeonSettleListener> dungeonSettleListeners) {
|
*/
|
||||||
var data = GameData.getDungeonDataMap().get(dungeonId);
|
public boolean handoffDungeon(Player player, int dungeonId, List<DungeonSettleListener> dungeonSettleListeners) {
|
||||||
|
DungeonData data = GameData.getDungeonDataMap().get(dungeonId);
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Grasscutter.getLogger().info("{}({}) is trying to enter tower dungeon {}" ,player.getNickname(),player.getUid(),dungeonId);
|
||||||
Grasscutter.getLogger()
|
|
||||||
.debug(
|
|
||||||
"{}({}) is trying to enter tower dungeon {}",
|
|
||||||
player.getNickname(),
|
|
||||||
player.getUid(),
|
|
||||||
dungeonId);
|
|
||||||
|
|
||||||
if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) {
|
if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) {
|
||||||
dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver);
|
dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void exitDungeon(Player player) {
|
public void exitDungeon(Player player) {
|
||||||
var scene = player.getScene();
|
Scene scene = player.getScene();
|
||||||
|
|
||||||
if (scene == null || scene.getSceneType() != SceneType.SCENE_DUNGEON) {
|
if (scene==null || scene.getSceneType() != SceneType.SCENE_DUNGEON) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get previous scene
|
// Get previous scene
|
||||||
var prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3;
|
int prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3;
|
||||||
|
|
||||||
// Get previous position
|
// Get previous position
|
||||||
var dungeonData = scene.getDungeonData();
|
val dungeonManager = scene.getDungeonManager();
|
||||||
var prevPos = new Position(GameConstants.START_POSITION);
|
DungeonData dungeonData = dungeonManager != null ? dungeonManager.getDungeonData() : null;
|
||||||
|
Position prevPos = new Position(GameConstants.START_POSITION);
|
||||||
|
|
||||||
if (dungeonData != null) {
|
if (dungeonData != null) {
|
||||||
var entry = GameData.getScenePointEntryById(prevScene, scene.getPrevScenePoint());
|
ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, scene.getPrevScenePoint());
|
||||||
|
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
prevPos.set(entry.getPointData().getTranPos());
|
prevPos.set(entry.getPointData().getTranPos());
|
||||||
}
|
}
|
||||||
|
if(!dungeonManager.isFinishedSuccessfully()){
|
||||||
|
dungeonManager.quitDungeon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dungeonManager.unsetTrialTeam(player);
|
||||||
|
}
|
||||||
// clean temp team if it has
|
// clean temp team if it has
|
||||||
player.getTeamManager().cleanTemporaryTeam();
|
player.getTeamManager().cleanTemporaryTeam();
|
||||||
player.getTowerManager().clearEntry();
|
player.getTowerManager().clearEntry();
|
||||||
|
|
||||||
|
|
||||||
// Transfer player back to world
|
// Transfer player back to world
|
||||||
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
|
player.getWorld().transferPlayerToScene(player, prevScene, prevPos);
|
||||||
player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,38 @@
|
|||||||
package emu.grasscutter.game.dungeons;
|
package emu.grasscutter.game.dungeons;
|
||||||
|
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult.DungeonEndReason;
|
||||||
|
import emu.grasscutter.game.world.SceneGroupInstance;
|
||||||
|
import emu.grasscutter.game.dungeons.dungeon_results.TowerResult;
|
||||||
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
|
import emu.grasscutter.server.packet.send.PacketDungeonSettleNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketTowerFloorRecordChangeNotify;
|
import emu.grasscutter.server.packet.send.PacketTowerFloorRecordChangeNotify;
|
||||||
import emu.grasscutter.utils.Utils;
|
|
||||||
|
|
||||||
public class TowerDungeonSettleListener implements DungeonSettleListener {
|
public class TowerDungeonSettleListener implements DungeonSettleListener {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDungeonSettle(Scene scene) {
|
public void onDungeonSettle(DungeonManager dungeonManager, DungeonEndReason endReason) {
|
||||||
if (scene.getScriptManager().getVariables().containsKey("stage")
|
var scene = dungeonManager.getScene();
|
||||||
&& scene.getScriptManager().getVariables().get("stage") == 1) {
|
var dungeonData = dungeonManager.getDungeonData();
|
||||||
|
if (scene.getLoadedGroups().stream().anyMatch(g -> {
|
||||||
|
var variables = scene.getScriptManager().getVariables(g.id);
|
||||||
|
return variables != null && variables.containsKey("stage") && variables.get("stage") == 1;
|
||||||
|
})) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scene.setAutoCloseTime(Utils.getCurrentSeconds() + 1000);
|
|
||||||
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
var towerManager = scene.getPlayers().get(0).getTowerManager();
|
||||||
|
|
||||||
towerManager.notifyCurLevelRecordChangeWhenDone(3);
|
towerManager.notifyCurLevelRecordChangeWhenDone(3);
|
||||||
scene.broadcastPacket(
|
scene.broadcastPacket(new PacketTowerFloorRecordChangeNotify(
|
||||||
new PacketTowerFloorRecordChangeNotify(
|
towerManager.getCurrentFloorId(),
|
||||||
towerManager.getCurrentFloorId(), 3, towerManager.canEnterScheduleFloor()));
|
3,
|
||||||
|
towerManager.canEnterScheduleFloor()
|
||||||
|
));
|
||||||
|
|
||||||
|
var challenge = scene.getChallenge();
|
||||||
|
var dungeonStats = new DungeonEndStats(scene.getKilledMonsterCount(), challenge.getFinishedTime(), 0, endReason);
|
||||||
|
var result = new TowerResult(dungeonData, dungeonStats, towerManager, challenge);
|
||||||
|
|
||||||
|
scene.broadcastPacket(new PacketDungeonSettleNotify(result));
|
||||||
|
|
||||||
scene.broadcastPacket(
|
|
||||||
new PacketDungeonSettleNotify(
|
|
||||||
scene.getChallenge(),
|
|
||||||
towerManager.hasNextFloor(),
|
|
||||||
towerManager.hasNextLevel(),
|
|
||||||
towerManager.hasNextLevel() ? 0 : towerManager.getNextFloorId()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,14 @@ package emu.grasscutter.game.dungeons.challenge;
|
|||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
||||||
|
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.entity.EntityMonster;
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
|
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
import emu.grasscutter.scripts.data.SceneTrigger;
|
||||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify;
|
import emu.grasscutter.server.packet.send.PacketDungeonChallengeBeginNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
|
import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify;
|
||||||
@ -14,6 +17,7 @@ import java.util.List;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@ -78,26 +82,33 @@ public class WorldChallenge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void done() {
|
public void done() {
|
||||||
if (!inProgress()) {
|
if (!this.inProgress()) return;
|
||||||
return;
|
this.finish(true);
|
||||||
|
|
||||||
|
var scene = this.getScene();
|
||||||
|
var dungeonManager = scene.getDungeonManager();
|
||||||
|
if (dungeonManager != null && dungeonManager.getDungeonData() != null) {
|
||||||
|
scene.getPlayers().forEach(p -> p.getActivityManager().triggerWatcher(
|
||||||
|
WatcherTriggerType.TRIGGER_FINISH_CHALLENGE,
|
||||||
|
String.valueOf(dungeonManager.getDungeonData().getId()),
|
||||||
|
String.valueOf(this.getGroup().id),
|
||||||
|
String.valueOf(this.getChallengeId())
|
||||||
|
));
|
||||||
}
|
}
|
||||||
finish(true);
|
|
||||||
this.getScene()
|
scene.getScriptManager().callEvent(
|
||||||
.getScriptManager()
|
|
||||||
.callEvent(
|
|
||||||
EventType.EVENT_CHALLENGE_SUCCESS,
|
|
||||||
// TODO record the time in PARAM2 and used in action
|
// TODO record the time in PARAM2 and used in action
|
||||||
new ScriptArgs().setParam2(finishedTime));
|
new ScriptArgs(this.getGroup().id, EventType.EVENT_CHALLENGE_SUCCESS).setParam2(finishedTime));
|
||||||
|
this.getScene().triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_FINISH_CHALLENGE, getChallengeId(), getChallengeIndex());
|
||||||
|
|
||||||
challengeTriggers.forEach(t -> t.onFinish(this));
|
this.challengeTriggers.forEach(t -> t.onFinish(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fail() {
|
public void fail(){
|
||||||
if (!inProgress()) {
|
if (!this.inProgress()) return;
|
||||||
return;
|
this.finish(true);
|
||||||
}
|
|
||||||
finish(false);
|
this.getScene().getScriptManager().callEvent(new ScriptArgs(this.getGroup().id, EventType.EVENT_CHALLENGE_FAIL));
|
||||||
this.getScene().getScriptManager().callEvent(EventType.EVENT_CHALLENGE_FAIL, null);
|
|
||||||
challengeTriggers.forEach(t -> t.onFinish(this));
|
challengeTriggers.forEach(t -> t.onFinish(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +143,18 @@ public class WorldChallenge {
|
|||||||
this.challengeTriggers.forEach(t -> t.onGadgetDeath(this, gadget));
|
this.challengeTriggers.forEach(t -> t.onGadgetDeath(this, gadget));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onGroupTriggerDeath(SceneTrigger trigger) {
|
||||||
|
if(!this.inProgress()) return;
|
||||||
|
|
||||||
|
var triggerGroup = trigger.getCurrentGroup();
|
||||||
|
if (triggerGroup == null ||
|
||||||
|
triggerGroup.id != getGroup().id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.challengeTriggers.forEach(t -> t.onGroupTrigger(this, trigger));
|
||||||
|
}
|
||||||
|
|
||||||
public void onGadgetDamage(EntityGadget gadget) {
|
public void onGadgetDamage(EntityGadget gadget) {
|
||||||
if (!inProgress()) {
|
if (!inProgress()) {
|
||||||
return;
|
return;
|
||||||
|
@ -1,36 +1,35 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
package emu.grasscutter.game.dungeons.challenge.factory;
|
||||||
|
|
||||||
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ChallengeFactory {
|
public abstract class ChallengeFactory {
|
||||||
|
|
||||||
private static final List<ChallengeFactoryHandler> challengeFactoryHandlers = new ArrayList<>();
|
private static final List<ChallengeFactoryHandler> challengeFactoryHandlers = new ArrayList<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
challengeFactoryHandlers.add(new DungeonChallengeFactoryHandler());
|
challengeFactoryHandlers.add(new KillAndGuardChallengeFactoryHandler());
|
||||||
challengeFactoryHandlers.add(new DungeonGuardChallengeFactoryHandler());
|
challengeFactoryHandlers.add(new KillMonsterCountChallengeFactoryHandler());
|
||||||
challengeFactoryHandlers.add(new KillGadgetChallengeFactoryHandler());
|
challengeFactoryHandlers.add(new KillMonsterInTimeChallengeFactoryHandler());
|
||||||
challengeFactoryHandlers.add(new KillMonsterChallengeFactoryHandler());
|
challengeFactoryHandlers.add(new KillMonsterTimeChallengeFactoryHandler());
|
||||||
|
challengeFactoryHandlers.add(new SurviveChallengeFactoryHandler());
|
||||||
|
challengeFactoryHandlers.add(new TriggerInTimeChallengeFactoryHandler());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WorldChallenge getChallenge(
|
public static WorldChallenge getChallenge(int localChallengeId, int challengeDataId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group){
|
||||||
int param1,
|
val challengeData = GameData.getDungeonChallengeConfigDataMap().get(challengeDataId);
|
||||||
int param2,
|
val challengeType = challengeData.getChallengeType();
|
||||||
int param3,
|
|
||||||
int param4,
|
for(var handler : challengeFactoryHandlers){
|
||||||
int param5,
|
if(!handler.isThisType(challengeType)){
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
for (var handler : challengeFactoryHandlers) {
|
|
||||||
if (!handler.isThisType(param1, param2, param3, param4, param5, param6, scene, group)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return handler.build(param1, param2, param3, param4, param5, param6, scene, group);
|
return handler.build(localChallengeId, challengeDataId, param3, param4, param5, param6, scene, group);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,11 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
package emu.grasscutter.game.dungeons.challenge.factory;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
|
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
|
||||||
public interface ChallengeFactoryHandler {
|
public interface ChallengeFactoryHandler {
|
||||||
boolean isThisType(
|
boolean isThisType(ChallengeType challengeType);
|
||||||
int challengeIndex,
|
WorldChallenge build(int challengeIndex, int challengeId, int param3, int param4, int param5, int param6, Scene scene, SceneGroup group);
|
||||||
int challengeId,
|
|
||||||
int param3,
|
|
||||||
int param4,
|
|
||||||
int param5,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group);
|
|
||||||
|
|
||||||
WorldChallenge build(
|
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int param3,
|
|
||||||
int param4,
|
|
||||||
int param5,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group);
|
|
||||||
}
|
}
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
|
|
||||||
import emu.grasscutter.game.props.SceneType;
|
|
||||||
import emu.grasscutter.game.world.Scene;
|
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class DungeonChallengeFactoryHandler implements ChallengeFactoryHandler {
|
|
||||||
@Override
|
|
||||||
public boolean isThisType(
|
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int param3,
|
|
||||||
int param4,
|
|
||||||
int param5,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
// ActiveChallenge with 1,1000,300,233101003,15,0
|
|
||||||
return scene.getSceneType() == SceneType.SCENE_DUNGEON && param4 == group.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WorldChallenge build(
|
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int param3,
|
|
||||||
int param4,
|
|
||||||
int param5,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
var realGroup = scene.getScriptManager().getGroupById(param4);
|
|
||||||
return new DungeonChallenge(
|
|
||||||
scene,
|
|
||||||
realGroup,
|
|
||||||
challengeId, // Id
|
|
||||||
challengeIndex, // Index
|
|
||||||
List.of(param5, param3),
|
|
||||||
param3, // Limit
|
|
||||||
param5, // Goal
|
|
||||||
List.of(new InTimeTrigger(), new KillMonsterTrigger()));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.GuardTrigger;
|
|
||||||
import emu.grasscutter.game.props.SceneType;
|
|
||||||
import emu.grasscutter.game.world.Scene;
|
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class DungeonGuardChallengeFactoryHandler implements ChallengeFactoryHandler {
|
|
||||||
@Override
|
|
||||||
public boolean isThisType(
|
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int param3,
|
|
||||||
int param4,
|
|
||||||
int param5,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
// ActiveChallenge with 1,188,234101003,12,3030,0
|
|
||||||
return scene.getSceneType() == SceneType.SCENE_DUNGEON && param3 == group.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WorldChallenge build(
|
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int param3,
|
|
||||||
int param4,
|
|
||||||
int param5,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
var realGroup = scene.getScriptManager().getGroupById(param3);
|
|
||||||
return new DungeonChallenge(
|
|
||||||
scene,
|
|
||||||
realGroup,
|
|
||||||
challengeId, // Id
|
|
||||||
challengeIndex, // Index
|
|
||||||
List.of(param4, 0),
|
|
||||||
0, // Limit
|
|
||||||
param4, // Goal
|
|
||||||
List.of(new GuardTrigger()));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +1,18 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
package emu.grasscutter.game.dungeons.challenge.factory;
|
||||||
|
|
||||||
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_KILL_COUNT_GUARD_HP;
|
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.GuardTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.GuardTrigger;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import java.util.List;
|
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
public class KillAndGuardChallengeFactoryHandler implements ChallengeFactoryHandler {
|
import java.util.List;
|
||||||
|
|
||||||
|
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_KILL_COUNT_GUARD_HP;
|
||||||
|
|
||||||
|
public class KillAndGuardChallengeFactoryHandler implements ChallengeFactoryHandler{
|
||||||
@Override
|
@Override
|
||||||
public boolean isThisType(ChallengeType challengeType) {
|
public boolean isThisType(ChallengeType challengeType) {
|
||||||
// ActiveChallenge with 1,188,234101003,12,3030,0
|
// ActiveChallenge with 1,188,234101003,12,3030,0
|
||||||
@ -19,19 +20,10 @@ public class KillAndGuardChallengeFactoryHandler implements ChallengeFactoryHand
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override /*TODO check param4 == monstesToKill*/
|
@Override /*TODO check param4 == monstesToKill*/
|
||||||
public WorldChallenge build(
|
public WorldChallenge build(int challengeIndex, int challengeId, int groupId, int monstersToKill, int gadgetCFGId, int unused, Scene scene, SceneGroup group) {
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int groupId,
|
|
||||||
int monstersToKill,
|
|
||||||
int gadgetCFGId,
|
|
||||||
int unused,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
||||||
return new WorldChallenge(
|
return new WorldChallenge(
|
||||||
scene,
|
scene, realGroup,
|
||||||
realGroup,
|
|
||||||
challengeId, // Id
|
challengeId, // Id
|
||||||
challengeIndex, // Index
|
challengeIndex, // Index
|
||||||
List.of(monstersToKill, 0),
|
List.of(monstersToKill, 0),
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillGadgetTrigger;
|
|
||||||
import emu.grasscutter.game.world.Scene;
|
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class KillGadgetChallengeFactoryHandler implements ChallengeFactoryHandler {
|
|
||||||
@Override
|
|
||||||
public boolean isThisType(
|
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int param3,
|
|
||||||
int param4,
|
|
||||||
int param5,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
// kill gadgets(explosive barrel) in time
|
|
||||||
// ActiveChallenge with 56,201,20,2,201,4
|
|
||||||
// open chest in time
|
|
||||||
// ActiveChallenge with 666,202,30,7,202,1
|
|
||||||
return challengeId == 201 || challengeId == 202;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WorldChallenge build(
|
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int param3,
|
|
||||||
int param4,
|
|
||||||
int param5,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
return new WorldChallenge(
|
|
||||||
scene,
|
|
||||||
group,
|
|
||||||
challengeId, // Id
|
|
||||||
challengeIndex, // Index
|
|
||||||
List.of(param3, param6, 0),
|
|
||||||
param3, // Limit
|
|
||||||
param6, // Goal
|
|
||||||
List.of(new InTimeTrigger(), new KillGadgetTrigger()));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
|
|
||||||
import emu.grasscutter.game.world.Scene;
|
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class KillMonsterChallengeFactoryHandler implements ChallengeFactoryHandler {
|
|
||||||
@Override
|
|
||||||
public boolean isThisType(
|
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int param3,
|
|
||||||
int param4,
|
|
||||||
int param5,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
// ActiveChallenge with 180,180,45,133108061,1,0
|
|
||||||
return challengeId == 180;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WorldChallenge build(
|
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int param3,
|
|
||||||
int param4,
|
|
||||||
int param5,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
var realGroup = scene.getScriptManager().getGroupById(param4);
|
|
||||||
return new WorldChallenge(
|
|
||||||
scene,
|
|
||||||
realGroup,
|
|
||||||
challengeId, // Id
|
|
||||||
challengeIndex, // Index
|
|
||||||
List.of(param5, param3),
|
|
||||||
param3, // Limit
|
|
||||||
param5, // Goal
|
|
||||||
List.of(new KillMonsterTrigger(), new InTimeTrigger()));
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,10 +5,11 @@ import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
|||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import java.util.List;
|
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
public class KillMonsterCountChallengeFactoryHandler implements ChallengeFactoryHandler {
|
import java.util.List;
|
||||||
|
|
||||||
|
public class KillMonsterCountChallengeFactoryHandler implements ChallengeFactoryHandler{
|
||||||
@Override
|
@Override
|
||||||
public boolean isThisType(ChallengeType challengeType) {
|
public boolean isThisType(ChallengeType challengeType) {
|
||||||
// ActiveChallenge with 1, 1, 241033003, 15, 0, 0
|
// ActiveChallenge with 1, 1, 241033003, 15, 0, 0
|
||||||
@ -16,24 +17,16 @@ public class KillMonsterCountChallengeFactoryHandler implements ChallengeFactory
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorldChallenge build(
|
public WorldChallenge build(int challengeIndex, int challengeId, int groupId, int goal, int param5, int param6, Scene scene, SceneGroup group) {
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int groupId,
|
|
||||||
int goal,
|
|
||||||
int param5,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
||||||
return new WorldChallenge(
|
return new WorldChallenge(
|
||||||
scene,
|
scene, realGroup,
|
||||||
realGroup,
|
|
||||||
challengeId, // Id
|
challengeId, // Id
|
||||||
challengeIndex, // Index
|
challengeIndex, // Index
|
||||||
List.of(goal, groupId),
|
List.of(goal, groupId),
|
||||||
0, // Limit
|
0, // Limit
|
||||||
goal, // Goal
|
goal, // Goal
|
||||||
List.of(new KillMonsterCountTrigger()));
|
List.of(new KillMonsterCountTrigger())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,11 @@ import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
|
|||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import java.util.List;
|
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
public class KillMonsterInTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
|
import java.util.List;
|
||||||
|
|
||||||
|
public class KillMonsterInTimeChallengeFactoryHandler implements ChallengeFactoryHandler{
|
||||||
@Override
|
@Override
|
||||||
public boolean isThisType(ChallengeType challengeType) {
|
public boolean isThisType(ChallengeType challengeType) {
|
||||||
// ActiveChallenge with 180, 72, 240, 133220161, 133220161, 0
|
// ActiveChallenge with 180, 72, 240, 133220161, 133220161, 0
|
||||||
@ -17,24 +18,16 @@ public class KillMonsterInTimeChallengeFactoryHandler implements ChallengeFactor
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorldChallenge build(
|
public WorldChallenge build(int challengeIndex, int challengeId, int timeLimit, int groupId, int targetCfgId, int param6, Scene scene, SceneGroup group) {
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int timeLimit,
|
|
||||||
int groupId,
|
|
||||||
int targetCfgId,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
||||||
return new WorldChallenge(
|
return new WorldChallenge(
|
||||||
scene,
|
scene, realGroup,
|
||||||
realGroup,
|
|
||||||
challengeId, // Id
|
challengeId, // Id
|
||||||
challengeIndex, // Index
|
challengeIndex, // Index
|
||||||
List.of(timeLimit),
|
List.of(timeLimit),
|
||||||
timeLimit, // Limit
|
timeLimit, // Limit
|
||||||
0, // Goal
|
0, // Goal
|
||||||
List.of(new KillMonsterTrigger(targetCfgId), new InTimeTrigger()));
|
List.of(new KillMonsterTrigger(targetCfgId), new InTimeTrigger())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,37 +6,30 @@ import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
|
|||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import java.util.List;
|
|
||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
public class KillMonsterTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
|
import java.util.List;
|
||||||
|
|
||||||
|
public class KillMonsterTimeChallengeFactoryHandler implements ChallengeFactoryHandler{
|
||||||
@Override
|
@Override
|
||||||
public boolean isThisType(ChallengeType challengeType) {
|
public boolean isThisType(ChallengeType challengeType) {
|
||||||
// ActiveChallenge with 180,180,45,133108061,1,0
|
// ActiveChallenge with 180,180,45,133108061,1,0
|
||||||
// ActiveChallenge Fast with 1001, 5, 15, 240004005, 10, 0
|
// ActiveChallenge Fast with 1001, 5, 15, 240004005, 10, 0
|
||||||
return challengeType == ChallengeType.CHALLENGE_KILL_COUNT_IN_TIME
|
return challengeType == ChallengeType.CHALLENGE_KILL_COUNT_IN_TIME ||
|
||||||
|| challengeType == ChallengeType.CHALLENGE_KILL_COUNT_FAST;
|
challengeType == ChallengeType.CHALLENGE_KILL_COUNT_FAST;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorldChallenge build(
|
public WorldChallenge build(int challengeIndex, int challengeId, int timeLimit, int groupId, int targetCount, int param6, Scene scene, SceneGroup group) {
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int timeLimit,
|
|
||||||
int groupId,
|
|
||||||
int targetCount,
|
|
||||||
int param6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
val realGroup = scene.getScriptManager().getGroupById(groupId);
|
||||||
return new WorldChallenge(
|
return new WorldChallenge(
|
||||||
scene,
|
scene, realGroup,
|
||||||
realGroup,
|
|
||||||
challengeId, // Id
|
challengeId, // Id
|
||||||
challengeIndex, // Index
|
challengeIndex, // Index
|
||||||
List.of(targetCount, timeLimit),
|
List.of(targetCount, timeLimit),
|
||||||
timeLimit, // Limit
|
timeLimit, // Limit
|
||||||
targetCount, // Goal
|
targetCount, // Goal
|
||||||
List.of(new KillMonsterCountTrigger(), new InTimeTrigger()));
|
List.of(new KillMonsterCountTrigger(), new InTimeTrigger())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
package emu.grasscutter.game.dungeons.challenge.factory;
|
||||||
|
|
||||||
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_SURVIVE;
|
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.ForTimeTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.ForTimeTrigger;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_SURVIVE;
|
||||||
|
|
||||||
public class SurviveChallengeFactoryHandler implements ChallengeFactoryHandler {
|
public class SurviveChallengeFactoryHandler implements ChallengeFactoryHandler {
|
||||||
@Override
|
@Override
|
||||||
public boolean isThisType(ChallengeType challengeType) {
|
public boolean isThisType(ChallengeType challengeType) {
|
||||||
@ -18,23 +19,15 @@ public class SurviveChallengeFactoryHandler implements ChallengeFactoryHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorldChallenge build(
|
public WorldChallenge build(int challengeIndex, int challengeId, int timeToSurvive, int unused4, int unused5, int unused6, Scene scene, SceneGroup group) {
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int timeToSurvive,
|
|
||||||
int unused4,
|
|
||||||
int unused5,
|
|
||||||
int unused6,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
return new WorldChallenge(
|
return new WorldChallenge(
|
||||||
scene,
|
scene, group,
|
||||||
group,
|
|
||||||
challengeId, // Id
|
challengeId, // Id
|
||||||
challengeIndex, // Index
|
challengeIndex, // Index
|
||||||
List.of(timeToSurvive),
|
List.of(timeToSurvive),
|
||||||
timeToSurvive, // Limit
|
timeToSurvive, // Limit
|
||||||
0, // Goal
|
0, // Goal
|
||||||
List.of(new ForTimeTrigger()));
|
List.of(new ForTimeTrigger())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
package emu.grasscutter.game.dungeons.challenge.factory;
|
package emu.grasscutter.game.dungeons.challenge.factory;
|
||||||
|
|
||||||
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_TRIGGER_IN_TIME;
|
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
import emu.grasscutter.game.dungeons.challenge.enums.ChallengeType;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.InTimeTrigger;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.TriggerGroupTriggerTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.TriggerGroupTriggerTrigger;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static emu.grasscutter.game.dungeons.challenge.enums.ChallengeType.CHALLENGE_TRIGGER_IN_TIME;
|
||||||
|
|
||||||
public class TriggerInTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
|
public class TriggerInTimeChallengeFactoryHandler implements ChallengeFactoryHandler {
|
||||||
@Override
|
@Override
|
||||||
public boolean isThisType(ChallengeType challengeType) {
|
public boolean isThisType(ChallengeType challengeType) {
|
||||||
@ -21,23 +22,15 @@ public class TriggerInTimeChallengeFactoryHandler implements ChallengeFactoryHan
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WorldChallenge build(
|
public WorldChallenge build(int challengeIndex, int challengeId, int timeLimit, int param4, int triggerTag, int triggerCount, Scene scene, SceneGroup group) {
|
||||||
int challengeIndex,
|
|
||||||
int challengeId,
|
|
||||||
int timeLimit,
|
|
||||||
int param4,
|
|
||||||
int triggerTag,
|
|
||||||
int triggerCount,
|
|
||||||
Scene scene,
|
|
||||||
SceneGroup group) {
|
|
||||||
return new WorldChallenge(
|
return new WorldChallenge(
|
||||||
scene,
|
scene, group,
|
||||||
group,
|
|
||||||
challengeId, // Id
|
challengeId, // Id
|
||||||
challengeIndex, // Index
|
challengeIndex, // Index
|
||||||
List.of(timeLimit, triggerCount),
|
List.of(timeLimit, triggerCount),
|
||||||
timeLimit, // Limit
|
timeLimit, // Limit
|
||||||
triggerCount, // Goal
|
triggerCount, // Goal
|
||||||
List.of(new InTimeTrigger(), new TriggerGroupTriggerTrigger(Integer.toString(triggerTag))));
|
List.of(new InTimeTrigger(), new TriggerGroupTriggerTrigger(Integer.toString(triggerTag)))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,17 +3,14 @@ package emu.grasscutter.game.dungeons.challenge.trigger;
|
|||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.entity.EntityMonster;
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
|
import emu.grasscutter.scripts.data.SceneTrigger;
|
||||||
|
|
||||||
public abstract class ChallengeTrigger {
|
public abstract class ChallengeTrigger {
|
||||||
public void onBegin(WorldChallenge challenge) {}
|
public void onBegin(WorldChallenge challenge) { }
|
||||||
|
public void onFinish(WorldChallenge challenge) { }
|
||||||
public void onFinish(WorldChallenge challenge) {}
|
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) { }
|
||||||
|
public void onGadgetDeath(WorldChallenge challenge, EntityGadget gadget) { }
|
||||||
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) {}
|
public void onCheckTimeout(WorldChallenge challenge) { }
|
||||||
|
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget) { }
|
||||||
public void onGadgetDeath(WorldChallenge challenge, EntityGadget gadget) {}
|
public void onGroupTrigger(WorldChallenge challenge, SceneTrigger trigger) { }
|
||||||
|
|
||||||
public void onCheckTimeout(WorldChallenge challenge) {}
|
|
||||||
|
|
||||||
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget) {}
|
|
||||||
}
|
}
|
||||||
|
@ -2,24 +2,36 @@ package emu.grasscutter.game.dungeons.challenge.trigger;
|
|||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
|
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
|
||||||
|
|
||||||
public class GuardTrigger extends KillMonsterTrigger {
|
public class GuardTrigger extends ChallengeTrigger {
|
||||||
@Override
|
private final int entityToProtectCFGId;
|
||||||
|
private int lastSendPercent = 100;
|
||||||
|
public GuardTrigger(int entityToProtectCFGId){
|
||||||
|
this.entityToProtectCFGId = entityToProtectCFGId;
|
||||||
|
}
|
||||||
|
|
||||||
public void onBegin(WorldChallenge challenge) {
|
public void onBegin(WorldChallenge challenge) {
|
||||||
super.onBegin(challenge);
|
|
||||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, 100));
|
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget) {
|
public void onGadgetDamage(WorldChallenge challenge, EntityGadget gadget) {
|
||||||
|
if(gadget.getConfigId() != entityToProtectCFGId){
|
||||||
|
return;
|
||||||
|
}
|
||||||
var curHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_CUR_HP.getId());
|
var curHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_CUR_HP.getId());
|
||||||
var maxHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_BASE_HP.getId());
|
var maxHp = gadget.getFightProperties().get(FightProperty.FIGHT_PROP_BASE_HP.getId());
|
||||||
int percent = (int) (curHp / maxHp);
|
int percent = (int) (curHp / maxHp);
|
||||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, percent));
|
|
||||||
|
|
||||||
if (percent <= 0) {
|
if(percent!=lastSendPercent) {
|
||||||
|
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 2, percent));
|
||||||
|
lastSendPercent = percent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(percent <= 0){
|
||||||
challenge.fail();
|
challenge.fail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,21 +3,19 @@ package emu.grasscutter.game.dungeons.challenge.trigger;
|
|||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.entity.EntityMonster;
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
|
import emu.grasscutter.server.packet.send.PacketChallengeDataNotify;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
public class KillMonsterTrigger extends ChallengeTrigger {
|
@AllArgsConstructor
|
||||||
|
public class KillMonsterTrigger extends ChallengeTrigger{
|
||||||
|
private int monsterCfgId;
|
||||||
@Override
|
@Override
|
||||||
public void onBegin(WorldChallenge challenge) {
|
public void onBegin(WorldChallenge challenge) {
|
||||||
challenge
|
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 1, challenge.getScore().get()));
|
||||||
.getScene()
|
|
||||||
.broadcastPacket(new PacketChallengeDataNotify(challenge, 1, challenge.getScore().get()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) {
|
public void onMonsterDeath(WorldChallenge challenge, EntityMonster monster) {
|
||||||
var newScore = challenge.increaseScore();
|
if(monster.getConfigId() == monsterCfgId){
|
||||||
challenge.getScene().broadcastPacket(new PacketChallengeDataNotify(challenge, 1, newScore));
|
|
||||||
|
|
||||||
if (newScore >= challenge.getGoal()) {
|
|
||||||
challenge.done();
|
challenge.done();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,18 +52,25 @@ public class EntityAvatar extends GameEntity {
|
|||||||
|
|
||||||
public EntityAvatar(Scene scene, Avatar avatar) {
|
public EntityAvatar(Scene scene, Avatar avatar) {
|
||||||
super(scene);
|
super(scene);
|
||||||
|
|
||||||
this.avatar = avatar;
|
this.avatar = avatar;
|
||||||
this.avatar.setCurrentEnergy();
|
this.avatar.setCurrentEnergy();
|
||||||
|
|
||||||
if (getScene() != null) {
|
if (getScene() != null) {
|
||||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.AVATAR);
|
this.id = getScene().getWorld().getNextEntityId(EntityIdType.AVATAR);
|
||||||
|
|
||||||
GameItem weapon = getAvatar().getWeapon();
|
var weapon = getAvatar().getWeapon();
|
||||||
if (weapon != null) {
|
if (weapon != null) {
|
||||||
weapon.setWeaponEntityId(getScene().getWorld().getNextEntityId(EntityIdType.WEAPON));
|
weapon.setWeaponEntityId(getScene().getWorld().getNextEntityId(EntityIdType.WEAPON));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEntityTypeId() {
|
||||||
|
return this.getAvatar().getAvatarId();
|
||||||
|
}
|
||||||
|
|
||||||
public Player getPlayer() {
|
public Player getPlayer() {
|
||||||
return this.avatar.getPlayer();
|
return this.avatar.getPlayer();
|
||||||
}
|
}
|
||||||
@ -153,6 +160,22 @@ public class EntityAvatar extends GameEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a fixed amount of energy to the current avatar.
|
||||||
|
*
|
||||||
|
* @param amount The amount of energy to add.
|
||||||
|
* @return True if the energy was added, false if the energy was not added.
|
||||||
|
*/
|
||||||
|
public boolean addEnergy(float amount) {
|
||||||
|
var curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp();
|
||||||
|
var curEnergy = this.getFightProperty(curEnergyProp);
|
||||||
|
if (curEnergy == amount) return false;
|
||||||
|
|
||||||
|
this.getAvatar().setCurrentEnergy(curEnergyProp, amount);
|
||||||
|
this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, curEnergyProp));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void addEnergy(float amount, PropChangeReason reason) {
|
public void addEnergy(float amount, PropChangeReason reason) {
|
||||||
this.addEnergy(amount, reason, false);
|
this.addEnergy(amount, reason, false);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.data.binout.ConfigGadget;
|
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
@ -25,12 +25,17 @@ public abstract class EntityBaseGadget extends GameEntity {
|
|||||||
|
|
||||||
public abstract int getGadgetId();
|
public abstract int getGadgetId();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEntityTypeId() {
|
||||||
|
return this.getGadgetId();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeath(int killerId) {
|
public void onDeath(int killerId) {
|
||||||
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void fillFightProps(ConfigGadget configGadget) {
|
protected void fillFightProps(ConfigEntityGadget configGadget) {
|
||||||
if (configGadget == null || configGadget.getCombat() == null) {
|
if (configGadget == null || configGadget.getCombat() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.binout.ConfigGadget;
|
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
||||||
import emu.grasscutter.data.excels.GadgetData;
|
import emu.grasscutter.data.excels.GadgetData;
|
||||||
import emu.grasscutter.game.entity.gadget.*;
|
import emu.grasscutter.game.entity.gadget.*;
|
||||||
|
import emu.grasscutter.game.entity.gadget.platform.BaseRoute;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.EntityIdType;
|
import emu.grasscutter.game.props.EntityIdType;
|
||||||
import emu.grasscutter.game.props.PlayerProperty;
|
import emu.grasscutter.game.props.PlayerProperty;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
|
import emu.grasscutter.game.world.SceneGroupInstance;
|
||||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||||
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
||||||
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
||||||
@ -15,42 +17,58 @@ import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData;
|
|||||||
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo;
|
||||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||||
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
||||||
|
import emu.grasscutter.net.proto.PlatformInfoOuterClass;
|
||||||
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
import emu.grasscutter.net.proto.PropPairOuterClass.PropPair;
|
||||||
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType;
|
||||||
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
|
||||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||||
|
import emu.grasscutter.net.proto.VisionTypeOuterClass;
|
||||||
|
import emu.grasscutter.scripts.EntityControllerScriptManager;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.scripts.data.SceneGadget;
|
import emu.grasscutter.scripts.data.SceneGadget;
|
||||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
|
import emu.grasscutter.server.packet.send.PacketGadgetStateNotify;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketPlatformStartRouteNotify;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketPlatformStopRouteNotify;
|
||||||
|
import emu.grasscutter.server.packet.send.PacketSceneTimeNotify;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import emu.grasscutter.utils.ProtoHelper;
|
import emu.grasscutter.utils.ProtoHelper;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||||
import java.util.Optional;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class EntityGadget extends EntityBaseGadget {
|
public class EntityGadget extends EntityBaseGadget {
|
||||||
@Getter private final GadgetData gadgetData;
|
@Getter private final GadgetData gadgetData;
|
||||||
|
@Getter(onMethod = @__(@Override)) @Setter
|
||||||
@Getter(onMethod_ = @Override, lazy = true)
|
|
||||||
private final Int2FloatMap fightProperties = new Int2FloatOpenHashMap();
|
|
||||||
|
|
||||||
@Getter(onMethod_ = @Override)
|
|
||||||
@Setter
|
|
||||||
private int gadgetId;
|
private int gadgetId;
|
||||||
|
@Getter private final Position bornPos;
|
||||||
|
@Getter private final Position bornRot;
|
||||||
|
@Getter @Setter private GameEntity owner = null;
|
||||||
|
@Getter @Setter private List<GameEntity> children = new ArrayList<>();
|
||||||
|
|
||||||
@Getter @Setter private int state;
|
@Getter private int state;
|
||||||
@Getter @Setter private int pointType;
|
@Getter @Setter private int pointType;
|
||||||
@Getter private GadgetContent content;
|
@Getter private GadgetContent content;
|
||||||
|
@Getter(onMethod = @__(@Override), lazy = true)
|
||||||
|
private final Int2FloatMap fightProperties = new Int2FloatOpenHashMap();
|
||||||
@Getter @Setter private SceneGadget metaGadget;
|
@Getter @Setter private SceneGadget metaGadget;
|
||||||
@Nullable @Getter private final ConfigGadget configGadget;
|
@Nullable @Getter
|
||||||
|
private ConfigEntityGadget configGadget;
|
||||||
|
@Getter @Setter private BaseRoute routeConfig;
|
||||||
|
|
||||||
|
@Getter @Setter private int stopValue = 0; //Controller related, inited to zero
|
||||||
|
@Getter @Setter private int startValue = 0; //Controller related, inited to zero
|
||||||
|
@Getter @Setter private int ticksSinceChange;
|
||||||
|
|
||||||
|
|
||||||
public EntityGadget(Scene scene, int gadgetId, Position pos) {
|
public EntityGadget(Scene scene, int gadgetId, Position pos) {
|
||||||
this(scene, gadgetId, pos, null, null);
|
this(scene, gadgetId, pos, null, null);
|
||||||
@ -60,27 +78,43 @@ public class EntityGadget extends EntityBaseGadget {
|
|||||||
this(scene, gadgetId, pos, rot, null);
|
this(scene, gadgetId, pos, rot, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityGadget(
|
public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot, GadgetContent content) {
|
||||||
Scene scene, int gadgetId, Position pos, Position rot, GadgetContent content) {
|
|
||||||
super(scene, pos, rot);
|
super(scene, pos, rot);
|
||||||
|
|
||||||
this.gadgetData = GameData.getGadgetDataMap().get(gadgetId);
|
this.gadgetData = GameData.getGadgetDataMap().get(gadgetId);
|
||||||
this.configGadget =
|
if (gadgetData != null && gadgetData.getJsonName() != null) {
|
||||||
Optional.ofNullable(this.gadgetData)
|
this.configGadget = GameData.getGadgetConfigData().get(gadgetData.getJsonName());
|
||||||
.map(GadgetData::getJsonName)
|
}
|
||||||
.map(GameData.getGadgetConfigData()::get)
|
|
||||||
.orElse(null);
|
|
||||||
this.id = this.getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
this.id = this.getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||||
this.gadgetId = gadgetId;
|
this.gadgetId = gadgetId;
|
||||||
this.content = content;
|
this.content = content;
|
||||||
fillFightProps(configGadget);
|
this.bornPos = this.getPosition().clone();
|
||||||
|
this.bornRot = this.getRotation().clone();
|
||||||
|
this.fillFightProps(configGadget);
|
||||||
|
|
||||||
|
if(GameData.getGadgetMappingMap().containsKey(gadgetId)) {
|
||||||
|
String controllerName = GameData.getGadgetMappingMap().get(gadgetId).getServerController();
|
||||||
|
this.setEntityController(EntityControllerScriptManager.getGadgetController(controllerName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(int state) {
|
||||||
|
this.state = state;
|
||||||
|
//Cache the gadget state
|
||||||
|
if(metaGadget != null && metaGadget.group != null) {
|
||||||
|
var instance = getScene().getScriptManager().getCachedGroupInstanceById(metaGadget.group.id);
|
||||||
|
if(instance != null) instance.cacheGadgetState(metaGadget, state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateState(int state) {
|
public void updateState(int state) {
|
||||||
|
if(state == this.getState()) return; //Don't triggers events
|
||||||
|
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
|
ticksSinceChange = getScene().getSceneTimeSeconds();
|
||||||
this.getScene().broadcastPacket(new PacketGadgetStateNotify(this, state));
|
this.getScene().broadcastPacket(new PacketGadgetStateNotify(this, state));
|
||||||
getScene()
|
getScene().getScriptManager().callEvent(new ScriptArgs(this.getGroupId(), EventType.EVENT_GADGET_STATE_CHANGE, state, this.getConfigId()));
|
||||||
.getScriptManager()
|
|
||||||
.callEvent(EventType.EVENT_GADGET_STATE_CHANGE, new ScriptArgs(state, this.getConfigId()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated(forRemoval = true) // Dont use!
|
@Deprecated(forRemoval = true) // Dont use!
|
||||||
@ -90,17 +124,14 @@ public class EntityGadget extends EntityBaseGadget {
|
|||||||
|
|
||||||
// TODO refactor
|
// TODO refactor
|
||||||
public void buildContent() {
|
public void buildContent() {
|
||||||
if (this.getContent() != null
|
if (this.getContent() != null || this.getGadgetData() == null || this.getGadgetData().getType() == null) {
|
||||||
|| this.getGadgetData() == null
|
|
||||||
|| this.getGadgetData().getType() == null) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.content =
|
this.content = switch (this.getGadgetData().getType()) {
|
||||||
switch (this.getGadgetData().getType()) {
|
|
||||||
case GatherPoint -> new GadgetGatherPoint(this);
|
case GatherPoint -> new GadgetGatherPoint(this);
|
||||||
case GatherObject -> new GadgetGatherObject(this);
|
case GatherObject -> new GadgetGatherObject(this);
|
||||||
case Worktop -> new GadgetWorktop(this);
|
case Worktop, SealGadget -> new GadgetWorktop(this);
|
||||||
case RewardStatue -> new GadgetRewardStatue(this);
|
case RewardStatue -> new GadgetRewardStatue(this);
|
||||||
case Chest -> new GadgetChest(this);
|
case Chest -> new GadgetChest(this);
|
||||||
case Gadget -> new GadgetObject(this);
|
case Gadget -> new GadgetObject(this);
|
||||||
@ -124,9 +155,16 @@ public class EntityGadget extends EntityBaseGadget {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
// Lua event
|
// Lua event
|
||||||
getScene()
|
getScene().getScriptManager().callEvent(new ScriptArgs(this.getGroupId(), EventType.EVENT_GADGET_CREATE, this.getConfigId()));
|
||||||
.getScriptManager()
|
}
|
||||||
.callEvent(EventType.EVENT_GADGET_CREATE, new ScriptArgs(this.getConfigId()));
|
|
||||||
|
@Override
|
||||||
|
public void onRemoved() {
|
||||||
|
super.onRemoved();
|
||||||
|
if(!children.isEmpty()) {
|
||||||
|
getScene().removeEntities(children, VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE);
|
||||||
|
children.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -139,51 +177,72 @@ public class EntityGadget extends EntityBaseGadget {
|
|||||||
if (getScene().getChallenge() != null) {
|
if (getScene().getChallenge() != null) {
|
||||||
getScene().getChallenge().onGadgetDeath(this);
|
getScene().getChallenge().onGadgetDeath(this);
|
||||||
}
|
}
|
||||||
getScene()
|
getScene().getScriptManager().callEvent(new ScriptArgs(this.getGroupId(), EventType.EVENT_ANY_GADGET_DIE, this.getConfigId()));
|
||||||
.getScriptManager()
|
|
||||||
.callEvent(EventType.EVENT_ANY_GADGET_DIE, new ScriptArgs(this.getConfigId()));
|
SceneGroupInstance groupInstance = getScene().getScriptManager().getCachedGroupInstanceById(this.getGroupId());
|
||||||
|
if(groupInstance != null && metaGadget != null)
|
||||||
|
groupInstance.getDeadEntities().add(metaGadget.config_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean startPlatform(){
|
||||||
|
if(routeConfig == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(routeConfig.isStarted()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
getScene().broadcastPacket(new PacketSceneTimeNotify(getScene()));
|
||||||
|
routeConfig.startRoute(getScene());
|
||||||
|
getScene().broadcastPacket(new PacketPlatformStartRouteNotify(this));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean stopPlatform(){
|
||||||
|
if(routeConfig == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!routeConfig.isStarted()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
routeConfig.stopRoute(getScene());
|
||||||
|
getScene().broadcastPacket(new PacketPlatformStopRouteNotify(this));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SceneEntityInfo toProto() {
|
public SceneEntityInfo toProto() {
|
||||||
EntityAuthorityInfo authority =
|
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||||
EntityAuthorityInfo.newBuilder()
|
|
||||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||||
.setAiInfo(
|
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(bornPos.toProto()))
|
||||||
SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder()))
|
.setBornPos(bornPos.toProto())
|
||||||
.setBornPos(Vector.newBuilder())
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
SceneEntityInfo.Builder entityInfo =
|
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||||
SceneEntityInfo.newBuilder()
|
|
||||||
.setEntityId(getId())
|
.setEntityId(getId())
|
||||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||||
.setMotionInfo(
|
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||||
MotionInfo.newBuilder()
|
|
||||||
.setPos(getPosition().toProto())
|
|
||||||
.setRot(getRotation().toProto())
|
|
||||||
.setSpeed(Vector.newBuilder()))
|
|
||||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||||
.setEntityClientData(EntityClientData.newBuilder())
|
.setEntityClientData(EntityClientData.newBuilder())
|
||||||
.setEntityAuthorityInfo(authority)
|
.setEntityAuthorityInfo(authority)
|
||||||
.setLifeState(1);
|
.setLifeState(1);
|
||||||
|
|
||||||
PropPair pair =
|
PropPair pair = PropPair.newBuilder()
|
||||||
PropPair.newBuilder()
|
|
||||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1))
|
||||||
.build();
|
.build();
|
||||||
entityInfo.addPropList(pair);
|
entityInfo.addPropList(pair);
|
||||||
|
|
||||||
// We do not use the getter to null check because the getter will create a fight prop map if it
|
// We do not use the getter to null check because the getter will create a fight prop map if it is null
|
||||||
// is null
|
|
||||||
if (this.fightProperties != null) {
|
if (this.fightProperties != null) {
|
||||||
addAllFightPropsToEntityInfo(entityInfo);
|
addAllFightPropsToEntityInfo(entityInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneGadgetInfo.Builder gadgetInfo =
|
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
||||||
SceneGadgetInfo.newBuilder()
|
|
||||||
.setGadgetId(this.getGadgetId())
|
.setGadgetId(this.getGadgetId())
|
||||||
.setGroupId(this.getGroupId())
|
.setGroupId(this.getGroupId())
|
||||||
.setConfigId(this.getConfigId())
|
.setConfigId(this.getConfigId())
|
||||||
@ -195,12 +254,28 @@ public class EntityGadget extends EntityBaseGadget {
|
|||||||
gadgetInfo.setDraftId(this.metaGadget.draft_id);
|
gadgetInfo.setDraftId(this.metaGadget.draft_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(owner != null){
|
||||||
|
gadgetInfo.setOwnerEntityId(owner.getId());
|
||||||
|
}
|
||||||
|
|
||||||
if (this.getContent() != null) {
|
if (this.getContent() != null) {
|
||||||
this.getContent().onBuildProto(gadgetInfo);
|
this.getContent().onBuildProto(gadgetInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(routeConfig!=null){
|
||||||
|
gadgetInfo.setPlatform(getPlatformInfo());
|
||||||
|
}
|
||||||
|
|
||||||
entityInfo.setGadget(gadgetInfo);
|
entityInfo.setGadget(gadgetInfo);
|
||||||
|
|
||||||
return entityInfo.build();
|
return entityInfo.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PlatformInfoOuterClass.PlatformInfo.Builder getPlatformInfo(){
|
||||||
|
if(routeConfig != null){
|
||||||
|
return routeConfig.toProto();
|
||||||
|
}
|
||||||
|
|
||||||
|
return PlatformInfoOuterClass.PlatformInfo.newBuilder();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,12 @@ import emu.grasscutter.data.common.PropGrowCurve;
|
|||||||
import emu.grasscutter.data.excels.EnvAnimalGatherConfigData;
|
import emu.grasscutter.data.excels.EnvAnimalGatherConfigData;
|
||||||
import emu.grasscutter.data.excels.monster.MonsterCurveData;
|
import emu.grasscutter.data.excels.monster.MonsterCurveData;
|
||||||
import emu.grasscutter.data.excels.monster.MonsterData;
|
import emu.grasscutter.data.excels.monster.MonsterData;
|
||||||
|
import emu.grasscutter.game.dungeons.enums.DungeonPassConditionType;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.*;
|
import emu.grasscutter.game.props.*;
|
||||||
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
|
import emu.grasscutter.game.world.SceneGroupInstance;
|
||||||
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo;
|
||||||
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair;
|
||||||
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo;
|
||||||
@ -22,32 +25,36 @@ import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
|||||||
import emu.grasscutter.net.proto.SceneMonsterInfoOuterClass.SceneMonsterInfo;
|
import emu.grasscutter.net.proto.SceneMonsterInfoOuterClass.SceneMonsterInfo;
|
||||||
import emu.grasscutter.net.proto.SceneWeaponInfoOuterClass.SceneWeaponInfo;
|
import emu.grasscutter.net.proto.SceneWeaponInfoOuterClass.SceneWeaponInfo;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
|
import emu.grasscutter.scripts.data.SceneMonster;
|
||||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
|
import emu.grasscutter.server.event.entity.EntityDamageEvent;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import emu.grasscutter.utils.ProtoHelper;
|
import emu.grasscutter.utils.ProtoHelper;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||||
import java.util.Optional;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
public class EntityMonster extends GameEntity {
|
import java.util.Optional;
|
||||||
@Getter private final MonsterData monsterData;
|
|
||||||
|
|
||||||
@Getter(onMethod_ = @Override)
|
import static emu.grasscutter.scripts.constants.EventType.EVENT_SPECIFIC_MONSTER_HP_CHANGE;
|
||||||
|
|
||||||
|
public class EntityMonster extends GameEntity {
|
||||||
|
@Getter(onMethod = @__(@Override))
|
||||||
private final Int2FloatOpenHashMap fightProperties;
|
private final Int2FloatOpenHashMap fightProperties;
|
||||||
|
|
||||||
@Getter(onMethod_ = @Override)
|
@Getter(onMethod = @__(@Override))
|
||||||
private final Position position;
|
private final Position position;
|
||||||
|
@Getter(onMethod = @__(@Override))
|
||||||
@Getter(onMethod_ = @Override)
|
|
||||||
private final Position rotation;
|
private final Position rotation;
|
||||||
|
@Getter private final MonsterData monsterData;
|
||||||
@Getter private final Position bornPos;
|
@Getter private final Position bornPos;
|
||||||
@Getter private final int level;
|
@Getter private final int level;
|
||||||
private int weaponEntityId;
|
@Getter private int weaponEntityId;
|
||||||
@Getter @Setter private int poseId;
|
@Getter @Setter private int poseId;
|
||||||
@Getter @Setter private int aiId = -1;
|
@Getter @Setter private int aiId = -1;
|
||||||
|
|
||||||
|
@Getter @Setter private SceneMonster metaMonster;
|
||||||
|
|
||||||
public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) {
|
public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) {
|
||||||
super(scene);
|
super(scene);
|
||||||
this.id = getWorld().getNextEntityId(EntityIdType.MONSTER);
|
this.id = getWorld().getNextEntityId(EntityIdType.MONSTER);
|
||||||
@ -66,6 +73,11 @@ public class EntityMonster extends GameEntity {
|
|||||||
this.recalcStats();
|
this.recalcStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEntityTypeId() {
|
||||||
|
return getMonsterId();
|
||||||
|
}
|
||||||
|
|
||||||
public int getMonsterWeaponId() {
|
public int getMonsterWeaponId() {
|
||||||
return this.getMonsterData().getWeaponId();
|
return this.getMonsterData().getWeaponId();
|
||||||
}
|
}
|
||||||
@ -81,8 +93,7 @@ public class EntityMonster extends GameEntity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onInteract(Player player, GadgetInteractReq interactReq) {
|
public void onInteract(Player player, GadgetInteractReq interactReq) {
|
||||||
EnvAnimalGatherConfigData gatherData =
|
EnvAnimalGatherConfigData gatherData = GameData.getEnvAnimalGatherConfigDataMap().get(this.getMonsterData().getId());
|
||||||
GameData.getEnvAnimalGatherConfigDataMap().get(this.getMonsterData().getId());
|
|
||||||
|
|
||||||
if (gatherData == null) {
|
if (gatherData == null) {
|
||||||
return;
|
return;
|
||||||
@ -96,18 +107,16 @@ public class EntityMonster extends GameEntity {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
// Lua event
|
// Lua event
|
||||||
getScene()
|
getScene().getScriptManager().callEvent(new ScriptArgs(this.getGroupId(), EventType.EVENT_ANY_MONSTER_LIVE, this.getConfigId()));
|
||||||
.getScriptManager()
|
|
||||||
.callEvent(EventType.EVENT_ANY_MONSTER_LIVE, new ScriptArgs(this.getConfigId()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void damage(float amount, int killerId) {
|
public void damage(float amount, int killerId, ElementType attackType) {
|
||||||
// Get HP before damage.
|
// Get HP before damage.
|
||||||
float hpBeforeDamage = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
float hpBeforeDamage = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||||
|
|
||||||
// Apply damage.
|
// Apply damage.
|
||||||
super.damage(amount, killerId);
|
super.damage(amount, killerId, attackType);
|
||||||
|
|
||||||
// Get HP after damage.
|
// Get HP after damage.
|
||||||
float hpAfterDamage = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
float hpAfterDamage = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP);
|
||||||
@ -118,6 +127,15 @@ public class EntityMonster extends GameEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void runLuaCallbacks(EntityDamageEvent event) {
|
||||||
|
super.runLuaCallbacks(event);
|
||||||
|
getScene().getScriptManager().callEvent(new ScriptArgs(this.getGroupId(), EVENT_SPECIFIC_MONSTER_HP_CHANGE, getConfigId(), monsterData.getId())
|
||||||
|
.setSourceEntityId(getId())
|
||||||
|
.setParam3((int) this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP))
|
||||||
|
.setEventSource(Integer.toString(getConfigId())));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeath(int killerId) {
|
public void onDeath(int killerId) {
|
||||||
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
super.onDeath(killerId); // Invoke super class's onDeath() method.
|
||||||
@ -131,22 +149,29 @@ public class EntityMonster extends GameEntity {
|
|||||||
challenge.ifPresent(c -> c.onMonsterDeath(this));
|
challenge.ifPresent(c -> c.onMonsterDeath(this));
|
||||||
|
|
||||||
if (scriptManager.isInit() && this.getGroupId() > 0) {
|
if (scriptManager.isInit() && this.getGroupId() > 0) {
|
||||||
Optional.ofNullable(scriptManager.getScriptMonsterSpawnService())
|
Optional.ofNullable(scriptManager.getScriptMonsterSpawnService()).ifPresent(s -> s.onMonsterDead(this));
|
||||||
.ifPresent(s -> s.onMonsterDead(this));
|
|
||||||
|
|
||||||
// prevent spawn monster after success
|
// prevent spawn monster after success
|
||||||
if (challenge.map(c -> c.inProgress()).orElse(true))
|
/*if (challenge.map(c -> c.inProgress()).orElse(true)) {
|
||||||
scriptManager.callEvent(
|
scriptManager.callEvent(new ScriptArgs(EventType.EVENT_ANY_MONSTER_DIE, this.getConfigId()).setGroupId(this.getGroupId()));
|
||||||
EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId()));
|
} else if (getScene().getChallenge() == null) {
|
||||||
|
}*/
|
||||||
|
scriptManager.callEvent(new ScriptArgs(this.getGroupId(), EventType.EVENT_ANY_MONSTER_DIE, this.getConfigId()));
|
||||||
}
|
}
|
||||||
// Battle Pass trigger
|
// Battle Pass trigger
|
||||||
scene
|
scene.getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_MONSTER_DIE, this.getMonsterId(), 1));
|
||||||
.getPlayers()
|
|
||||||
.forEach(
|
scene.getPlayers().forEach(p -> p.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_MONSTER_DIE, this.getMonsterId()));
|
||||||
p ->
|
scene.getPlayers().forEach(p -> p.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_KILL_MONSTER, this.getMonsterId()));
|
||||||
p.getBattlePassManager()
|
scene.getPlayers().forEach(p -> p.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_CLEAR_GROUP_MONSTER, this.getGroupId()));
|
||||||
.triggerMission(
|
|
||||||
WatcherTriggerType.TRIGGER_MONSTER_DIE, this.getMonsterId(), 1));
|
SceneGroupInstance groupInstance = scene.getScriptManager().getGroupInstanceById(this.getGroupId());
|
||||||
|
if(groupInstance != null && metaMonster != null)
|
||||||
|
groupInstance.getDeadEntities().add(metaMonster.config_id);
|
||||||
|
|
||||||
|
scene.triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_KILL_GROUP_MONSTER, this.getGroupId());
|
||||||
|
scene.triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_KILL_TYPE_MONSTER, this.getMonsterData().getType().getValue());
|
||||||
|
scene.triggerDungeonEvent(DungeonPassConditionType.DUNGEON_COND_KILL_MONSTER, this.getMonsterId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void recalcStats() {
|
public void recalcStats() {
|
||||||
@ -154,59 +179,41 @@ public class EntityMonster extends GameEntity {
|
|||||||
MonsterData data = this.getMonsterData();
|
MonsterData data = this.getMonsterData();
|
||||||
|
|
||||||
// Get hp percent, set to 100% if none
|
// Get hp percent, set to 100% if none
|
||||||
float hpPercent =
|
float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
||||||
this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0
|
|
||||||
? 1f
|
|
||||||
: this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP)
|
|
||||||
/ this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP);
|
|
||||||
|
|
||||||
// Clear properties
|
// Clear properties
|
||||||
this.getFightProperties().clear();
|
this.getFightProperties().clear();
|
||||||
|
|
||||||
// Base stats
|
// Base stats
|
||||||
MonsterData.definedFightProperties.forEach(
|
MonsterData.definedFightProperties.forEach(prop -> this.setFightProperty(prop, data.getFightProperty(prop)));
|
||||||
prop -> this.setFightProperty(prop, data.getFightProperty(prop)));
|
|
||||||
|
|
||||||
// Level curve
|
// Level curve
|
||||||
MonsterCurveData curve = GameData.getMonsterCurveDataMap().get(this.getLevel());
|
MonsterCurveData curve = GameData.getMonsterCurveDataMap().get(this.getLevel());
|
||||||
if (curve != null) {
|
if (curve != null) {
|
||||||
for (PropGrowCurve growCurve : data.getPropGrowCurves()) {
|
for (PropGrowCurve growCurve : data.getPropGrowCurves()) {
|
||||||
FightProperty prop = FightProperty.getPropByName(growCurve.getType());
|
FightProperty prop = FightProperty.getPropByName(growCurve.getType());
|
||||||
this.setFightProperty(
|
this.setFightProperty(prop, this.getFightProperty(prop) * curve.getMultByProp(growCurve.getGrowCurve()));
|
||||||
prop, this.getFightProperty(prop) * curve.getMultByProp(growCurve.getGrowCurve()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set % stats
|
// Set % stats
|
||||||
FightProperty.forEachCompoundProperty(
|
FightProperty.forEachCompoundProperty(c -> this.setFightProperty(c.getResult(),
|
||||||
c ->
|
this.getFightProperty(c.getFlat()) + (this.getFightProperty(c.getBase()) * (1f + this.getFightProperty(c.getPercent())))));
|
||||||
this.setFightProperty(
|
|
||||||
c.getResult(),
|
|
||||||
this.getFightProperty(c.getFlat())
|
|
||||||
+ (this.getFightProperty(c.getBase())
|
|
||||||
* (1f + this.getFightProperty(c.getPercent())))));
|
|
||||||
|
|
||||||
// Set current hp
|
// Set current hp
|
||||||
this.setFightProperty(
|
this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent);
|
||||||
FightProperty.FIGHT_PROP_CUR_HP,
|
|
||||||
this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SceneEntityInfo toProto() {
|
public SceneEntityInfo toProto() {
|
||||||
var authority =
|
var authority = EntityAuthorityInfo.newBuilder()
|
||||||
EntityAuthorityInfo.newBuilder()
|
|
||||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||||
.setAiInfo(
|
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(this.getBornPos().toProto()))
|
||||||
SceneEntityAiInfo.newBuilder()
|
|
||||||
.setIsAiOpen(true)
|
|
||||||
.setBornPos(this.getBornPos().toProto()))
|
|
||||||
.setBornPos(this.getBornPos().toProto())
|
.setBornPos(this.getBornPos().toProto())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
var entityInfo =
|
var entityInfo = SceneEntityInfo.newBuilder()
|
||||||
SceneEntityInfo.newBuilder()
|
|
||||||
.setEntityId(getId())
|
.setEntityId(getId())
|
||||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_MONSTER)
|
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_MONSTER)
|
||||||
.setMotionInfo(this.getMotionInfo())
|
.setMotionInfo(this.getMotionInfo())
|
||||||
@ -217,31 +224,29 @@ public class EntityMonster extends GameEntity {
|
|||||||
|
|
||||||
this.addAllFightPropsToEntityInfo(entityInfo);
|
this.addAllFightPropsToEntityInfo(entityInfo);
|
||||||
|
|
||||||
entityInfo.addPropList(
|
entityInfo.addPropList(PropPair.newBuilder()
|
||||||
PropPair.newBuilder()
|
|
||||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getLevel()))
|
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getLevel()))
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
var monsterInfo =
|
var monsterInfo = SceneMonsterInfo.newBuilder()
|
||||||
SceneMonsterInfo.newBuilder()
|
|
||||||
.setMonsterId(getMonsterId())
|
.setMonsterId(getMonsterId())
|
||||||
.setGroupId(this.getGroupId())
|
.setGroupId(this.getGroupId())
|
||||||
.setConfigId(this.getConfigId())
|
.setConfigId(this.getConfigId())
|
||||||
.addAllAffixList(getMonsterData().getAffix())
|
.addAllAffixList(getMonsterData().getAffix())
|
||||||
.setAuthorityPeerId(getWorld().getHostPeerId())
|
.setAuthorityPeerId(getWorld().getHostPeerId())
|
||||||
.setPoseId(this.getPoseId())
|
.setPoseId(this.getPoseId())
|
||||||
.setBlockId(3001)
|
.setBlockId(getScene().getId())
|
||||||
.setBornType(MonsterBornType.MONSTER_BORN_TYPE_DEFAULT)
|
.setBornType(MonsterBornType.MONSTER_BORN_TYPE_DEFAULT);
|
||||||
.setSpecialNameId(40);
|
|
||||||
|
|
||||||
if (getMonsterData().getDescribeData() != null) {
|
if (getMonsterData().getDescribeData() != null) {
|
||||||
monsterInfo.setTitleId(getMonsterData().getDescribeData().getTitleID());
|
monsterInfo.setTitleId(getMonsterData().getDescribeData().getTitleId())
|
||||||
|
.setSpecialNameId(getMonsterData().getSpecialNameId());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getMonsterWeaponId() > 0) {
|
if (this.getMonsterWeaponId() > 0) {
|
||||||
SceneWeaponInfo weaponInfo =
|
SceneWeaponInfo weaponInfo = SceneWeaponInfo.newBuilder()
|
||||||
SceneWeaponInfo.newBuilder()
|
|
||||||
.setEntityId(this.weaponEntityId)
|
.setEntityId(this.weaponEntityId)
|
||||||
.setGadgetId(this.getMonsterWeaponId())
|
.setGadgetId(this.getMonsterWeaponId())
|
||||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||||
|
@ -30,6 +30,11 @@ public class EntityNPC extends GameEntity {
|
|||||||
this.metaNpc = metaNPC;
|
this.metaNpc = metaNPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEntityTypeId() {
|
||||||
|
return this.metaNpc.npc_id;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Int2FloatMap getFightProperties() {
|
public Int2FloatMap getFightProperties() {
|
||||||
return null;
|
return null;
|
||||||
|
@ -20,15 +20,21 @@ public class EntityRegion extends GameEntity {
|
|||||||
|
|
||||||
public EntityRegion(Scene scene, SceneRegion region) {
|
public EntityRegion(Scene scene, SceneRegion region) {
|
||||||
super(scene);
|
super(scene);
|
||||||
|
|
||||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.REGION);
|
this.id = getScene().getWorld().getNextEntityId(EntityIdType.REGION);
|
||||||
setGroupId(region.group.id);
|
this.setGroupId(region.group.id);
|
||||||
setBlockId(region.group.block_id);
|
this.setBlockId(region.group.block_id);
|
||||||
setConfigId(region.config_id);
|
this.setConfigId(region.config_id);
|
||||||
this.position = region.pos.clone();
|
this.position = region.pos.clone();
|
||||||
this.entities = ConcurrentHashMap.newKeySet();
|
this.entities = ConcurrentHashMap.newKeySet();
|
||||||
this.metaRegion = region;
|
this.metaRegion = region;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEntityTypeId() {
|
||||||
|
return this.metaRegion.config_id;
|
||||||
|
}
|
||||||
|
|
||||||
public void addEntity(GameEntity entity) {
|
public void addEntity(GameEntity entity) {
|
||||||
if (this.getEntities().contains(entity.getId())) {
|
if (this.getEntities().contains(entity.getId())) {
|
||||||
return;
|
return;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.platform.EntityPlatform;
|
|
||||||
import emu.grasscutter.game.entity.platform.EntitySolarIsotomaElevatorPlatform;
|
import emu.grasscutter.game.entity.platform.EntitySolarIsotomaElevatorPlatform;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
@ -10,25 +9,22 @@ import lombok.Getter;
|
|||||||
public class EntitySolarIsotomaClientGadget extends EntityClientGadget {
|
public class EntitySolarIsotomaClientGadget extends EntityClientGadget {
|
||||||
public static final int GADGET_ID = 41038001;
|
public static final int GADGET_ID = 41038001;
|
||||||
public static final int ELEVATOR_GADGET_ID = 41038002;
|
public static final int ELEVATOR_GADGET_ID = 41038002;
|
||||||
@Getter private EntityPlatform platformGadget;
|
@Getter private EntityGadget platformGadget;
|
||||||
|
|
||||||
public EntitySolarIsotomaClientGadget(
|
public EntitySolarIsotomaClientGadget(Scene scene, Player player, EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify notify) {
|
||||||
Scene scene, Player player, EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify notify) {
|
|
||||||
super(scene, player, notify);
|
super(scene, player, notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
// Create solar isotoma elevator and send to all.
|
//Create solar isotoma elevator and send to all.
|
||||||
this.platformGadget =
|
this.platformGadget = new EntitySolarIsotomaElevatorPlatform(this, getScene(), ELEVATOR_GADGET_ID, getPosition(), getRotation());
|
||||||
new EntitySolarIsotomaElevatorPlatform(
|
|
||||||
this, getScene(), getOwner(), ELEVATOR_GADGET_ID, getPosition(), getRotation());
|
|
||||||
getScene().addEntity(this.platformGadget);
|
getScene().addEntity(this.platformGadget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRemoved() {
|
public void onRemoved() {
|
||||||
// Remove solar isotoma elevator entity.
|
//Remove solar isotoma elevator entity.
|
||||||
getScene().removeEntity(this.platformGadget);
|
getScene().removeEntity(this.platformGadget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.binout.ConfigGadget;
|
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
||||||
import emu.grasscutter.data.excels.GadgetData;
|
import emu.grasscutter.data.excels.GadgetData;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.props.EntityIdType;
|
import emu.grasscutter.game.props.EntityIdType;
|
||||||
@ -25,17 +25,17 @@ import emu.grasscutter.utils.Position;
|
|||||||
import emu.grasscutter.utils.ProtoHelper;
|
import emu.grasscutter.utils.ProtoHelper;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class EntityVehicle extends EntityBaseGadget {
|
public class EntityVehicle extends EntityBaseGadget {
|
||||||
|
|
||||||
@Getter private final Player owner;
|
@Getter private final Player owner;
|
||||||
|
@Getter(onMethod = @__(@Override))
|
||||||
@Getter(onMethod_ = @Override)
|
|
||||||
private final Int2FloatMap fightProperties;
|
private final Int2FloatMap fightProperties;
|
||||||
|
|
||||||
@Getter private final int pointId;
|
@Getter private final int pointId;
|
||||||
@ -43,10 +43,9 @@ public class EntityVehicle extends EntityBaseGadget {
|
|||||||
|
|
||||||
@Getter @Setter private float curStamina;
|
@Getter @Setter private float curStamina;
|
||||||
@Getter private final List<VehicleMember> vehicleMembers;
|
@Getter private final List<VehicleMember> vehicleMembers;
|
||||||
@Nullable @Getter private ConfigGadget configGadget;
|
@Nullable @Getter private ConfigEntityGadget configGadget;
|
||||||
|
|
||||||
public EntityVehicle(
|
public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) {
|
||||||
Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) {
|
|
||||||
super(scene, pos, rot);
|
super(scene, pos, rot);
|
||||||
this.owner = player;
|
this.owner = player;
|
||||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
||||||
@ -64,7 +63,7 @@ public class EntityVehicle extends EntityBaseGadget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void fillFightProps(ConfigGadget configGadget) {
|
protected void fillFightProps(ConfigEntityGadget configGadget) {
|
||||||
super.fillFightProps(configGadget);
|
super.fillFightProps(configGadget);
|
||||||
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_SPEED, 0);
|
this.addFightProperty(FightProperty.FIGHT_PROP_CUR_SPEED, 0);
|
||||||
this.addFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, 0);
|
this.addFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, 0);
|
||||||
@ -73,46 +72,34 @@ public class EntityVehicle extends EntityBaseGadget {
|
|||||||
@Override
|
@Override
|
||||||
public SceneEntityInfo toProto() {
|
public SceneEntityInfo toProto() {
|
||||||
|
|
||||||
VehicleInfo vehicle =
|
VehicleInfo vehicle = VehicleInfo.newBuilder()
|
||||||
VehicleInfo.newBuilder()
|
|
||||||
.setOwnerUid(this.owner.getUid())
|
.setOwnerUid(this.owner.getUid())
|
||||||
.setCurStamina(getCurStamina())
|
.setCurStamina(getCurStamina())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
EntityAuthorityInfo authority =
|
EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder()
|
||||||
EntityAuthorityInfo.newBuilder()
|
|
||||||
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
.setAbilityInfo(AbilitySyncStateInfo.newBuilder())
|
||||||
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
.setRendererChangedInfo(EntityRendererChangedInfo.newBuilder())
|
||||||
.setAiInfo(
|
.setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(getPosition().toProto()))
|
||||||
SceneEntityAiInfo.newBuilder()
|
|
||||||
.setIsAiOpen(true)
|
|
||||||
.setBornPos(getPosition().toProto()))
|
|
||||||
.setBornPos(getPosition().toProto())
|
.setBornPos(getPosition().toProto())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
SceneGadgetInfo.Builder gadgetInfo =
|
SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder()
|
||||||
SceneGadgetInfo.newBuilder()
|
|
||||||
.setGadgetId(this.getGadgetId())
|
.setGadgetId(this.getGadgetId())
|
||||||
.setAuthorityPeerId(this.getOwner().getPeerId())
|
.setAuthorityPeerId(this.getOwner().getPeerId())
|
||||||
.setIsEnableInteract(true)
|
.setIsEnableInteract(true)
|
||||||
.setVehicleInfo(vehicle);
|
.setVehicleInfo(vehicle);
|
||||||
|
|
||||||
SceneEntityInfo.Builder entityInfo =
|
SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder()
|
||||||
SceneEntityInfo.newBuilder()
|
|
||||||
.setEntityId(getId())
|
.setEntityId(getId())
|
||||||
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
.setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
||||||
.setMotionInfo(
|
.setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder()))
|
||||||
MotionInfo.newBuilder()
|
|
||||||
.setPos(getPosition().toProto())
|
|
||||||
.setRot(getRotation().toProto())
|
|
||||||
.setSpeed(Vector.newBuilder()))
|
|
||||||
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
.addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder())
|
||||||
.setGadget(gadgetInfo)
|
.setGadget(gadgetInfo)
|
||||||
.setEntityAuthorityInfo(authority)
|
.setEntityAuthorityInfo(authority)
|
||||||
.setLifeState(1);
|
.setLifeState(1);
|
||||||
|
|
||||||
PropPair pair =
|
PropPair pair = PropPair.newBuilder()
|
||||||
PropPair.newBuilder()
|
|
||||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
.setType(PlayerProperty.PROP_LEVEL.getId())
|
||||||
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 47))
|
.setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 47))
|
||||||
.build();
|
.build();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package emu.grasscutter.game.entity;
|
package emu.grasscutter.game.entity;
|
||||||
|
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
|
import emu.grasscutter.game.props.ElementType;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
import emu.grasscutter.game.props.LifeState;
|
import emu.grasscutter.game.props.LifeState;
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
@ -12,6 +13,7 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
|
|||||||
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
|
import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState;
|
||||||
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
|
||||||
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
import emu.grasscutter.net.proto.VectorOuterClass.Vector;
|
||||||
|
import emu.grasscutter.scripts.data.controller.EntityController;
|
||||||
import emu.grasscutter.server.event.entity.EntityDamageEvent;
|
import emu.grasscutter.server.event.entity.EntityDamageEvent;
|
||||||
import emu.grasscutter.server.event.entity.EntityDeathEvent;
|
import emu.grasscutter.server.event.entity.EntityDeathEvent;
|
||||||
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify;
|
||||||
@ -39,6 +41,10 @@ public abstract class GameEntity {
|
|||||||
|
|
||||||
@Getter @Setter private boolean lockHP;
|
@Getter @Setter private boolean lockHP;
|
||||||
|
|
||||||
|
// Lua controller for specific actions
|
||||||
|
@Getter @Setter private EntityController entityController;
|
||||||
|
@Getter private ElementType lastAttackType = ElementType.None;
|
||||||
|
|
||||||
// Abilities
|
// Abilities
|
||||||
private Object2FloatMap<String> metaOverrideMap;
|
private Object2FloatMap<String> metaOverrideMap;
|
||||||
private Int2ObjectMap<String> metaModifiers;
|
private Int2ObjectMap<String> metaModifiers;
|
||||||
@ -52,6 +58,8 @@ public abstract class GameEntity {
|
|||||||
return this.getId() >> 24;
|
return this.getId() >> 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract int getEntityTypeId();
|
||||||
|
|
||||||
public World getWorld() {
|
public World getWorld() {
|
||||||
return this.getScene().getWorld();
|
return this.getScene().getWorld();
|
||||||
}
|
}
|
||||||
@ -115,15 +123,12 @@ public abstract class GameEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected MotionInfo getMotionInfo() {
|
protected MotionInfo getMotionInfo() {
|
||||||
MotionInfo proto =
|
return MotionInfo.newBuilder()
|
||||||
MotionInfo.newBuilder()
|
|
||||||
.setPos(this.getPosition().toProto())
|
.setPos(this.getPosition().toProto())
|
||||||
.setRot(this.getRotation().toProto())
|
.setRot(this.getRotation().toProto())
|
||||||
.setSpeed(Vector.newBuilder())
|
.setSpeed(Vector.newBuilder())
|
||||||
.setState(this.getMotionState())
|
.setState(this.getMotionState())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
return proto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public float heal(float amount) {
|
public float heal(float amount) {
|
||||||
@ -149,10 +154,10 @@ public abstract class GameEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void damage(float amount) {
|
public void damage(float amount) {
|
||||||
this.damage(amount, 0);
|
this.damage(amount, 0, ElementType.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void damage(float amount, int killerId) {
|
public void damage(float amount, int killerId, ElementType attackType) {
|
||||||
// Check if the entity has properties.
|
// Check if the entity has properties.
|
||||||
if (this.getFightProperties() == null || !hasFightProperty(FightProperty.FIGHT_PROP_CUR_HP)) {
|
if (this.getFightProperties() == null || !hasFightProperty(FightProperty.FIGHT_PROP_CUR_HP)) {
|
||||||
return;
|
return;
|
||||||
@ -160,7 +165,7 @@ public abstract class GameEntity {
|
|||||||
|
|
||||||
// Invoke entity damage event.
|
// Invoke entity damage event.
|
||||||
EntityDamageEvent event =
|
EntityDamageEvent event =
|
||||||
new EntityDamageEvent(this, amount, this.getScene().getEntityById(killerId));
|
new EntityDamageEvent(this, amount, attackType, this.getScene().getEntityById(killerId));
|
||||||
event.call();
|
event.call();
|
||||||
if (event.isCanceled()) {
|
if (event.isCanceled()) {
|
||||||
return; // If the event is canceled, do not damage the entity.
|
return; // If the event is canceled, do not damage the entity.
|
||||||
@ -190,6 +195,17 @@ public abstract class GameEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the Lua callbacks for {@link EntityDamageEvent}.
|
||||||
|
*
|
||||||
|
* @param event The damage event.
|
||||||
|
*/
|
||||||
|
public void runLuaCallbacks(EntityDamageEvent event) {
|
||||||
|
if (entityController != null) {
|
||||||
|
entityController.onBeHurt(this, event.getAttackElementType(), true);//todo is host handling
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Move this entity to a new position.
|
* Move this entity to a new position.
|
||||||
*
|
*
|
||||||
@ -215,6 +231,19 @@ public abstract class GameEntity {
|
|||||||
|
|
||||||
public void onRemoved() {}
|
public void onRemoved() {}
|
||||||
|
|
||||||
|
public void onTick(int sceneTime) {
|
||||||
|
if (entityController != null) {
|
||||||
|
entityController.onTimer(this, sceneTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int onClientExecuteRequest(int param1, int param2, int param3) {
|
||||||
|
if (entityController != null) {
|
||||||
|
return entityController.onClientExecuteRequest(this, param1, param2, param3);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when this entity dies
|
* Called when this entity dies
|
||||||
*
|
*
|
||||||
@ -224,6 +253,11 @@ public abstract class GameEntity {
|
|||||||
// Invoke entity death event.
|
// Invoke entity death event.
|
||||||
EntityDeathEvent event = new EntityDeathEvent(this, killerId);
|
EntityDeathEvent event = new EntityDeathEvent(this, killerId);
|
||||||
event.call();
|
event.call();
|
||||||
|
|
||||||
|
// Run Lua callbacks.
|
||||||
|
if (entityController != null) {
|
||||||
|
entityController.onDie(this, getLastAttackType());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract SceneEntityInfo toProto();
|
public abstract SceneEntityInfo toProto();
|
||||||
|
@ -5,19 +5,22 @@ import emu.grasscutter.game.entity.EntityGadget;
|
|||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq;
|
||||||
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
||||||
|
import emu.grasscutter.net.proto.ResinCostTypeOuterClass;
|
||||||
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo;
|
||||||
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
|
import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp;
|
||||||
|
|
||||||
public class GadgetRewardStatue extends GadgetContent {
|
public final class GadgetRewardStatue extends GadgetContent {
|
||||||
|
|
||||||
public GadgetRewardStatue(EntityGadget gadget) {
|
public GadgetRewardStatue(EntityGadget gadget) {
|
||||||
super(gadget);
|
super(gadget);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onInteract(Player player, GadgetInteractReq req) {
|
public boolean onInteract(Player player, GadgetInteractReq req) {
|
||||||
if (player.getScene().getChallenge() != null
|
var dungeonManager = player.getScene().getDungeonManager();
|
||||||
&& player.getScene().getChallenge() instanceof DungeonChallenge dungeonChallenge) {
|
|
||||||
dungeonChallenge.getStatueDrops(player, req);
|
if (player.getScene().getChallenge() instanceof DungeonChallenge) {
|
||||||
|
var useCondensed = req.getResinCostType() == ResinCostTypeOuterClass.ResinCostType.RESIN_COST_TYPE_CONDENSE;
|
||||||
|
dungeonManager.getStatueDrops(player, useCondensed, getGadget().getGroupId());
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendPacket(
|
player.sendPacket(
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
package emu.grasscutter.game.entity.platform;
|
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
|
||||||
import emu.grasscutter.data.binout.ConfigGadget;
|
|
||||||
import emu.grasscutter.data.excels.GadgetData;
|
|
||||||
import emu.grasscutter.game.entity.EntityBaseGadget;
|
|
||||||
import emu.grasscutter.game.entity.EntityClientGadget;
|
|
||||||
import emu.grasscutter.game.player.Player;
|
|
||||||
import emu.grasscutter.game.props.EntityIdType;
|
|
||||||
import emu.grasscutter.game.world.Scene;
|
|
||||||
import emu.grasscutter.net.proto.*;
|
|
||||||
import emu.grasscutter.utils.Position;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatMap;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
|
|
||||||
public class EntityPlatform extends EntityBaseGadget {
|
|
||||||
@Getter private final Player owner;
|
|
||||||
|
|
||||||
@Getter(onMethod_ = @Override)
|
|
||||||
private final int gadgetId;
|
|
||||||
|
|
||||||
@Getter private final EntityClientGadget gadget;
|
|
||||||
|
|
||||||
@Getter(onMethod_ = @Override)
|
|
||||||
private final Int2FloatMap fightProperties;
|
|
||||||
|
|
||||||
@Getter private final MovingPlatformTypeOuterClass.MovingPlatformType movingPlatformType;
|
|
||||||
@Nullable @Getter private ConfigGadget configGadget;
|
|
||||||
@Getter @Setter private boolean isStarted;
|
|
||||||
@Getter @Setter private boolean isActive;
|
|
||||||
|
|
||||||
public EntityPlatform(
|
|
||||||
EntityClientGadget gadget,
|
|
||||||
Scene scene,
|
|
||||||
Player player,
|
|
||||||
int gadgetId,
|
|
||||||
Position pos,
|
|
||||||
Position rot,
|
|
||||||
MovingPlatformTypeOuterClass.MovingPlatformType movingPlatformType) {
|
|
||||||
super(scene, pos, rot);
|
|
||||||
this.gadget = gadget;
|
|
||||||
this.owner = player;
|
|
||||||
this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET);
|
|
||||||
this.fightProperties = new Int2FloatOpenHashMap();
|
|
||||||
this.movingPlatformType = movingPlatformType;
|
|
||||||
this.gadgetId = gadgetId;
|
|
||||||
GadgetData data = GameData.getGadgetDataMap().get(gadgetId);
|
|
||||||
if (data != null && data.getJsonName() != null) {
|
|
||||||
this.configGadget = GameData.getGadgetConfigData().get(data.getJsonName());
|
|
||||||
}
|
|
||||||
|
|
||||||
fillFightProps(configGadget);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {
|
|
||||||
var platform =
|
|
||||||
PlatformInfoOuterClass.PlatformInfo.newBuilder()
|
|
||||||
.setMovingPlatformType(movingPlatformType)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var gadgetInfo =
|
|
||||||
SceneGadgetInfoOuterClass.SceneGadgetInfo.newBuilder()
|
|
||||||
.setGadgetId(getGadgetId())
|
|
||||||
.setAuthorityPeerId(getOwner().getPeerId())
|
|
||||||
.setPlatform(platform);
|
|
||||||
|
|
||||||
var entityInfo =
|
|
||||||
SceneEntityInfoOuterClass.SceneEntityInfo.newBuilder()
|
|
||||||
.setEntityId(getId())
|
|
||||||
.setEntityType(ProtEntityTypeOuterClass.ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
|
||||||
.setGadget(gadgetInfo)
|
|
||||||
.setLifeState(1);
|
|
||||||
|
|
||||||
this.addAllFightPropsToEntityInfo(entityInfo);
|
|
||||||
return entityInfo.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlatformInfoOuterClass.PlatformInfo onStartRoute() {
|
|
||||||
return PlatformInfoOuterClass.PlatformInfo.newBuilder()
|
|
||||||
.setStartSceneTime(getScene().getSceneTime())
|
|
||||||
.setIsStarted(true)
|
|
||||||
.setPosOffset(getPosition().toProto())
|
|
||||||
.setMovingPlatformType(getMovingPlatformType())
|
|
||||||
.setIsActive(true)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlatformInfoOuterClass.PlatformInfo onStopRoute() {
|
|
||||||
var sceneTime = getScene().getSceneTime();
|
|
||||||
return PlatformInfoOuterClass.PlatformInfo.newBuilder()
|
|
||||||
.setStartSceneTime(sceneTime)
|
|
||||||
.setStopSceneTime(sceneTime)
|
|
||||||
.setPosOffset(getPosition().toProto())
|
|
||||||
.setMovingPlatformType(getMovingPlatformType())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +1,23 @@
|
|||||||
package emu.grasscutter.game.entity.platform;
|
package emu.grasscutter.game.entity.platform;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.data.binout.ConfigGadget;
|
import emu.grasscutter.data.binout.config.ConfigEntityGadget;
|
||||||
import emu.grasscutter.game.entity.EntityAvatar;
|
import emu.grasscutter.game.entity.*;
|
||||||
import emu.grasscutter.game.entity.EntitySolarIsotomaClientGadget;
|
import emu.grasscutter.game.entity.gadget.GadgetAbility;
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
import emu.grasscutter.game.entity.gadget.platform.AbilityRoute;
|
||||||
import emu.grasscutter.game.player.Player;
|
|
||||||
import emu.grasscutter.game.props.PlayerProperty;
|
|
||||||
import emu.grasscutter.game.world.Scene;
|
import emu.grasscutter.game.world.Scene;
|
||||||
import emu.grasscutter.net.proto.*;
|
|
||||||
import emu.grasscutter.server.packet.send.PacketSceneTimeNotify;
|
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import emu.grasscutter.utils.ProtoHelper;
|
|
||||||
|
|
||||||
public class EntitySolarIsotomaElevatorPlatform extends EntityPlatform {
|
public class EntitySolarIsotomaElevatorPlatform extends EntityGadget {
|
||||||
public EntitySolarIsotomaElevatorPlatform(
|
public EntitySolarIsotomaElevatorPlatform(EntitySolarIsotomaClientGadget isotoma, Scene scene, int gadgetId, Position pos, Position rot) {
|
||||||
EntitySolarIsotomaClientGadget isotoma,
|
super(scene, gadgetId, pos, rot);
|
||||||
Scene scene,
|
setOwner(isotoma);
|
||||||
Player player,
|
this.setRouteConfig(new AbilityRoute(rot, false, false, pos));
|
||||||
int gadgetId,
|
this.setContent(new GadgetAbility(this, isotoma));
|
||||||
Position pos,
|
|
||||||
Position rot) {
|
|
||||||
super(
|
|
||||||
isotoma,
|
|
||||||
scene,
|
|
||||||
player,
|
|
||||||
gadgetId,
|
|
||||||
pos,
|
|
||||||
rot,
|
|
||||||
MovingPlatformTypeOuterClass.MovingPlatformType.MOVING_PLATFORM_TYPE_ABILITY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void fillFightProps(ConfigGadget configGadget) {
|
protected void fillFightProps(ConfigEntityGadget configGadget) {
|
||||||
if (configGadget == null || configGadget.getCombat() == null) {
|
if (configGadget == null || configGadget.getCombat() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -40,10 +25,10 @@ public class EntitySolarIsotomaElevatorPlatform extends EntityPlatform {
|
|||||||
var combatProperties = combatData.getProperty();
|
var combatProperties = combatData.getProperty();
|
||||||
|
|
||||||
if (combatProperties.isUseCreatorProperty()) {
|
if (combatProperties.isUseCreatorProperty()) {
|
||||||
// If useCreatorProperty == true, use owner's property;
|
//If useCreatorProperty == true, use owner's property;
|
||||||
GameEntity ownerAvatar = getScene().getEntityById(getGadget().getOwnerEntityId());
|
GameEntity ownerEntity = getOwner();
|
||||||
if (ownerAvatar != null) {
|
if (ownerEntity != null) {
|
||||||
getFightProperties().putAll(ownerAvatar.getFightProperties());
|
getFightProperties().putAll(ownerEntity.getFightProperties());
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
Grasscutter.getLogger().warn("Why gadget owner is null?");
|
Grasscutter.getLogger().warn("Why gadget owner is null?");
|
||||||
@ -52,102 +37,4 @@ public class EntitySolarIsotomaElevatorPlatform extends EntityPlatform {
|
|||||||
|
|
||||||
super.fillFightProps(configGadget);
|
super.fillFightProps(configGadget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public SceneEntityInfoOuterClass.SceneEntityInfo toProto() {
|
|
||||||
var gadget =
|
|
||||||
SceneGadgetInfoOuterClass.SceneGadgetInfo.newBuilder()
|
|
||||||
.setGadgetId(getGadgetId())
|
|
||||||
.setOwnerEntityId(getGadget().getId())
|
|
||||||
.setAuthorityPeerId(getOwner().getPeerId())
|
|
||||||
.setIsEnableInteract(true)
|
|
||||||
.setAbilityGadget(
|
|
||||||
AbilityGadgetInfoOuterClass.AbilityGadgetInfo.newBuilder()
|
|
||||||
.setCampId(getGadget().getCampId())
|
|
||||||
.setCampTargetType(getGadget().getCampType())
|
|
||||||
.setTargetEntityId(getGadget().getId())
|
|
||||||
.build())
|
|
||||||
.setPlatform(
|
|
||||||
PlatformInfoOuterClass.PlatformInfo.newBuilder()
|
|
||||||
.setStartRot(
|
|
||||||
MathQuaternionOuterClass.MathQuaternion.newBuilder().setW(1.0F).build())
|
|
||||||
.setPosOffset(getGadget().getPosition().toProto())
|
|
||||||
.setRotOffset(
|
|
||||||
MathQuaternionOuterClass.MathQuaternion.newBuilder().setW(1.0F).build())
|
|
||||||
.setMovingPlatformType(
|
|
||||||
MovingPlatformTypeOuterClass.MovingPlatformType
|
|
||||||
.MOVING_PLATFORM_TYPE_ABILITY)
|
|
||||||
.build())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var authority =
|
|
||||||
EntityAuthorityInfoOuterClass.EntityAuthorityInfo.newBuilder()
|
|
||||||
.setAiInfo(
|
|
||||||
SceneEntityAiInfoOuterClass.SceneEntityAiInfo.newBuilder()
|
|
||||||
.setIsAiOpen(true)
|
|
||||||
.setBornPos(getGadget().getPosition().toProto()))
|
|
||||||
.setBornPos(getGadget().getPosition().toProto())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
var info =
|
|
||||||
SceneEntityInfoOuterClass.SceneEntityInfo.newBuilder()
|
|
||||||
.setEntityType(ProtEntityTypeOuterClass.ProtEntityType.PROT_ENTITY_TYPE_GADGET)
|
|
||||||
.setEntityId(getId())
|
|
||||||
.setMotionInfo(
|
|
||||||
MotionInfoOuterClass.MotionInfo.newBuilder()
|
|
||||||
.setPos(getGadget().getPosition().toProto())
|
|
||||||
.setRot(getGadget().getRotation().toProto())
|
|
||||||
.build());
|
|
||||||
|
|
||||||
GameEntity entity = getScene().getEntityById(getGadget().getOwnerEntityId());
|
|
||||||
if (entity instanceof EntityAvatar avatar) {
|
|
||||||
info.addPropList(
|
|
||||||
PropPairOuterClass.PropPair.newBuilder()
|
|
||||||
.setType(PlayerProperty.PROP_LEVEL.getId())
|
|
||||||
.setPropValue(
|
|
||||||
ProtoHelper.newPropValue(
|
|
||||||
PlayerProperty.PROP_LEVEL, avatar.getAvatar().getLevel()))
|
|
||||||
.build());
|
|
||||||
} else {
|
|
||||||
Grasscutter.getLogger().warn("Why gadget owner doesn't exist?");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.addAllFightPropsToEntityInfo(info);
|
|
||||||
|
|
||||||
info.setLifeState(1).setGadget(gadget).setEntityAuthorityInfo(authority);
|
|
||||||
|
|
||||||
return info.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PlatformInfoOuterClass.PlatformInfo onStartRoute() {
|
|
||||||
setStarted(true);
|
|
||||||
setActive(true);
|
|
||||||
|
|
||||||
var sceneTime = getScene().getSceneTime();
|
|
||||||
getOwner().sendPacket(new PacketSceneTimeNotify(getOwner()));
|
|
||||||
|
|
||||||
return PlatformInfoOuterClass.PlatformInfo.newBuilder()
|
|
||||||
.setStartSceneTime(sceneTime + 300)
|
|
||||||
.setIsStarted(true)
|
|
||||||
.setPosOffset(getPosition().toProto())
|
|
||||||
.setRotOffset(MathQuaternionOuterClass.MathQuaternion.newBuilder().setW(1.0F).build())
|
|
||||||
.setMovingPlatformType(getMovingPlatformType())
|
|
||||||
.setIsActive(true)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PlatformInfoOuterClass.PlatformInfo onStopRoute() {
|
|
||||||
setStarted(false);
|
|
||||||
setActive(false);
|
|
||||||
|
|
||||||
return PlatformInfoOuterClass.PlatformInfo.newBuilder()
|
|
||||||
.setStartSceneTime(getScene().getSceneTime())
|
|
||||||
.setStopSceneTime(getScene().getSceneTime())
|
|
||||||
.setPosOffset(getPosition().toProto())
|
|
||||||
.setRotOffset(MathQuaternionOuterClass.MathQuaternion.newBuilder().setW(1.0F).build())
|
|
||||||
.setMovingPlatformType(getMovingPlatformType())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
package emu.grasscutter.game.managers.blossom;
|
package emu.grasscutter.game.managers.blossom;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.excels.monster.MonsterData;
|
|
||||||
import emu.grasscutter.data.excels.world.WorldLevelData;
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.ChallengeTrigger;
|
||||||
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterTrigger;
|
import emu.grasscutter.game.dungeons.challenge.trigger.KillMonsterCountTrigger;
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.entity.EntityMonster;
|
import emu.grasscutter.game.entity.EntityMonster;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.FightProperty;
|
||||||
@ -15,54 +13,48 @@ import emu.grasscutter.scripts.data.SceneGadget;
|
|||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
|
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
||||||
public class BlossomActivity {
|
public final class BlossomActivity {
|
||||||
|
|
||||||
private static final int BLOOMING_GADGET_ID = 70210109;
|
|
||||||
private final SceneGroup tempSceneGroup;
|
private final SceneGroup tempSceneGroup;
|
||||||
private final WorldChallenge challenge;
|
private final WorldChallenge challenge;
|
||||||
private final EntityGadget gadget;
|
private final EntityGadget gadget;
|
||||||
private final int goal;
|
|
||||||
private final int worldLevel;
|
|
||||||
private final List<EntityMonster> activeMonsters = new ArrayList<>();
|
|
||||||
private final Queue<Integer> candidateMonsters = new ArrayDeque<>();
|
|
||||||
private EntityGadget chest;
|
private EntityGadget chest;
|
||||||
private int step;
|
private int step;
|
||||||
|
private final int goal;
|
||||||
private int generatedCount;
|
private int generatedCount;
|
||||||
private boolean pass = false;
|
private final int worldLevel;
|
||||||
|
private boolean pass=false;
|
||||||
public BlossomActivity(
|
private final List<EntityMonster> activeMonsters = new ArrayList<>();
|
||||||
EntityGadget entityGadget, List<Integer> monsters, int timeout, int worldLevel) {
|
private final Queue<Integer> candidateMonsters = new ArrayDeque<>();
|
||||||
|
private static final int BLOOMING_GADGET_ID = 70210109;
|
||||||
|
public BlossomActivity(EntityGadget entityGadget, List<Integer> monsters, int timeout, int worldLevel) {
|
||||||
this.tempSceneGroup = new SceneGroup();
|
this.tempSceneGroup = new SceneGroup();
|
||||||
this.tempSceneGroup.id = entityGadget.getId();
|
this.tempSceneGroup.id = entityGadget.getId();
|
||||||
this.gadget = entityGadget;
|
this.gadget=entityGadget;
|
||||||
this.step = 0;
|
this.step=0;
|
||||||
this.goal = monsters.size();
|
this.goal = monsters.size();
|
||||||
this.candidateMonsters.addAll(monsters);
|
this.candidateMonsters.addAll(monsters);
|
||||||
this.worldLevel = worldLevel;
|
this.worldLevel = worldLevel;
|
||||||
ArrayList<ChallengeTrigger> challengeTriggers = new ArrayList<>();
|
ArrayList<ChallengeTrigger> challengeTriggers = new ArrayList<>();
|
||||||
this.challenge =
|
this.challenge = new WorldChallenge(entityGadget.getScene(),
|
||||||
new WorldChallenge(
|
|
||||||
entityGadget.getScene(),
|
|
||||||
tempSceneGroup,
|
tempSceneGroup,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
List.of(goal, timeout),
|
List.of(goal, timeout),
|
||||||
timeout,
|
timeout,
|
||||||
goal,
|
goal, challengeTriggers);
|
||||||
challengeTriggers);
|
challengeTriggers.add(new KillMonsterCountTrigger());
|
||||||
challengeTriggers.add(new KillMonsterTrigger());
|
//this.challengeTriggers.add(new InTimeTrigger());
|
||||||
// this.challengeTriggers.add(new InTimeTrigger());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public WorldChallenge getChallenge() {
|
public WorldChallenge getChallenge() {
|
||||||
return this.challenge;
|
return this.challenge;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMonsters(List<EntityMonster> monsters) {
|
public void setMonsters(List<EntityMonster> monsters) {
|
||||||
this.activeMonsters.clear();
|
this.activeMonsters.clear();
|
||||||
this.activeMonsters.addAll(monsters);
|
this.activeMonsters.addAll(monsters);
|
||||||
@ -70,53 +62,49 @@ public class BlossomActivity {
|
|||||||
monster.setGroupId(this.tempSceneGroup.id);
|
monster.setGroupId(this.tempSceneGroup.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getAliveMonstersCount() {
|
public int getAliveMonstersCount() {
|
||||||
int count = 0;
|
int count=0;
|
||||||
for (EntityMonster monster : activeMonsters) {
|
for (EntityMonster monster: activeMonsters) {
|
||||||
if (monster.isAlive()) {
|
if (monster.isAlive()) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getPass() {
|
public boolean getPass() {
|
||||||
return pass;
|
return pass;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void start() {
|
public void start() {
|
||||||
challenge.start();
|
challenge.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTick() {
|
public void onTick() {
|
||||||
Scene scene = gadget.getScene();
|
Scene scene = gadget.getScene();
|
||||||
Position pos = gadget.getPosition();
|
Position pos = gadget.getPosition();
|
||||||
if (getAliveMonstersCount() <= 2) {
|
if (getAliveMonstersCount() <= 2) {
|
||||||
if (generatedCount < goal) {
|
if (generatedCount<goal) {
|
||||||
step++;
|
step++;
|
||||||
|
|
||||||
WorldLevelData worldLevelData = GameData.getWorldLevelDataMap().get(worldLevel);
|
var worldLevelData = GameData.getWorldLevelDataMap().get(worldLevel);
|
||||||
int worldLevelOverride = 0;
|
int worldLevelOverride = 0;
|
||||||
if (worldLevelData != null) {
|
if (worldLevelData != null) {
|
||||||
worldLevelOverride = worldLevelData.getMonsterLevel();
|
worldLevelOverride = worldLevelData.getMonsterLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<EntityMonster> newMonsters = new ArrayList<>();
|
List<EntityMonster> newMonsters = new ArrayList<>();
|
||||||
int willSpawn = Utils.randomRange(3, 5);
|
int willSpawn = Utils.randomRange(3,5);
|
||||||
if (generatedCount + willSpawn > goal) {
|
if (generatedCount+willSpawn>goal) {
|
||||||
willSpawn = goal - generatedCount;
|
willSpawn = goal - generatedCount;
|
||||||
}
|
}
|
||||||
generatedCount += willSpawn;
|
generatedCount+=willSpawn;
|
||||||
for (int i = 0; i < willSpawn; i++) {
|
for (int i = 0; i < willSpawn; i++) {
|
||||||
MonsterData monsterData = GameData.getMonsterDataMap().get(candidateMonsters.poll());
|
var monsterData = GameData.getMonsterDataMap().get(candidateMonsters.poll());
|
||||||
int level = scene.getEntityLevel(1, worldLevelOverride);
|
int level = scene.getEntityLevel(1, worldLevelOverride);
|
||||||
EntityMonster entity = new EntityMonster(scene, monsterData, pos.nearby2d(4f), level);
|
EntityMonster entity = new EntityMonster(scene, monsterData, pos.nearby2d(4f), level);
|
||||||
scene.addEntity(entity);
|
scene.addEntity(entity);
|
||||||
newMonsters.add(entity);
|
newMonsters.add(entity);
|
||||||
}
|
}
|
||||||
setMonsters(newMonsters);
|
setMonsters(newMonsters);
|
||||||
} else {
|
}else {
|
||||||
if (getAliveMonstersCount() == 0) {
|
if (getAliveMonstersCount() == 0) {
|
||||||
this.pass = true;
|
this.pass = true;
|
||||||
this.challenge.done();
|
this.challenge.done();
|
||||||
@ -124,15 +112,12 @@ public class BlossomActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityGadget getGadget() {
|
public EntityGadget getGadget() {
|
||||||
return gadget;
|
return gadget;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntityGadget getChest() {
|
public EntityGadget getChest() {
|
||||||
if (chest == null) {
|
if (chest==null) {
|
||||||
EntityGadget rewardGadget =
|
EntityGadget rewardGadget = new EntityGadget(gadget.getScene(), BLOOMING_GADGET_ID, gadget.getPosition());
|
||||||
new EntityGadget(gadget.getScene(), BLOOMING_GADGET_ID, gadget.getPosition());
|
|
||||||
SceneGadget metaGadget = new SceneGadget();
|
SceneGadget metaGadget = new SceneGadget();
|
||||||
metaGadget.boss_chest = new SceneBossChest();
|
metaGadget.boss_chest = new SceneBossChest();
|
||||||
metaGadget.boss_chest.resin = 20;
|
metaGadget.boss_chest.resin = 20;
|
||||||
|
@ -30,6 +30,8 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
@ -40,7 +42,7 @@ public class EnergyManager extends BasePlayerManager {
|
|||||||
private static final Int2ObjectMap<List<SkillParticleGenerationInfo>>
|
private static final Int2ObjectMap<List<SkillParticleGenerationInfo>>
|
||||||
skillParticleGenerationData = new Int2ObjectOpenHashMap<>();
|
skillParticleGenerationData = new Int2ObjectOpenHashMap<>();
|
||||||
private final Object2IntMap<EntityAvatar> avatarNormalProbabilities;
|
private final Object2IntMap<EntityAvatar> avatarNormalProbabilities;
|
||||||
private boolean energyUsage; // Should energy usage be enabled for this player?
|
@Getter private boolean energyUsage; // Should energy usage be enabled for this player?
|
||||||
|
|
||||||
public EnergyManager(Player player) {
|
public EnergyManager(Player player) {
|
||||||
super(player);
|
super(player);
|
||||||
@ -381,8 +383,28 @@ public class EnergyManager extends BasePlayerManager {
|
|||||||
.findFirst();
|
.findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getEnergyUsage() {
|
/**
|
||||||
return this.energyUsage;
|
* Refills the energy of the active avatar.
|
||||||
|
*
|
||||||
|
* @return True if the energy was refilled, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean refillActiveEnergy() {
|
||||||
|
var activeEntity = this.player.getTeamManager().getCurrentAvatarEntity();
|
||||||
|
return activeEntity.addEnergy(activeEntity.getAvatar().getSkillDepot().getEnergySkillData().getCostElemVal());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refills the energy of the entire team.
|
||||||
|
*
|
||||||
|
* @param changeReason The reason for the energy change.
|
||||||
|
* @param isFlat Whether the energy should be added as a flat value.
|
||||||
|
*/
|
||||||
|
public void refillTeamEnergy(PropChangeReason changeReason, boolean isFlat) {
|
||||||
|
for (var entityAvatar : this.player.getTeamManager().getActiveTeam()) {
|
||||||
|
// giving the exact amount read off the AvatarSkillData.json
|
||||||
|
entityAvatar.addEnergy(entityAvatar.getAvatar().getSkillDepot()
|
||||||
|
.getEnergySkillData().getCostElemVal(), changeReason, isFlat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnergyUsage(boolean energyUsage) {
|
public void setEnergyUsage(boolean energyUsage) {
|
||||||
|
@ -294,7 +294,7 @@ public class StaminaManager extends BasePlayerManager {
|
|||||||
// Returns new stamina and sends PlayerPropNotify or VehicleStaminaNotify
|
// Returns new stamina and sends PlayerPropNotify or VehicleStaminaNotify
|
||||||
public int setStamina(GameSession session, String reason, int newStamina, boolean isCharacterStamina) {
|
public int setStamina(GameSession session, String reason, int newStamina, boolean isCharacterStamina) {
|
||||||
// Target Player
|
// Target Player
|
||||||
if (!GAME_OPTIONS.staminaUsage || session.getPlayer().getUnlimitedStamina()) {
|
if (!GAME_OPTIONS.staminaUsage || session.getPlayer().isUnlimitedStamina()) {
|
||||||
newStamina = getMaxCharacterStamina();
|
newStamina = getMaxCharacterStamina();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,6 @@ import emu.grasscutter.game.props.PlayerProperty;
|
|||||||
import emu.grasscutter.game.props.WatcherTriggerType;
|
import emu.grasscutter.game.props.WatcherTriggerType;
|
||||||
import emu.grasscutter.game.quest.QuestManager;
|
import emu.grasscutter.game.quest.QuestManager;
|
||||||
import emu.grasscutter.game.quest.enums.QuestContent;
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.game.quest.enums.QuestTrigger;
|
|
||||||
import emu.grasscutter.game.shop.ShopLimit;
|
import emu.grasscutter.game.shop.ShopLimit;
|
||||||
import emu.grasscutter.game.tower.TowerData;
|
import emu.grasscutter.game.tower.TowerData;
|
||||||
import emu.grasscutter.game.tower.TowerManager;
|
import emu.grasscutter.game.tower.TowerManager;
|
||||||
@ -117,12 +116,13 @@ public class Player {
|
|||||||
@Getter @Setter private int sceneId;
|
@Getter @Setter private int sceneId;
|
||||||
@Getter @Setter private int regionId;
|
@Getter @Setter private int regionId;
|
||||||
@Getter private int mainCharacterId;
|
@Getter private int mainCharacterId;
|
||||||
@Setter private boolean godmode; // Getter is inGodmode
|
@Getter @Setter private boolean inGodMode;
|
||||||
private boolean stamina; // Getter is getUnlimitedStamina, Setter is setUnlimitedStamina
|
@Getter @Setter private boolean unlimitedStamina;
|
||||||
|
|
||||||
@Getter private Set<Integer> nameCardList;
|
@Getter private Set<Integer> nameCardList;
|
||||||
@Getter private Set<Integer> flyCloakList;
|
@Getter private Set<Integer> flyCloakList;
|
||||||
@Getter private Set<Integer> costumeList;
|
@Getter private Set<Integer> costumeList;
|
||||||
|
@Getter private Set<Integer> personalLineList;
|
||||||
@Getter @Setter private Set<Integer> rewardedLevels;
|
@Getter @Setter private Set<Integer> rewardedLevels;
|
||||||
@Getter @Setter private Set<Integer> homeRewardedLevels;
|
@Getter @Setter private Set<Integer> homeRewardedLevels;
|
||||||
@Getter @Setter private Set<Integer> realmList;
|
@Getter @Setter private Set<Integer> realmList;
|
||||||
@ -793,18 +793,6 @@ public class Player {
|
|||||||
this.save();
|
this.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getUnlimitedStamina() {
|
|
||||||
return stamina;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUnlimitedStamina(boolean stamina) {
|
|
||||||
this.stamina = stamina;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean inGodmode() {
|
|
||||||
return godmode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasSentLoginPackets() {
|
public boolean hasSentLoginPackets() {
|
||||||
return hasSentLoginPackets;
|
return hasSentLoginPackets;
|
||||||
}
|
}
|
||||||
|
@ -5,14 +5,18 @@ import emu.grasscutter.data.binout.ScenePointEntry;
|
|||||||
import emu.grasscutter.data.excels.OpenStateData;
|
import emu.grasscutter.data.excels.OpenStateData;
|
||||||
import emu.grasscutter.data.excels.OpenStateData.OpenStateCondType;
|
import emu.grasscutter.data.excels.OpenStateData.OpenStateCondType;
|
||||||
import emu.grasscutter.game.props.ActionReason;
|
import emu.grasscutter.game.props.ActionReason;
|
||||||
|
import emu.grasscutter.game.quest.enums.QuestCond;
|
||||||
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.game.quest.enums.QuestState;
|
import emu.grasscutter.game.quest.enums.QuestState;
|
||||||
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
||||||
import emu.grasscutter.server.packet.send.*;
|
import emu.grasscutter.server.packet.send.*;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
// @Entity
|
// @Entity
|
||||||
public class PlayerProgressManager extends BasePlayerDataManager {
|
public final class PlayerProgressManager extends BasePlayerDataManager {
|
||||||
/******************************************************************************************************************
|
/******************************************************************************************************************
|
||||||
******************************************************************************************************************
|
******************************************************************************************************************
|
||||||
* OPEN STATES
|
* OPEN STATES
|
||||||
@ -145,6 +149,13 @@ public class PlayerProgressManager extends BasePlayerDataManager {
|
|||||||
this.player.sendPacket(new PacketSetOpenStateRsp(openState, value));
|
this.player.sendPacket(new PacketSetOpenStateRsp(openState, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This force sets an open state, ignoring all conditions and permissions
|
||||||
|
*/
|
||||||
|
public void forceSetOpenState(int openState, int value) {
|
||||||
|
this.setOpenState(openState, value);
|
||||||
|
}
|
||||||
|
|
||||||
/**********
|
/**********
|
||||||
* Triggered unlocking of open states (unlock states whose conditions have been met.)
|
* Triggered unlocking of open states (unlock states whose conditions have been met.)
|
||||||
**********/
|
**********/
|
||||||
@ -221,7 +232,7 @@ public class PlayerProgressManager extends BasePlayerDataManager {
|
|||||||
// Fire quest trigger for trans point unlock.
|
// Fire quest trigger for trans point unlock.
|
||||||
this.player
|
this.player
|
||||||
.getQuestManager()
|
.getQuestManager()
|
||||||
.triggerEvent(QuestContent.QUEST_CONTENT_UNLOCK_TRANS_POINT, sceneId, pointId);
|
.queueEvent(QuestContent.QUEST_CONTENT_UNLOCK_TRANS_POINT, sceneId, pointId);
|
||||||
|
|
||||||
// Send packet.
|
// Send packet.
|
||||||
this.player.sendPacket(new PacketScenePointUnlockNotify(sceneId, pointId));
|
this.player.sendPacket(new PacketScenePointUnlockNotify(sceneId, pointId));
|
||||||
@ -235,4 +246,35 @@ public class PlayerProgressManager extends BasePlayerDataManager {
|
|||||||
// Send packet.
|
// Send packet.
|
||||||
this.player.sendPacket(new PacketSceneAreaUnlockNotify(sceneId, areaId));
|
this.player.sendPacket(new PacketSceneAreaUnlockNotify(sceneId, areaId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Give replace costume to player (Amber, Jean, Mona, Rosaria)
|
||||||
|
*/
|
||||||
|
public void addReplaceCostumes(){
|
||||||
|
var currentPlayerCostumes = player.getCostumeList();
|
||||||
|
GameData.getAvatarReplaceCostumeDataMap().keySet().forEach(costumeId -> {
|
||||||
|
if (GameData.getAvatarCostumeDataMap().get(costumeId) == null || currentPlayerCostumes.contains(costumeId)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.player.addCostume(costumeId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quest progress
|
||||||
|
*/
|
||||||
|
public void addQuestProgress(int id, int count){
|
||||||
|
var newCount = player.getPlayerProgress().addToCurrentProgress(id, count);
|
||||||
|
player.save();
|
||||||
|
player.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_ADD_QUEST_PROGRESS, id, newCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item history
|
||||||
|
*/
|
||||||
|
public void addItemObtainedHistory(int id, int count){
|
||||||
|
var newCount = player.getPlayerProgress().addToItemHistory(id, count);
|
||||||
|
player.save();
|
||||||
|
player.getQuestManager().queueEvent(QuestCond.QUEST_COND_HISTORY_GOT_ANY_ITEM, id, newCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ import lombok.Setter;
|
|||||||
import lombok.val;
|
import lombok.val;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public class TeamManager extends BasePlayerDataManager {
|
public final class TeamManager extends BasePlayerDataManager {
|
||||||
@Transient private final List<EntityAvatar> avatars;
|
@Transient private final List<EntityAvatar> avatars;
|
||||||
@Transient @Getter private final Set<EntityBaseGadget> gadgets;
|
@Transient @Getter private final Set<EntityBaseGadget> gadgets;
|
||||||
@Transient @Getter private final IntSet teamResonances;
|
@Transient @Getter private final IntSet teamResonances;
|
||||||
@ -658,6 +658,17 @@ public class TeamManager extends BasePlayerDataManager {
|
|||||||
this.getPlayer().sendPacket(new PacketChangeAvatarRsp(guid));
|
this.getPlayer().sendPacket(new PacketChangeAvatarRsp(guid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies 10% of the avatar's max HP as damage.
|
||||||
|
* This occurs when the avatar is killed by the void.
|
||||||
|
*/
|
||||||
|
public void applyVoidDamage() {
|
||||||
|
this.getActiveTeam().forEach(entity -> {
|
||||||
|
entity.damage(entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .1f);
|
||||||
|
player.sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void onAvatarDie(long dieGuid) {
|
public void onAvatarDie(long dieGuid) {
|
||||||
EntityAvatar deadAvatar = this.getCurrentAvatarEntity();
|
EntityAvatar deadAvatar = this.getCurrentAvatarEntity();
|
||||||
|
|
||||||
|
@ -1,82 +1,36 @@
|
|||||||
package emu.grasscutter.game.props;
|
package emu.grasscutter.game.props;
|
||||||
|
|
||||||
import emu.grasscutter.utils.Utils;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import emu.grasscutter.scripts.constants.IntValueEnum;
|
||||||
|
import emu.grasscutter.utils.Utils;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
public enum ElementType {
|
public enum ElementType implements IntValueEnum {
|
||||||
None(0, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
None (0, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
||||||
Fire(
|
Fire (1, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10101, "TeamResonance_Fire_Lv2", 1),
|
||||||
1,
|
Water (2, FightProperty.FIGHT_PROP_CUR_WATER_ENERGY, FightProperty.FIGHT_PROP_MAX_WATER_ENERGY, 10201, "TeamResonance_Water_Lv2", 2),
|
||||||
FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY,
|
Grass (3, FightProperty.FIGHT_PROP_CUR_GRASS_ENERGY, FightProperty.FIGHT_PROP_MAX_GRASS_ENERGY, 10501, "TeamResonance_Grass_Lv2", 7),
|
||||||
FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY,
|
Electric (4, FightProperty.FIGHT_PROP_CUR_ELEC_ENERGY, FightProperty.FIGHT_PROP_MAX_ELEC_ENERGY, 10401, "TeamResonance_Electric_Lv2", 6),
|
||||||
10101,
|
Ice (5, FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY, 10601, "TeamResonance_Ice_Lv2", 4),
|
||||||
"TeamResonance_Fire_Lv2",
|
Frozen (6, FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY),
|
||||||
2),
|
Wind (7, FightProperty.FIGHT_PROP_CUR_WIND_ENERGY, FightProperty.FIGHT_PROP_MAX_WIND_ENERGY, 10301, "TeamResonance_Wind_Lv2", 3),
|
||||||
Water(
|
Rock (8, FightProperty.FIGHT_PROP_CUR_ROCK_ENERGY, FightProperty.FIGHT_PROP_MAX_ROCK_ENERGY, 10701, "TeamResonance_Rock_Lv2", 5),
|
||||||
2,
|
AntiFire (9, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
||||||
FightProperty.FIGHT_PROP_CUR_WATER_ENERGY,
|
Default (255, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY, 10801, "TeamResonance_AllDifferent");
|
||||||
FightProperty.FIGHT_PROP_MAX_WATER_ENERGY,
|
|
||||||
10201,
|
|
||||||
"TeamResonance_Water_Lv2",
|
|
||||||
3),
|
|
||||||
Grass(
|
|
||||||
3,
|
|
||||||
FightProperty.FIGHT_PROP_CUR_GRASS_ENERGY,
|
|
||||||
FightProperty.FIGHT_PROP_MAX_GRASS_ENERGY,
|
|
||||||
10501,
|
|
||||||
"TeamResonance_Grass_Lv2",
|
|
||||||
8),
|
|
||||||
Electric(
|
|
||||||
4,
|
|
||||||
FightProperty.FIGHT_PROP_CUR_ELEC_ENERGY,
|
|
||||||
FightProperty.FIGHT_PROP_MAX_ELEC_ENERGY,
|
|
||||||
10401,
|
|
||||||
"TeamResonance_Electric_Lv2",
|
|
||||||
7),
|
|
||||||
Ice(
|
|
||||||
5,
|
|
||||||
FightProperty.FIGHT_PROP_CUR_ICE_ENERGY,
|
|
||||||
FightProperty.FIGHT_PROP_MAX_ICE_ENERGY,
|
|
||||||
10601,
|
|
||||||
"TeamResonance_Ice_Lv2",
|
|
||||||
5),
|
|
||||||
Frozen(6, FightProperty.FIGHT_PROP_CUR_ICE_ENERGY, FightProperty.FIGHT_PROP_MAX_ICE_ENERGY),
|
|
||||||
Wind(
|
|
||||||
7,
|
|
||||||
FightProperty.FIGHT_PROP_CUR_WIND_ENERGY,
|
|
||||||
FightProperty.FIGHT_PROP_MAX_WIND_ENERGY,
|
|
||||||
10301,
|
|
||||||
"TeamResonance_Wind_Lv2",
|
|
||||||
4),
|
|
||||||
Rock(
|
|
||||||
8,
|
|
||||||
FightProperty.FIGHT_PROP_CUR_ROCK_ENERGY,
|
|
||||||
FightProperty.FIGHT_PROP_MAX_ROCK_ENERGY,
|
|
||||||
10701,
|
|
||||||
"TeamResonance_Rock_Lv2",
|
|
||||||
6),
|
|
||||||
AntiFire(9, FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY, FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY),
|
|
||||||
Default(
|
|
||||||
255,
|
|
||||||
FightProperty.FIGHT_PROP_CUR_FIRE_ENERGY,
|
|
||||||
FightProperty.FIGHT_PROP_MAX_FIRE_ENERGY,
|
|
||||||
10801,
|
|
||||||
"TeamResonance_AllDifferent");
|
|
||||||
|
|
||||||
private static final Int2ObjectMap<ElementType> map = new Int2ObjectOpenHashMap<>();
|
private static final Int2ObjectMap<ElementType> map = new Int2ObjectOpenHashMap<>();
|
||||||
private static final Map<String, ElementType> stringMap = new HashMap<>();
|
private static final Map<String, ElementType> stringMap = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
Stream.of(values())
|
// Create bindings for each value.
|
||||||
.forEach(
|
Stream.of(ElementType.values()).forEach(entry -> {
|
||||||
e -> {
|
map.put(entry.getValue(), entry);
|
||||||
map.put(e.getValue(), e);
|
stringMap.put(entry.name(), entry);
|
||||||
stringMap.put(e.name(), e);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,34 +38,23 @@ public enum ElementType {
|
|||||||
@Getter private final int teamResonanceId;
|
@Getter private final int teamResonanceId;
|
||||||
@Getter private final FightProperty curEnergyProp;
|
@Getter private final FightProperty curEnergyProp;
|
||||||
@Getter private final FightProperty maxEnergyProp;
|
@Getter private final FightProperty maxEnergyProp;
|
||||||
@Getter private final int depotValue;
|
@Getter private final int depotIndex;
|
||||||
@Getter private final int configHash;
|
@Getter private final int configHash;
|
||||||
|
|
||||||
ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp) {
|
ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp) {
|
||||||
this(value, curEnergyProp, maxEnergyProp, 0, null, 1);
|
this(value, curEnergyProp, maxEnergyProp, 0, null, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementType(
|
ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp, int teamResonanceId, String configName) {
|
||||||
int value,
|
|
||||||
FightProperty curEnergyProp,
|
|
||||||
FightProperty maxEnergyProp,
|
|
||||||
int teamResonanceId,
|
|
||||||
String configName) {
|
|
||||||
this(value, curEnergyProp, maxEnergyProp, teamResonanceId, configName, 1);
|
this(value, curEnergyProp, maxEnergyProp, teamResonanceId, configName, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementType(
|
ElementType(int value, FightProperty curEnergyProp, FightProperty maxEnergyProp, int teamResonanceId, String configName, int depotIndex) {
|
||||||
int value,
|
|
||||||
FightProperty curEnergyProp,
|
|
||||||
FightProperty maxEnergyProp,
|
|
||||||
int teamResonanceId,
|
|
||||||
String configName,
|
|
||||||
int depotValue) {
|
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.curEnergyProp = curEnergyProp;
|
this.curEnergyProp = curEnergyProp;
|
||||||
this.maxEnergyProp = maxEnergyProp;
|
this.maxEnergyProp = maxEnergyProp;
|
||||||
this.teamResonanceId = teamResonanceId;
|
this.teamResonanceId = teamResonanceId;
|
||||||
this.depotValue = depotValue;
|
this.depotIndex = depotIndex;
|
||||||
if (configName != null) {
|
if (configName != null) {
|
||||||
this.configHash = Utils.abilityHash(configName);
|
this.configHash = Utils.abilityHash(configName);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
package emu.grasscutter.game.quest;
|
|
||||||
|
|
||||||
import emu.grasscutter.game.quest.enums.QuestTrigger;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface QuestValue {
|
|
||||||
QuestTrigger value();
|
|
||||||
}
|
|
@ -15,8 +15,9 @@ public class ConditionPersonalLineUnlock extends BaseCondition {
|
|||||||
QuestData questData,
|
QuestData questData,
|
||||||
QuestData.QuestAcceptCondition condition,
|
QuestData.QuestAcceptCondition condition,
|
||||||
String paramStr,
|
String paramStr,
|
||||||
int... params) {
|
int... params
|
||||||
val personalLineId = condition.getParam()[0];
|
) {
|
||||||
|
var personalLineId = condition.getParam()[0];
|
||||||
return owner.getPersonalLineList().contains(personalLineId);
|
return owner.getPersonalLineList().contains(personalLineId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,6 @@ public class ExecAddCurAvatarEnergy extends QuestExecHandler {
|
|||||||
@Override
|
@Override
|
||||||
public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) {
|
public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) {
|
||||||
Grasscutter.getLogger().info("Energy refilled");
|
Grasscutter.getLogger().info("Energy refilled");
|
||||||
return quest.getOwner().getEnergyManager().refillEntityAvatarEnergy();
|
return quest.getOwner().getEnergyManager().refillActiveEnergy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import emu.grasscutter.game.quest.handlers.QuestExecHandler;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@QuestValueExec(QuestExec.QUEST_EXEC_ADD_QUEST_PROGRESS)
|
@QuestValueExec(QuestExec.QUEST_EXEC_ADD_QUEST_PROGRESS)
|
||||||
public class ExecAddQuestProgress extends QuestExecHandler {
|
public final class ExecAddQuestProgress extends QuestExecHandler {
|
||||||
@Override
|
@Override
|
||||||
public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) {
|
public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) {
|
||||||
var param =
|
var param =
|
||||||
|
@ -6,13 +6,12 @@ import emu.grasscutter.game.quest.QuestValueExec;
|
|||||||
import emu.grasscutter.game.quest.enums.QuestExec;
|
import emu.grasscutter.game.quest.enums.QuestExec;
|
||||||
import emu.grasscutter.game.quest.handlers.QuestExecHandler;
|
import emu.grasscutter.game.quest.handlers.QuestExecHandler;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import lombok.val;
|
|
||||||
|
|
||||||
@QuestValueExec(QuestExec.QUEST_EXEC_SET_OPEN_STATE)
|
@QuestValueExec(QuestExec.QUEST_EXEC_SET_OPEN_STATE)
|
||||||
public class ExecSetOpenState extends QuestExecHandler {
|
public class ExecSetOpenState extends QuestExecHandler {
|
||||||
@Override
|
@Override
|
||||||
public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) {
|
public boolean execute(GameQuest quest, QuestData.QuestExecParam condition, String... paramStr) {
|
||||||
val param =
|
var param =
|
||||||
Arrays.stream(paramStr).filter(i -> !i.isBlank()).mapToInt(Integer::parseInt).toArray();
|
Arrays.stream(paramStr).filter(i -> !i.isBlank()).mapToInt(Integer::parseInt).toArray();
|
||||||
|
|
||||||
quest.getOwner().getProgressManager().forceSetOpenState(param[0], param[1]);
|
quest.getOwner().getProgressManager().forceSetOpenState(param[0], param[1]);
|
||||||
|
@ -19,20 +19,23 @@ import emu.grasscutter.game.entity.gadget.GadgetWorktop;
|
|||||||
import emu.grasscutter.game.managers.blossom.BlossomManager;
|
import emu.grasscutter.game.managers.blossom.BlossomManager;
|
||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.game.player.TeamInfo;
|
import emu.grasscutter.game.player.TeamInfo;
|
||||||
import emu.grasscutter.game.props.FightProperty;
|
import emu.grasscutter.game.props.*;
|
||||||
import emu.grasscutter.game.props.LifeState;
|
|
||||||
import emu.grasscutter.game.props.SceneType;
|
|
||||||
import emu.grasscutter.game.quest.QuestGroupSuite;
|
import emu.grasscutter.game.quest.QuestGroupSuite;
|
||||||
|
import emu.grasscutter.game.world.data.TeleportProperties;
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||||
|
import emu.grasscutter.net.proto.EnterTypeOuterClass;
|
||||||
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass;
|
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass;
|
||||||
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType;
|
||||||
import emu.grasscutter.scripts.SceneIndexManager;
|
import emu.grasscutter.scripts.SceneIndexManager;
|
||||||
import emu.grasscutter.scripts.SceneScriptManager;
|
import emu.grasscutter.scripts.SceneScriptManager;
|
||||||
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.scripts.data.SceneBlock;
|
import emu.grasscutter.scripts.data.SceneBlock;
|
||||||
import emu.grasscutter.scripts.data.SceneGadget;
|
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
|
import emu.grasscutter.server.event.player.PlayerTeleportEvent;
|
||||||
import emu.grasscutter.server.packet.send.*;
|
import emu.grasscutter.server.packet.send.*;
|
||||||
|
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 java.util.*;
|
import java.util.*;
|
||||||
@ -41,8 +44,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
public class Scene {
|
public final class Scene {
|
||||||
@Getter private final World world;
|
@Getter private final World world;
|
||||||
@Getter private final SceneData sceneData;
|
@Getter private final SceneData sceneData;
|
||||||
@Getter private final List<Player> players;
|
@Getter private final List<Player> players;
|
||||||
@ -115,6 +119,13 @@ public class Scene {
|
|||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GameEntity getEntityByConfigId(int configId, int groupId) {
|
||||||
|
return this.entities.values().stream()
|
||||||
|
.filter(x -> x.getConfigId() == configId && x.getGroupId() == groupId)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the scene's pause state. Sends the current scene's time to all players.
|
* Sets the scene's pause state. Sends the current scene's time to all players.
|
||||||
*
|
*
|
||||||
@ -338,6 +349,7 @@ public class Scene {
|
|||||||
public void handleAttack(AttackResult result) {
|
public void handleAttack(AttackResult result) {
|
||||||
// GameEntity attacker = getEntityById(result.getAttackerId());
|
// GameEntity attacker = getEntityById(result.getAttackerId());
|
||||||
GameEntity target = getEntityById(result.getDefenseId());
|
GameEntity target = getEntityById(result.getDefenseId());
|
||||||
|
ElementType attackType = ElementType.getTypeByValue(result.getElementType());
|
||||||
|
|
||||||
if (target == null) {
|
if (target == null) {
|
||||||
return;
|
return;
|
||||||
@ -345,13 +357,13 @@ public class Scene {
|
|||||||
|
|
||||||
// Godmode check
|
// Godmode check
|
||||||
if (target instanceof EntityAvatar) {
|
if (target instanceof EntityAvatar) {
|
||||||
if (((EntityAvatar) target).getPlayer().inGodmode()) {
|
if (((EntityAvatar) target).getPlayer().isInGodMode()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
target.damage(result.getDamage(), result.getAttackerId());
|
target.damage(result.getDamage(), result.getAttackerId(), attackType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void killEntity(GameEntity target) {
|
public void killEntity(GameEntity target) {
|
||||||
@ -399,17 +411,19 @@ public class Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onTick() {
|
public void onTick() {
|
||||||
// disable script for home
|
// Disable ticking for the player's home world.
|
||||||
if (this.getSceneType() == SceneType.SCENE_HOME_WORLD
|
if (this.getSceneType() == SceneType.SCENE_HOME_WORLD
|
||||||
|| this.getSceneType() == SceneType.SCENE_HOME_ROOM) {
|
|| this.getSceneType() == SceneType.SCENE_HOME_ROOM) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.getScriptManager().isInit()) {
|
if (this.getScriptManager().isInit()) {
|
||||||
this.checkBlocks();
|
this.checkBlocks();
|
||||||
} else {
|
} else {
|
||||||
// TEMPORARY
|
// TEMPORARY
|
||||||
this.checkSpawns();
|
this.checkSpawns();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Triggers
|
// Triggers
|
||||||
this.scriptManager.checkRegions();
|
this.scriptManager.checkRegions();
|
||||||
|
|
||||||
@ -417,14 +431,134 @@ public class Scene {
|
|||||||
challenge.onCheckTimeOut();
|
challenge.onCheckTimeOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
blossomManager.onTick();
|
this.blossomManager.onTick();
|
||||||
|
|
||||||
checkNpcGroup();
|
checkNpcGroup();
|
||||||
|
|
||||||
|
this.finishLoading();
|
||||||
|
this.checkPlayerRespawn();
|
||||||
|
if (this.tickCount++ % 10 == 0)
|
||||||
|
broadcastPacket(new PacketSceneTimeNotify(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a player's current position.
|
||||||
|
* Teleports the player if the player is out of bounds.
|
||||||
|
*/
|
||||||
|
private void checkPlayerRespawn() {
|
||||||
|
var diePos = this.getScriptManager().getConfig().die_y;
|
||||||
|
|
||||||
|
// Check players in the scene.
|
||||||
|
this.players.forEach(player -> {
|
||||||
|
if (this.getScriptManager().getConfig() == null) return;
|
||||||
|
|
||||||
|
// Check if we need a respawn
|
||||||
|
if (diePos >= player.getPosition().getY()) {
|
||||||
|
//Respawn the player.
|
||||||
|
this.respawnPlayer(player);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check entities in the scene.
|
||||||
|
this.getEntities().forEach((id, entity) -> {
|
||||||
|
if (diePos >= entity.getPosition().getY()){
|
||||||
|
this.killEntity(entity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The script's default location, or the player's location.
|
||||||
|
*/
|
||||||
|
public Position getDefaultLocation(Player player) {
|
||||||
|
val defaultPosition = getScriptManager().getConfig().born_pos;
|
||||||
|
return defaultPosition != null ? defaultPosition : player.getPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The script's default rotation, or the player's rotation.
|
||||||
|
*/
|
||||||
|
private Position getDefaultRot(Player player) {
|
||||||
|
var defaultRotation = this.getScriptManager().getConfig().born_rot;
|
||||||
|
return defaultRotation != null ? defaultRotation : player.getRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the respawn position for the player.
|
||||||
|
*
|
||||||
|
* @param player The player to get the respawn position for.
|
||||||
|
* @return The respawn position for the player.
|
||||||
|
*/
|
||||||
|
private Position getRespawnLocation(Player player) {
|
||||||
|
// TODO: Get the last valid location the player stood on.
|
||||||
|
var lastCheckpointPos = dungeonManager != null ? dungeonManager.getRespawnLocation() : null;
|
||||||
|
return lastCheckpointPos != null ? lastCheckpointPos : getDefaultLocation(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the respawn rotation for the player.
|
||||||
|
*
|
||||||
|
* @param player The player to get the respawn rotation for.
|
||||||
|
* @return The respawn rotation for the player.
|
||||||
|
*/
|
||||||
|
private Position getRespawnRotation(Player player) {
|
||||||
|
var lastCheckpointRot = this.dungeonManager != null ? this.dungeonManager.getRespawnRotation() : null;
|
||||||
|
return lastCheckpointRot != null ? lastCheckpointRot : this.getDefaultRot(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Teleports the player to the respawn location.
|
||||||
|
*
|
||||||
|
* @param player The player to respawn.
|
||||||
|
* @return true if the player was successfully respawned, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean respawnPlayer(Player player) {
|
||||||
|
// Apply void damage as a penalty.
|
||||||
|
player.getTeamManager().applyVoidDamage();
|
||||||
|
|
||||||
|
// TODO: Respawn the player at the last valid location.
|
||||||
|
var targetPos = getRespawnLocation(player);
|
||||||
|
var targetRot = getRespawnRotation(player);
|
||||||
|
var teleportProps = TeleportProperties.builder()
|
||||||
|
.sceneId(getId())
|
||||||
|
.teleportTo(targetPos)
|
||||||
|
.teleportRot(targetRot)
|
||||||
|
.teleportType(PlayerTeleportEvent.TeleportType.INTERNAL)
|
||||||
|
.enterType(EnterTypeOuterClass.EnterType.ENTER_TYPE_GOTO)
|
||||||
|
.enterReason(dungeonManager != null ? EnterReason.DungeonReviveOnWaypoint : EnterReason.Revival);
|
||||||
|
|
||||||
|
return this.getWorld().transferPlayerToScene(player, teleportProps.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when the scene finishes loading.
|
||||||
|
* Runs all callbacks that were added with {@link #runWhenFinished(Runnable)}.
|
||||||
|
*/
|
||||||
|
public void finishLoading() {
|
||||||
|
if (this.finishedLoading) return;
|
||||||
|
|
||||||
|
this.finishedLoading = true;
|
||||||
|
this.afterLoadedCallbacks.forEach(Runnable::run);
|
||||||
|
this.afterLoadedCallbacks.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a callback to be executed when the scene is finished loading.
|
||||||
|
* If the scene is already finished loading, the callback will be executed immediately.
|
||||||
|
*
|
||||||
|
* @param runnable The callback to be executed.
|
||||||
|
*/
|
||||||
|
public void runWhenFinished(Runnable runnable) {
|
||||||
|
if (this.isFinishedLoading()) {
|
||||||
|
runnable.run();return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.afterLoadedCallbacks.add(runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getEntityLevel(int baseLevel, int worldLevelOverride) {
|
public int getEntityLevel(int baseLevel, int worldLevelOverride) {
|
||||||
int level = worldLevelOverride > 0 ? worldLevelOverride + baseLevel - 22 : baseLevel;
|
int level = worldLevelOverride > 0 ? worldLevelOverride + baseLevel - 22 : baseLevel;
|
||||||
level = level >= 100 ? 100 : level;
|
level = Math.min(level, 100);
|
||||||
level = level <= 0 ? 1 : level;
|
level = level <= 0 ? 1 : level;
|
||||||
|
|
||||||
return level;
|
return level;
|
||||||
@ -543,11 +677,12 @@ public class Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (toAdd.size() > 0) {
|
if (toAdd.size() > 0) {
|
||||||
toAdd.stream().forEach(this::addEntityDirectly);
|
toAdd.forEach(this::addEntityDirectly);
|
||||||
this.broadcastPacket(new PacketSceneEntityAppearNotify(toAdd, VisionType.VISION_TYPE_BORN));
|
this.broadcastPacket(new PacketSceneEntityAppearNotify(toAdd, VisionType.VISION_TYPE_BORN));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toRemove.size() > 0) {
|
if (toRemove.size() > 0) {
|
||||||
toRemove.stream().forEach(this::removeEntityDirectly);
|
toRemove.forEach(this::removeEntityDirectly);
|
||||||
this.broadcastPacket(
|
this.broadcastPacket(
|
||||||
new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_TYPE_REMOVE));
|
new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_TYPE_REMOVE));
|
||||||
blossomManager.recycleGadgetEntity(toRemove);
|
blossomManager.recycleGadgetEntity(toRemove);
|
||||||
@ -568,8 +703,9 @@ public class Scene {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized boolean loadBlock(SceneBlock block) {
|
public synchronized boolean loadBlock(SceneBlock block) {
|
||||||
if (this.loadedBlocks.contains(block)) return false;
|
if (this.loadedBlocks.contains(block)) return false;
|
||||||
|
|
||||||
this.onLoadBlock(block, this.players);
|
this.onLoadBlock(block, this.players);
|
||||||
this.loadedBlocks.add(block);
|
this.loadedBlocks.add(block);
|
||||||
return true;
|
return true;
|
||||||
@ -578,7 +714,7 @@ public class Scene {
|
|||||||
public synchronized void checkBlocks() {
|
public synchronized void checkBlocks() {
|
||||||
Set<SceneBlock> visible =
|
Set<SceneBlock> visible =
|
||||||
this.players.stream()
|
this.players.stream()
|
||||||
.map(player -> this.getPlayerActiveBlocks(player))
|
.map(this::getPlayerActiveBlocks)
|
||||||
.flatMap(Collection::stream)
|
.flatMap(Collection::stream)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
|
|
||||||
@ -635,11 +771,89 @@ public class Scene {
|
|||||||
Grasscutter.getLogger().info("Scene {} Block {} loaded.", this.getId(), block.id);
|
Grasscutter.getLogger().info("Scene {} Block {} loaded.", this.getId(), block.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int loadDynamicGroup(int group_id) {
|
||||||
|
SceneGroup group = getScriptManager().getGroupById(group_id);
|
||||||
|
if(group == null || getScriptManager().getGroupInstanceById(group_id) != null) return -1; //Group not found or already instanced
|
||||||
|
|
||||||
|
onLoadGroup(new ArrayList<>(List.of(group)));
|
||||||
|
|
||||||
|
if(GameData.getGroupReplacements().containsKey(group_id)) onRegisterGroups();
|
||||||
|
|
||||||
|
if (group.init_config == null) return -1;
|
||||||
|
return group.init_config.suite;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean unregisterDynamicGroup(int groupId){
|
||||||
|
var group = getScriptManager().getGroupById(groupId);
|
||||||
|
if (group == null) return false;
|
||||||
|
|
||||||
|
var block = getScriptManager().getBlocks().get(group.block_id);
|
||||||
|
this.unloadGroup(block, groupId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onRegisterGroups() {
|
||||||
|
var sceneGroups = this.loadedGroups;
|
||||||
|
var sceneGroupMap = sceneGroups.stream()
|
||||||
|
.collect(Collectors.toMap(item -> item.id, item -> item));
|
||||||
|
var sceneGroupsIds = sceneGroups.stream()
|
||||||
|
.map(group -> group.id)
|
||||||
|
.toList();
|
||||||
|
var dynamicGroups = sceneGroups.stream()
|
||||||
|
.filter(group -> group.dynamic_load)
|
||||||
|
.map(group -> group.id)
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
//Create the graph
|
||||||
|
var nodes = new ArrayList<KahnsSort.Node>();
|
||||||
|
var groupList = new ArrayList<Integer>();
|
||||||
|
GameData.getGroupReplacements().values().stream().filter(replacement -> dynamicGroups.contains(replacement.id)).forEach(replacement -> {
|
||||||
|
Grasscutter.getLogger().info("Graph ordering replacement {}", replacement);
|
||||||
|
replacement.replace_groups.forEach(group -> {
|
||||||
|
nodes.add(new KahnsSort.Node(replacement.id, group));
|
||||||
|
if (!groupList.contains(group))
|
||||||
|
groupList.add(group);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!groupList.contains(replacement.id))
|
||||||
|
groupList.add(replacement.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
KahnsSort.Graph graph = new KahnsSort.Graph(nodes, groupList);
|
||||||
|
List<Integer> dynamicGroupsOrdered = KahnsSort.doSort(graph);
|
||||||
|
if (dynamicGroupsOrdered == null) throw new RuntimeException("Invalid group replacement graph");
|
||||||
|
|
||||||
|
// Now we can start unloading and loading groups :D
|
||||||
|
dynamicGroupsOrdered.forEach(group -> {
|
||||||
|
if (GameData.getGroupReplacements().containsKey((int)group)) { //isGroupJoinReplacement
|
||||||
|
var data = GameData.getGroupReplacements().get((int)group);
|
||||||
|
var sceneGroupReplacement = this.loadedGroups.stream().filter(g -> g.id == group).findFirst().orElseThrow();
|
||||||
|
if (sceneGroupReplacement.is_replaceable != null) {
|
||||||
|
var it = data.replace_groups.iterator();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
var replace_group = it.next();
|
||||||
|
if (!sceneGroupsIds.contains(replace_group)) continue;
|
||||||
|
|
||||||
|
// Check if we can replace this group
|
||||||
|
SceneGroup sceneGroup = sceneGroupMap.get(replace_group);
|
||||||
|
if (sceneGroup != null && sceneGroup.is_replaceable != null &&
|
||||||
|
((sceneGroup.is_replaceable.value &&
|
||||||
|
sceneGroup.is_replaceable.version <= sceneGroupReplacement.is_replaceable.version) ||
|
||||||
|
sceneGroup.is_replaceable.new_bin_only)) {
|
||||||
|
this.unloadGroup(scriptManager.getBlocks().get(sceneGroup.block_id), replace_group);
|
||||||
|
it.remove();
|
||||||
|
Grasscutter.getLogger().info("Graph ordering: unloaded {}", replace_group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void loadTriggerFromGroup(SceneGroup group, String triggerName) {
|
public void loadTriggerFromGroup(SceneGroup group, String triggerName) {
|
||||||
// Load triggers and regions
|
// Load triggers and regions
|
||||||
getScriptManager()
|
this.getScriptManager().registerTrigger(group.triggers.values().stream()
|
||||||
.registerTrigger(
|
.filter(p -> p.getName().contains(triggerName)).toList());
|
||||||
group.triggers.values().stream().filter(p -> p.name.contains(triggerName)).toList());
|
|
||||||
group.regions.values().stream()
|
group.regions.values().stream()
|
||||||
.filter(q -> q.config_id == Integer.parseInt(triggerName.substring(13)))
|
.filter(q -> q.config_id == Integer.parseInt(triggerName.substring(13)))
|
||||||
.map(region -> new EntityRegion(this, region))
|
.map(region -> new EntityRegion(this, region))
|
||||||
@ -650,50 +864,53 @@ public class Scene {
|
|||||||
if (groups == null || groups.isEmpty()) {
|
if (groups == null || groups.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (SceneGroup group : groups) {
|
|
||||||
|
for (var group : groups) {
|
||||||
|
if(this.loadedGroups.contains(group)) continue;
|
||||||
|
|
||||||
// We load the script files for the groups here
|
// We load the script files for the groups here
|
||||||
this.getScriptManager().loadGroupFromScript(group);
|
this.getScriptManager().loadGroupFromScript(group);
|
||||||
|
if (!this.scriptManager.getLoadedGroupSetPerBlock().containsKey(group.block_id))
|
||||||
|
this.onLoadBlock(scriptManager.getBlocks().get(group.block_id), players);
|
||||||
|
this.scriptManager.getLoadedGroupSetPerBlock().get(group.block_id).add(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn gadgets AFTER triggers are added
|
// Spawn gadgets AFTER triggers are added
|
||||||
// TODO
|
// TODO
|
||||||
var entities = new ArrayList<GameEntity>();
|
var entities = new ArrayList<GameEntity>();
|
||||||
for (SceneGroup group : groups) {
|
for (var group : groups) {
|
||||||
|
if(this.loadedGroups.contains(group)) continue;
|
||||||
|
|
||||||
if (group.init_config == null) {
|
if (group.init_config == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var groupInstance = this.getScriptManager().getGroupInstanceById(group.id);
|
||||||
|
var cachedInstance = this.getScriptManager().getCachedGroupInstanceById(group.id);
|
||||||
|
if (cachedInstance != null) {
|
||||||
|
cachedInstance.setLuaGroup(group);
|
||||||
|
groupInstance = cachedInstance;
|
||||||
|
}
|
||||||
|
|
||||||
// Load garbages
|
// Load garbages
|
||||||
List<SceneGadget> garbageGadgets = group.getGarbageGadgets();
|
var garbageGadgets = group.getGarbageGadgets();
|
||||||
|
|
||||||
if (garbageGadgets != null) {
|
if (garbageGadgets != null) {
|
||||||
entities.addAll(
|
entities.addAll(garbageGadgets.stream()
|
||||||
garbageGadgets.stream()
|
|
||||||
.map(g -> scriptManager.createGadget(group.id, group.block_id, g))
|
.map(g -> scriptManager.createGadget(group.id, group.block_id, g))
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull).toList());
|
||||||
.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load suites
|
// Load suites
|
||||||
int suite = group.init_config.suite;
|
//int suite = group.findInitSuiteIndex(0);
|
||||||
|
this.getScriptManager().refreshGroup(groupInstance, 0, false); //This is what the official server does
|
||||||
|
|
||||||
if (suite == 0 || group.suites == null || group.suites.size() == 0) {
|
this.loadedGroups.add(group);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// just load the 'init' suite, avoid spawn the suite added by AddExtraGroupSuite etc.
|
this.scriptManager.meetEntities(entities);
|
||||||
var suiteData = group.getSuiteByIndex(suite);
|
groups.forEach(g -> scriptManager.callEvent(new ScriptArgs(g.id, EventType.EVENT_GROUP_LOAD, g.id)));
|
||||||
suiteData.sceneTriggers.forEach(getScriptManager()::registerTrigger);
|
|
||||||
|
|
||||||
entities.addAll(scriptManager.getGadgetsInGroupSuite(group, suiteData));
|
|
||||||
entities.addAll(scriptManager.getMonstersInGroupSuite(group, suiteData));
|
|
||||||
|
|
||||||
scriptManager.registerRegionInGroupSuite(group, suiteData);
|
|
||||||
}
|
|
||||||
|
|
||||||
scriptManager.meetEntities(entities);
|
|
||||||
// scriptManager.callEvent(EventType.EVENT_GROUP_LOAD, null);
|
|
||||||
// groups.forEach(g -> scriptManager.callEvent(EventType.EVENT_GROUP_LOAD, null));
|
|
||||||
Grasscutter.getLogger().info("Scene {} loaded {} group(s)", this.getId(), groups.size());
|
Grasscutter.getLogger().info("Scene {} loaded {} group(s)", this.getId(), groups.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -718,6 +935,47 @@ public class Scene {
|
|||||||
scriptManager.getLoadedGroupSetPerBlock().remove(block.id);
|
scriptManager.getLoadedGroupSetPerBlock().remove(block.id);
|
||||||
Grasscutter.getLogger().info("Scene {} Block {} is unloaded.", this.getId(), block.id);
|
Grasscutter.getLogger().info("Scene {} Block {} is unloaded.", this.getId(), block.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unloads a Lua group.
|
||||||
|
*
|
||||||
|
* @param block The block that contains the group.
|
||||||
|
* @param groupId The group ID.
|
||||||
|
*/
|
||||||
|
public void unloadGroup(SceneBlock block, int groupId) {
|
||||||
|
var toRemove = this.getEntities().values().stream()
|
||||||
|
.filter(e -> e != null && (
|
||||||
|
e.getBlockId() == block.id &&
|
||||||
|
e.getGroupId() == groupId)
|
||||||
|
).toList();
|
||||||
|
|
||||||
|
if (toRemove.size() > 0) {
|
||||||
|
toRemove.forEach(this::removeEntityDirectly);
|
||||||
|
this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_TYPE_REMOVE));
|
||||||
|
}
|
||||||
|
|
||||||
|
var group = block.groups.get(groupId);
|
||||||
|
if (group.triggers != null) {
|
||||||
|
group.triggers.values().forEach(
|
||||||
|
this.getScriptManager()::deregisterTrigger);
|
||||||
|
}
|
||||||
|
if (group.regions != null) {
|
||||||
|
group.regions.values().forEach(
|
||||||
|
this.getScriptManager()::deregisterRegion);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scriptManager.getLoadedGroupSetPerBlock().get(block.id).remove(group);
|
||||||
|
this.loadedGroups.remove(group);
|
||||||
|
|
||||||
|
if (this.scriptManager.getLoadedGroupSetPerBlock().get(block.id).isEmpty()) {
|
||||||
|
this.scriptManager.getLoadedGroupSetPerBlock().remove(block.id);
|
||||||
|
Grasscutter.getLogger().info("Scene {} Block {} is unloaded.", this.getId(), block.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.broadcastPacket(new PacketGroupUnloadNotify(List.of(groupId)));
|
||||||
|
this.scriptManager.unregisterGroup(group);
|
||||||
|
}
|
||||||
|
|
||||||
// Gadgets
|
// Gadgets
|
||||||
|
|
||||||
public void onPlayerCreateGadget(EntityClientGadget gadget) {
|
public void onPlayerCreateGadget(EntityClientGadget gadget) {
|
||||||
@ -738,7 +996,7 @@ public class Scene {
|
|||||||
public void onPlayerDestroyGadget(int entityId) {
|
public void onPlayerDestroyGadget(int entityId) {
|
||||||
GameEntity entity = getEntities().get(entityId);
|
GameEntity entity = getEntities().get(entityId);
|
||||||
|
|
||||||
if (entity == null || !(entity instanceof EntityClientGadget gadget)) {
|
if (!(entity instanceof EntityClientGadget gadget)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -834,20 +1092,40 @@ public class Scene {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sceneGroupSuite.forEach(
|
sceneGroupSuite.forEach(i -> {
|
||||||
i -> {
|
|
||||||
var group = scriptManager.getGroupById(i.getGroup());
|
var group = scriptManager.getGroupById(i.getGroup());
|
||||||
if (group == null) {
|
if (group == null) return;
|
||||||
return;
|
|
||||||
}
|
var groupInstance = scriptManager.getGroupInstanceById(i.getGroup());
|
||||||
var suite = group.getSuiteByIndex(i.getSuite());
|
var suite = group.getSuiteByIndex(i.getSuite());
|
||||||
if (suite == null) {
|
if (suite == null || groupInstance == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scriptManager.addGroupSuite(group, suite);
|
|
||||||
|
scriptManager.refreshGroup(groupInstance, i.getSuite(), false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an unlocked force to the scene.
|
||||||
|
*
|
||||||
|
* @param force The ID of the force to unlock.
|
||||||
|
*/
|
||||||
|
public void unlockForce(int force) {
|
||||||
|
this.unlockedForces.add(force);
|
||||||
|
this.broadcastPacket(new PacketSceneForceUnlockNotify(force, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an unlocked force from the scene.
|
||||||
|
*
|
||||||
|
* @param force The ID of the force to lock.
|
||||||
|
*/
|
||||||
|
public void lockForce(int force) {
|
||||||
|
this.unlockedForces.remove(force);
|
||||||
|
this.broadcastPacket(new PacketSceneForceLockNotify(force));
|
||||||
|
}
|
||||||
|
|
||||||
public void selectWorktopOptionWith(SelectWorktopOptionReqOuterClass.SelectWorktopOptionReq req) {
|
public void selectWorktopOptionWith(SelectWorktopOptionReqOuterClass.SelectWorktopOptionReq req) {
|
||||||
GameEntity entity = getEntityById(req.getGadgetEntityId());
|
GameEntity entity = getEntityById(req.getGadgetEntityId());
|
||||||
if (entity == null) {
|
if (entity == null) {
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
package emu.grasscutter.game.world;
|
package emu.grasscutter.game.world;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.bson.types.ObjectId;
|
||||||
|
|
||||||
import dev.morphia.annotations.Entity;
|
import dev.morphia.annotations.Entity;
|
||||||
import dev.morphia.annotations.Id;
|
import dev.morphia.annotations.Id;
|
||||||
import dev.morphia.annotations.Indexed;
|
import dev.morphia.annotations.Indexed;
|
||||||
@ -7,25 +14,20 @@ import emu.grasscutter.database.DatabaseHelper;
|
|||||||
import emu.grasscutter.game.player.Player;
|
import emu.grasscutter.game.player.Player;
|
||||||
import emu.grasscutter.scripts.data.SceneGadget;
|
import emu.grasscutter.scripts.data.SceneGadget;
|
||||||
import emu.grasscutter.scripts.data.SceneGroup;
|
import emu.grasscutter.scripts.data.SceneGroup;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.bson.types.ObjectId;
|
|
||||||
|
|
||||||
@Entity(value = "group_instances", useDiscriminator = false)
|
@Entity(value = "group_instances", useDiscriminator = false)
|
||||||
public class SceneGroupInstance {
|
public final class SceneGroupInstance {
|
||||||
@Id private ObjectId id;
|
@Id private ObjectId id;
|
||||||
|
|
||||||
@Indexed private int ownerUid; // This group is owned by the host player
|
@Indexed private int ownerUid; //This group is owned by the host player
|
||||||
@Getter private int groupId;
|
@Getter private int groupId;
|
||||||
|
|
||||||
@Getter private transient SceneGroup luaGroup;
|
@Getter private transient SceneGroup luaGroup;
|
||||||
@Getter @Setter private int targetSuiteId;
|
@Getter @Setter private int targetSuiteId;
|
||||||
@Getter @Setter private int activeSuiteId;
|
@Getter @Setter private int activeSuiteId;
|
||||||
@Getter private Set<Integer> deadEntities; // Config_ids
|
@Getter private Set<Integer> deadEntities; //Config_ids
|
||||||
private boolean isCached;
|
private boolean isCached;
|
||||||
|
|
||||||
@Getter private Map<Integer, Integer> cachedGadgetStates;
|
@Getter private Map<Integer, Integer> cachedGadgetStates;
|
||||||
@ -44,12 +46,11 @@ public class SceneGroupInstance {
|
|||||||
this.cachedGadgetStates = new ConcurrentHashMap<>();
|
this.cachedGadgetStates = new ConcurrentHashMap<>();
|
||||||
this.cachedVariables = new ConcurrentHashMap<>();
|
this.cachedVariables = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
this.isCached =
|
this.isCached = false; //This is true when the group is not loaded on scene but caches suite data
|
||||||
false; // This is true when the group is not loaded on scene but caches suite data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated // Morphia only!
|
@Deprecated // Morphia only!
|
||||||
SceneGroupInstance() {
|
SceneGroupInstance(){
|
||||||
this.cachedVariables = new ConcurrentHashMap<>();
|
this.cachedVariables = new ConcurrentHashMap<>();
|
||||||
this.deadEntities = new HashSet<>();
|
this.deadEntities = new HashSet<>();
|
||||||
this.cachedGadgetStates = new ConcurrentHashMap<>();
|
this.cachedGadgetStates = new ConcurrentHashMap<>();
|
||||||
@ -66,11 +67,11 @@ public class SceneGroupInstance {
|
|||||||
|
|
||||||
public void setCached(boolean value) {
|
public void setCached(boolean value) {
|
||||||
this.isCached = value;
|
this.isCached = value;
|
||||||
save(); // Save each time a group is registered or unregistered
|
save(); //Save each time a group is registered or unregistered
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cacheGadgetState(SceneGadget g, int state) {
|
public void cacheGadgetState(SceneGadget g, int state) {
|
||||||
if (g.persistent) // Only cache when is persistent
|
if(g.persistent) //Only cache when is persistent
|
||||||
cachedGadgetStates.put(g.config_id, state);
|
cachedGadgetStates.put(g.config_id, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -2,12 +2,14 @@ package emu.grasscutter.scripts;
|
|||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import emu.grasscutter.utils.Position;
|
||||||
|
import lombok.val;
|
||||||
import org.luaj.vm2.LuaTable;
|
import org.luaj.vm2.LuaTable;
|
||||||
import org.luaj.vm2.LuaValue;
|
import org.luaj.vm2.LuaValue;
|
||||||
|
|
||||||
public class ScriptUtils {
|
public interface ScriptUtils {
|
||||||
|
static HashMap<Object, Object> toMap(LuaTable table) {
|
||||||
public static HashMap<Object, Object> toMap(LuaTable table) {
|
|
||||||
HashMap<Object, Object> map = new HashMap<>();
|
HashMap<Object, Object> map = new HashMap<>();
|
||||||
LuaValue[] rootKeys = table.keys();
|
LuaValue[] rootKeys = table.keys();
|
||||||
for (LuaValue k : rootKeys) {
|
for (LuaValue k : rootKeys) {
|
||||||
@ -20,7 +22,45 @@ public class ScriptUtils {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void print(LuaTable table) {
|
static void print(LuaTable table) {
|
||||||
Grasscutter.getLogger().info(toMap(table).toString());
|
Grasscutter.getLogger().info(toMap(table).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a position object into a Lua table.
|
||||||
|
*
|
||||||
|
* @param position The position object to convert.
|
||||||
|
* @return The Lua table.
|
||||||
|
*/
|
||||||
|
static LuaTable posToLua(Position position) {
|
||||||
|
var result = new LuaTable();
|
||||||
|
if (position != null) {
|
||||||
|
result.set("x", position.getX());
|
||||||
|
result.set("y", position.getY());
|
||||||
|
result.set("z", position.getZ());
|
||||||
|
} else {
|
||||||
|
result.set("x", 0);
|
||||||
|
result.set("y", 0);
|
||||||
|
result.set("z", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a Lua table into a position object.
|
||||||
|
*
|
||||||
|
* @param position The Lua table to convert.
|
||||||
|
* @return The position object.
|
||||||
|
*/
|
||||||
|
static Position luaToPos(LuaValue position) {
|
||||||
|
var result = new Position();
|
||||||
|
if (position != null && !position.isnil()) {
|
||||||
|
result.setX(position.get("x").optint(0));
|
||||||
|
result.setY(position.get("y").optint(0));
|
||||||
|
result.setZ(position.get("z").optint(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,4 +12,5 @@ public class SceneConfig {
|
|||||||
public Position born_rot;
|
public Position born_rot;
|
||||||
public Position begin_pos;
|
public Position begin_pos;
|
||||||
public Position size;
|
public Position size;
|
||||||
|
public float die_y;
|
||||||
}
|
}
|
||||||
|
@ -3,28 +3,33 @@ package emu.grasscutter.scripts.data;
|
|||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.scripts.ScriptLoader;
|
import emu.grasscutter.scripts.ScriptLoader;
|
||||||
import emu.grasscutter.utils.Position;
|
import emu.grasscutter.utils.Position;
|
||||||
import java.util.List;
|
import lombok.Getter;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import javax.script.Bindings;
|
|
||||||
import javax.script.CompiledScript;
|
|
||||||
import javax.script.ScriptException;
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.luaj.vm2.LuaValue;
|
import org.luaj.vm2.LuaValue;
|
||||||
|
|
||||||
|
import javax.script.Bindings;
|
||||||
|
import javax.script.CompiledScript;
|
||||||
|
import javax.script.ScriptException;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@Setter
|
@Setter
|
||||||
public class SceneGroup {
|
public final class SceneGroup {
|
||||||
public transient int
|
public transient int block_id; // Not an actual variable in the scripts but we will keep it here for reference
|
||||||
block_id; // Not an actual variable in the scripts but we will keep it here for reference
|
|
||||||
|
|
||||||
public int id;
|
public int id;
|
||||||
public int refresh_id;
|
public int refresh_id;
|
||||||
public Position pos;
|
public Position pos;
|
||||||
|
|
||||||
public Map<Integer, SceneMonster> monsters; // <ConfigId, Monster>
|
public Map<Integer, SceneMonster> monsters; // <ConfigId, Monster>
|
||||||
|
public Map<Integer, SceneNPC> npcs; // <ConfigId, Npc>
|
||||||
public Map<Integer, SceneGadget> gadgets; // <ConfigId, Gadgets>
|
public Map<Integer, SceneGadget> gadgets; // <ConfigId, Gadgets>
|
||||||
public Map<String, SceneTrigger> triggers;
|
public Map<String, SceneTrigger> triggers;
|
||||||
public Map<Integer, SceneRegion> regions;
|
public Map<Integer, SceneRegion> regions;
|
||||||
@ -34,11 +39,13 @@ public class SceneGroup {
|
|||||||
public SceneBusiness business;
|
public SceneBusiness business;
|
||||||
public SceneGarbage garbages;
|
public SceneGarbage garbages;
|
||||||
public SceneInitConfig init_config;
|
public SceneInitConfig init_config;
|
||||||
|
@Getter public boolean dynamic_load = false;
|
||||||
|
|
||||||
|
public SceneReplaceable is_replaceable;
|
||||||
|
|
||||||
private transient boolean loaded; // Not an actual variable in the scripts either
|
private transient boolean loaded; // Not an actual variable in the scripts either
|
||||||
private transient CompiledScript script;
|
private transient CompiledScript script;
|
||||||
private transient Bindings bindings;
|
private transient Bindings bindings;
|
||||||
|
|
||||||
public static SceneGroup of(int groupId) {
|
public static SceneGroup of(int groupId) {
|
||||||
var group = new SceneGroup();
|
var group = new SceneGroup();
|
||||||
group.id = groupId;
|
group.id = groupId;
|
||||||
@ -66,6 +73,9 @@ public class SceneGroup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SceneSuite getSuiteByIndex(int index) {
|
public SceneSuite getSuiteByIndex(int index) {
|
||||||
|
if(index < 1 || index > suites.size()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return this.suites.get(index - 1);
|
return this.suites.get(index - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,9 +92,7 @@ public class SceneGroup {
|
|||||||
|
|
||||||
this.bindings = ScriptLoader.getEngine().createBindings();
|
this.bindings = ScriptLoader.getEngine().createBindings();
|
||||||
|
|
||||||
CompiledScript cs =
|
CompiledScript cs = ScriptLoader.getScript("Scene/" + sceneId + "/scene" + sceneId + "_group" + this.id + ".lua");
|
||||||
ScriptLoader.getScript(
|
|
||||||
"Scene/" + sceneId + "/scene" + sceneId + "_group" + this.id + ".lua");
|
|
||||||
|
|
||||||
if (cs == null) {
|
if (cs == null) {
|
||||||
return this;
|
return this;
|
||||||
@ -97,74 +105,79 @@ public class SceneGroup {
|
|||||||
cs.eval(this.bindings);
|
cs.eval(this.bindings);
|
||||||
|
|
||||||
// Set
|
// Set
|
||||||
this.monsters =
|
this.monsters = ScriptLoader.getSerializer().toList(SceneMonster.class, this.bindings.get("monsters")).stream()
|
||||||
ScriptLoader.getSerializer()
|
|
||||||
.toList(SceneMonster.class, this.bindings.get("monsters"))
|
|
||||||
.stream()
|
|
||||||
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
||||||
this.monsters.values().forEach(m -> m.group = this);
|
this.monsters.values().forEach(m -> m.group = this);
|
||||||
|
|
||||||
this.gadgets =
|
this.npcs = ScriptLoader.getSerializer().toList(SceneNPC.class, this.bindings.get("npcs")).stream()
|
||||||
ScriptLoader.getSerializer()
|
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
||||||
.toList(SceneGadget.class, this.bindings.get("gadgets"))
|
this.npcs.values().forEach(m -> m.group = this);
|
||||||
.stream()
|
|
||||||
|
this.gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, this.bindings.get("gadgets")).stream()
|
||||||
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
||||||
this.gadgets.values().forEach(m -> m.group = this);
|
this.gadgets.values().forEach(m -> m.group = this);
|
||||||
|
|
||||||
this.triggers =
|
this.triggers = ScriptLoader.getSerializer().toList(SceneTrigger.class, this.bindings.get("triggers")).stream()
|
||||||
ScriptLoader.getSerializer()
|
.collect(Collectors.toMap(SceneTrigger::getName, y -> y, (a, b) -> a));
|
||||||
.toList(SceneTrigger.class, this.bindings.get("triggers"))
|
|
||||||
.stream()
|
|
||||||
.collect(Collectors.toMap(x -> x.name, y -> y, (a, b) -> a));
|
|
||||||
this.triggers.values().forEach(t -> t.currentGroup = this);
|
this.triggers.values().forEach(t -> t.currentGroup = this);
|
||||||
|
|
||||||
this.suites =
|
this.suites = ScriptLoader.getSerializer().toList(SceneSuite.class, this.bindings.get("suites"));
|
||||||
ScriptLoader.getSerializer().toList(SceneSuite.class, this.bindings.get("suites"));
|
this.regions = ScriptLoader.getSerializer().toList(SceneRegion.class, this.bindings.get("regions")).stream()
|
||||||
this.regions =
|
|
||||||
ScriptLoader.getSerializer()
|
|
||||||
.toList(SceneRegion.class, this.bindings.get("regions"))
|
|
||||||
.stream()
|
|
||||||
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
.collect(Collectors.toMap(x -> x.config_id, y -> y, (a, b) -> a));
|
||||||
this.regions.values().forEach(m -> m.group = this);
|
this.regions.values().forEach(m -> m.group = this);
|
||||||
|
|
||||||
this.init_config =
|
this.init_config = ScriptLoader.getSerializer().toObject(SceneInitConfig.class, this.bindings.get("init_config"));
|
||||||
ScriptLoader.getSerializer()
|
|
||||||
.toObject(SceneInitConfig.class, this.bindings.get("init_config"));
|
|
||||||
|
|
||||||
// Garbages // TODO: fix properly later
|
// Garbages // TODO: fix properly later
|
||||||
Object garbagesValue = this.bindings.get("garbages");
|
Object garbagesValue = this.bindings.get("garbages");
|
||||||
if (garbagesValue instanceof LuaValue garbagesTable) {
|
if (garbagesValue instanceof LuaValue garbagesTable) {
|
||||||
this.garbages = new SceneGarbage();
|
this.garbages = new SceneGarbage();
|
||||||
if (garbagesTable.checktable().get("gadgets") != LuaValue.NIL) {
|
if (garbagesTable.checktable().get("gadgets") != LuaValue.NIL) {
|
||||||
this.garbages.gadgets =
|
this.garbages.gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, garbagesTable.checktable().get("gadgets").checktable());
|
||||||
ScriptLoader.getSerializer()
|
|
||||||
.toList(
|
|
||||||
SceneGadget.class, garbagesTable.checktable().get("gadgets").checktable());
|
|
||||||
this.garbages.gadgets.forEach(m -> m.group = this);
|
this.garbages.gadgets.forEach(m -> m.group = this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add variables to suite
|
// Add variables to suite
|
||||||
this.variables =
|
this.variables = ScriptLoader.getSerializer().toList(SceneVar.class, this.bindings.get("variables"));
|
||||||
ScriptLoader.getSerializer().toList(SceneVar.class, this.bindings.get("variables"));
|
|
||||||
|
|
||||||
// Add monsters and gadgets to suite
|
// Add monsters and gadgets to suite
|
||||||
this.suites.forEach(i -> i.init(this));
|
this.suites.forEach(i -> i.init(this));
|
||||||
|
|
||||||
} catch (ScriptException e) {
|
} catch (ScriptException e) {
|
||||||
Grasscutter.getLogger()
|
Grasscutter.getLogger().error("An error occurred while loading group " + this.id + " in scene " + sceneId + ".", e);
|
||||||
.error(
|
|
||||||
"An error occurred while loading group " + this.id + " in scene " + sceneId + ".", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Grasscutter.getLogger().debug("Successfully loaded group {} in scene {}.", this.id, sceneId);
|
Grasscutter.getLogger().debug("Successfully loaded group {} in scene {}.", this.id, sceneId);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int findInitSuiteIndex(int exclude_index) { //TODO: Investigate end index
|
||||||
|
if (init_config == null) return 1;
|
||||||
|
if (init_config.io_type == 1) return init_config.suite; //IO TYPE FLOW
|
||||||
|
if (init_config.rand_suite) {
|
||||||
|
if (suites.size() == 1) {
|
||||||
|
return init_config.suite;
|
||||||
|
} else {
|
||||||
|
List<Integer> randSuiteList = new ArrayList<>();
|
||||||
|
for (int i = 0; i < suites.size(); i++) {
|
||||||
|
if (i == exclude_index) continue;
|
||||||
|
|
||||||
|
var suite = suites.get(i);
|
||||||
|
for(int j = 0; j < suite.rand_weight; j++) randSuiteList.add(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return randSuiteList.get(new Random().nextInt(randSuiteList.size()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return init_config.suite;
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<SceneBossChest> searchBossChestInGroup() {
|
public Optional<SceneBossChest> searchBossChestInGroup() {
|
||||||
return this.gadgets.values().stream()
|
return this.gadgets.values().stream()
|
||||||
.filter(g -> g.boss_chest != null && g.boss_chest.monster_config_id > 0)
|
.filter(g -> g.boss_chest != null && g.boss_chest.monster_config_id > 0)
|
||||||
.map(g -> g.boss_chest)
|
.map(g -> g.boss_chest)
|
||||||
.findFirst();
|
.findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,9 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@Setter
|
@Setter
|
||||||
public class SceneInitConfig {
|
public final class SceneInitConfig {
|
||||||
public int suite;
|
public int suite;
|
||||||
public int end_suite;
|
public int end_suite;
|
||||||
|
public int io_type;
|
||||||
public boolean rand_suite;
|
public boolean rand_suite;
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,11 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@Setter
|
@Setter
|
||||||
public class SceneMonster extends SceneObject {
|
public class SceneMonster extends SceneObject{
|
||||||
public int monster_id;
|
public int monster_id;
|
||||||
public int pose_id;
|
public int pose_id;
|
||||||
public int drop_id;
|
public int drop_id;
|
||||||
public int special_name_id;
|
|
||||||
public String drop_tag;
|
|
||||||
public int climate_area_id;
|
|
||||||
public boolean disableWander;
|
public boolean disableWander;
|
||||||
public int title_id;
|
public int title_id;
|
||||||
public int[] affix;
|
public int special_name_id;
|
||||||
public int mark_flag;
|
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,11 @@ import lombok.ToString;
|
|||||||
|
|
||||||
@ToString
|
@ToString
|
||||||
@Setter
|
@Setter
|
||||||
public class SceneObject {
|
public abstract class SceneObject {
|
||||||
public int level;
|
public int level;
|
||||||
public int config_id;
|
public int config_id;
|
||||||
public int area_id;
|
public int area_id;
|
||||||
|
public int vision_level = 0;
|
||||||
|
|
||||||
public Position pos;
|
public Position pos;
|
||||||
public Position rot;
|
public Position rot;
|
||||||
|
@ -2,6 +2,7 @@ package emu.grasscutter.scripts.data;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
@ -14,7 +15,8 @@ public class SceneSuite {
|
|||||||
public List<String> triggers = List.of();
|
public List<String> triggers = List.of();
|
||||||
public List<Integer> regions = List.of();
|
public List<Integer> regions = List.of();
|
||||||
public int rand_weight;
|
public int rand_weight;
|
||||||
public int[] npcs;
|
|
||||||
|
public boolean ban_refresh = false;
|
||||||
|
|
||||||
public transient List<SceneMonster> sceneMonsters = List.of();
|
public transient List<SceneMonster> sceneMonsters = List.of();
|
||||||
public transient List<SceneGadget> sceneGadgets = List.of();
|
public transient List<SceneGadget> sceneGadgets = List.of();
|
||||||
@ -22,39 +24,40 @@ public class SceneSuite {
|
|||||||
public transient List<SceneRegion> sceneRegions = List.of();
|
public transient List<SceneRegion> sceneRegions = List.of();
|
||||||
|
|
||||||
public void init(SceneGroup sceneGroup) {
|
public void init(SceneGroup sceneGroup) {
|
||||||
if (sceneGroup.monsters != null && this.monsters != null) {
|
if(sceneGroup.monsters != null){
|
||||||
this.sceneMonsters =
|
this.sceneMonsters = new ArrayList<>(
|
||||||
new ArrayList<>(
|
|
||||||
this.monsters.stream()
|
this.monsters.stream()
|
||||||
.filter(sceneGroup.monsters::containsKey)
|
.filter(sceneGroup.monsters::containsKey)
|
||||||
.map(sceneGroup.monsters::get)
|
.map(sceneGroup.monsters::get)
|
||||||
.toList());
|
.toList()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sceneGroup.gadgets != null && this.gadgets != null) {
|
if(sceneGroup.gadgets != null){
|
||||||
this.sceneGadgets =
|
this.sceneGadgets = new ArrayList<>(
|
||||||
new ArrayList<>(
|
|
||||||
this.gadgets.stream()
|
this.gadgets.stream()
|
||||||
.filter(sceneGroup.gadgets::containsKey)
|
.filter(sceneGroup.gadgets::containsKey)
|
||||||
.map(sceneGroup.gadgets::get)
|
.map(sceneGroup.gadgets::get)
|
||||||
.toList());
|
.toList()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sceneGroup.triggers != null && this.triggers != null) {
|
if(sceneGroup.triggers != null) {
|
||||||
this.sceneTriggers =
|
this.sceneTriggers = new ArrayList<>(
|
||||||
new ArrayList<>(
|
|
||||||
this.triggers.stream()
|
this.triggers.stream()
|
||||||
.filter(sceneGroup.triggers::containsKey)
|
.filter(sceneGroup.triggers::containsKey)
|
||||||
.map(sceneGroup.triggers::get)
|
.map(sceneGroup.triggers::get)
|
||||||
.toList());
|
.toList()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (sceneGroup.regions != null && this.regions != null) {
|
if(sceneGroup.regions != null) {
|
||||||
this.sceneRegions =
|
this.sceneRegions = new ArrayList<>(
|
||||||
new ArrayList<>(
|
|
||||||
this.regions.stream()
|
this.regions.stream()
|
||||||
.filter(sceneGroup.regions::containsKey)
|
.filter(sceneGroup.regions::containsKey)
|
||||||
.map(sceneGroup.regions::get)
|
.map(sceneGroup.regions::get)
|
||||||
.toList());
|
.toList()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,28 @@
|
|||||||
package emu.grasscutter.scripts.data;
|
package emu.grasscutter.scripts.data;
|
||||||
|
|
||||||
import lombok.Setter;
|
import lombok.*;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
public class SceneTrigger {
|
@Getter
|
||||||
public String name;
|
@NoArgsConstructor
|
||||||
public int config_id;
|
// todo find way to deserialize from lua with final fields, maybe with the help of Builder?
|
||||||
public int event;
|
public final class SceneTrigger {
|
||||||
public String source;
|
private String name;
|
||||||
public String condition;
|
private int config_id;
|
||||||
public String action;
|
private int event;
|
||||||
public boolean forbid_guest;
|
private int trigger_count = 1;
|
||||||
public int trigger_count;
|
private String source;
|
||||||
public String tlog_tag;
|
private String condition;
|
||||||
|
private String action;
|
||||||
|
private String tag;
|
||||||
|
|
||||||
public transient SceneGroup currentGroup;
|
public transient SceneGroup currentGroup;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if (obj instanceof SceneTrigger sceneTrigger) {
|
if (obj instanceof SceneTrigger sceneTrigger){
|
||||||
return this.name.equals(sceneTrigger.name);
|
return this.name.equals(sceneTrigger.name);
|
||||||
}
|
} else return super.equals(obj);
|
||||||
return super.equals(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -31,29 +32,14 @@ public class SceneTrigger {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SceneTrigger{"
|
return "SceneTrigger{" +
|
||||||
+ "name='"
|
"name='" + name + '\'' +
|
||||||
+ name
|
", config_id=" + config_id +
|
||||||
+ '\''
|
", event=" + event +
|
||||||
+ ", config_id="
|
", source='" + source + '\'' +
|
||||||
+ config_id
|
", condition='" + condition + '\'' +
|
||||||
+ ", event="
|
", action='" + action + '\'' +
|
||||||
+ event
|
", trigger_count='" + trigger_count + '\'' +
|
||||||
+ ", source='"
|
'}';
|
||||||
+ source
|
|
||||||
+ '\''
|
|
||||||
+ ", condition='"
|
|
||||||
+ condition
|
|
||||||
+ '\''
|
|
||||||
+ ", action='"
|
|
||||||
+ action
|
|
||||||
+ '\''
|
|
||||||
+ ", forbid_guest='"
|
|
||||||
+ forbid_guest
|
|
||||||
+ '\''
|
|
||||||
+ ", trigger_count='"
|
|
||||||
+ trigger_count
|
|
||||||
+ '\''
|
|
||||||
+ '}';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,23 @@ public class ScriptArgs {
|
|||||||
public int param3;
|
public int param3;
|
||||||
public int source_eid; // Source entity
|
public int source_eid; // Source entity
|
||||||
public int target_eid;
|
public int target_eid;
|
||||||
|
public int group_id;
|
||||||
|
public String source; // source string, used for timers
|
||||||
|
public int type; // lua event type, used by scripts and the ScriptManager
|
||||||
|
|
||||||
public ScriptArgs() {}
|
public ScriptArgs(int groupId, int eventType) {
|
||||||
|
this(groupId, eventType, 0,0);
|
||||||
public ScriptArgs(int param1) {
|
|
||||||
this.param1 = param1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptArgs(int param1, int param2) {
|
public ScriptArgs(int groupId, int eventType, int param1) {
|
||||||
|
this(groupId, eventType, param1,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScriptArgs(int groupId, int eventType, int param1, int param2) {
|
||||||
|
this.type = eventType;
|
||||||
this.param1 = param1;
|
this.param1 = param1;
|
||||||
this.param2 = param2;
|
this.param2 = param2;
|
||||||
|
this.group_id = groupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getParam1() {
|
public int getParam1() {
|
||||||
@ -62,4 +69,22 @@ public class ScriptArgs {
|
|||||||
this.target_eid = target_eid;
|
this.target_eid = target_eid;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getEventSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScriptArgs setEventSource(String source) {
|
||||||
|
this.source = source;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGroupId() {
|
||||||
|
return group_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScriptArgs setGroupId(int group_id) {
|
||||||
|
this.group_id = group_id;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,13 @@ import emu.grasscutter.scripts.data.SceneGroup;
|
|||||||
import emu.grasscutter.scripts.data.SceneMonster;
|
import emu.grasscutter.scripts.data.SceneMonster;
|
||||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
import emu.grasscutter.scripts.listener.ScriptMonsterListener;
|
import emu.grasscutter.scripts.listener.ScriptMonsterListener;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
public class ScriptMonsterTideService {
|
public final class ScriptMonsterTideService {
|
||||||
private final SceneScriptManager sceneScriptManager;
|
private final SceneScriptManager sceneScriptManager;
|
||||||
private final SceneGroup currentGroup;
|
private final SceneGroup currentGroup;
|
||||||
private final AtomicInteger monsterAlive;
|
private final AtomicInteger monsterAlive;
|
||||||
@ -19,15 +21,12 @@ public class ScriptMonsterTideService {
|
|||||||
private final AtomicInteger monsterKillCount;
|
private final AtomicInteger monsterKillCount;
|
||||||
private final int monsterSceneLimit;
|
private final int monsterSceneLimit;
|
||||||
private final ConcurrentLinkedQueue<Integer> monsterConfigOrders;
|
private final ConcurrentLinkedQueue<Integer> monsterConfigOrders;
|
||||||
private final OnMonsterCreated onMonsterCreated = new OnMonsterCreated();
|
private final List<Integer> monsterConfigIds;
|
||||||
private final OnMonsterDead onMonsterDead = new OnMonsterDead();
|
private final OnMonsterCreated onMonsterCreated= new OnMonsterCreated();
|
||||||
|
private final OnMonsterDead onMonsterDead= new OnMonsterDead();
|
||||||
|
|
||||||
public ScriptMonsterTideService(
|
public ScriptMonsterTideService(SceneScriptManager sceneScriptManager,
|
||||||
SceneScriptManager sceneScriptManager,
|
SceneGroup group, int tideCount, int monsterSceneLimit, Integer[] ordersConfigId){
|
||||||
SceneGroup group,
|
|
||||||
int tideCount,
|
|
||||||
int monsterSceneLimit,
|
|
||||||
Integer[] ordersConfigId) {
|
|
||||||
this.sceneScriptManager = sceneScriptManager;
|
this.sceneScriptManager = sceneScriptManager;
|
||||||
this.currentGroup = group;
|
this.currentGroup = group;
|
||||||
this.monsterSceneLimit = monsterSceneLimit;
|
this.monsterSceneLimit = monsterSceneLimit;
|
||||||
@ -35,44 +34,35 @@ public class ScriptMonsterTideService {
|
|||||||
this.monsterKillCount = new AtomicInteger(0);
|
this.monsterKillCount = new AtomicInteger(0);
|
||||||
this.monsterAlive = new AtomicInteger(0);
|
this.monsterAlive = new AtomicInteger(0);
|
||||||
this.monsterConfigOrders = new ConcurrentLinkedQueue<>(List.of(ordersConfigId));
|
this.monsterConfigOrders = new ConcurrentLinkedQueue<>(List.of(ordersConfigId));
|
||||||
|
this.monsterConfigIds = List.of(ordersConfigId);
|
||||||
|
|
||||||
this.sceneScriptManager
|
this.sceneScriptManager.getScriptMonsterSpawnService().addMonsterCreatedListener(onMonsterCreated);
|
||||||
.getScriptMonsterSpawnService()
|
|
||||||
.addMonsterCreatedListener(onMonsterCreated);
|
|
||||||
this.sceneScriptManager.getScriptMonsterSpawnService().addMonsterDeadListener(onMonsterDead);
|
this.sceneScriptManager.getScriptMonsterSpawnService().addMonsterDeadListener(onMonsterDead);
|
||||||
// spawn the first turn
|
// spawn the first turn
|
||||||
for (int i = 0; i < this.monsterSceneLimit; i++) {
|
for (int i = 0; i < this.monsterSceneLimit; i++) {
|
||||||
sceneScriptManager.addEntity(
|
sceneScriptManager.addEntity(this.sceneScriptManager.createMonster(group.id, group.block_id, getNextMonster()));
|
||||||
this.sceneScriptManager.createMonster(group.id, group.block_id, getNextMonster()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SceneMonster getNextMonster() {
|
public class OnMonsterCreated implements ScriptMonsterListener{
|
||||||
var nextId = this.monsterConfigOrders.poll();
|
|
||||||
if (currentGroup.monsters.containsKey(nextId)) {
|
|
||||||
return currentGroup.monsters.get(nextId);
|
|
||||||
}
|
|
||||||
// TODO some monster config_id do not exist in groups, so temporarily set it to the first
|
|
||||||
return currentGroup.monsters.values().stream().findFirst().orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unload() {
|
|
||||||
this.sceneScriptManager
|
|
||||||
.getScriptMonsterSpawnService()
|
|
||||||
.removeMonsterCreatedListener(onMonsterCreated);
|
|
||||||
this.sceneScriptManager.getScriptMonsterSpawnService().removeMonsterDeadListener(onMonsterDead);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class OnMonsterCreated implements ScriptMonsterListener {
|
|
||||||
@Override
|
@Override
|
||||||
public void onNotify(EntityMonster sceneMonster) {
|
public void onNotify(EntityMonster sceneMonster) {
|
||||||
if (monsterSceneLimit > 0) {
|
if(monsterConfigIds.contains(sceneMonster.getConfigId()) && monsterSceneLimit > 0){
|
||||||
monsterAlive.incrementAndGet();
|
monsterAlive.incrementAndGet();
|
||||||
monsterTideCount.decrementAndGet();
|
monsterTideCount.decrementAndGet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SceneMonster getNextMonster(){
|
||||||
|
var nextId = this.monsterConfigOrders.poll();
|
||||||
|
if(currentGroup.monsters.containsKey(nextId)){
|
||||||
|
return currentGroup.monsters.get(nextId);
|
||||||
|
}
|
||||||
|
// TODO some monster config_id do not exist in groups, so temporarily set it to the first
|
||||||
|
return currentGroup.monsters.values().stream().findFirst().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
public class OnMonsterDead implements ScriptMonsterListener {
|
public class OnMonsterDead implements ScriptMonsterListener {
|
||||||
@Override
|
@Override
|
||||||
public void onNotify(EntityMonster sceneMonster) {
|
public void onNotify(EntityMonster sceneMonster) {
|
||||||
@ -86,14 +76,17 @@ public class ScriptMonsterTideService {
|
|||||||
monsterKillCount.incrementAndGet();
|
monsterKillCount.incrementAndGet();
|
||||||
if (monsterTideCount.get() > 0) {
|
if (monsterTideCount.get() > 0) {
|
||||||
// add more
|
// add more
|
||||||
sceneScriptManager.addEntity(
|
sceneScriptManager.addEntity(sceneScriptManager.createMonster(currentGroup.id, currentGroup.block_id, getNextMonster()));
|
||||||
sceneScriptManager.createMonster(
|
|
||||||
currentGroup.id, currentGroup.block_id, getNextMonster()));
|
|
||||||
}
|
}
|
||||||
// spawn the last turn of monsters
|
// spawn the last turn of monsters
|
||||||
// fix the 5-2
|
// fix the 5-2
|
||||||
sceneScriptManager.callEvent(
|
sceneScriptManager.callEvent(new ScriptArgs(currentGroup.id, EventType.EVENT_MONSTER_TIDE_DIE, monsterKillCount.get()));
|
||||||
EventType.EVENT_MONSTER_TIDE_DIE, new ScriptArgs(monsterKillCount.get()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unload(){
|
||||||
|
this.sceneScriptManager.getScriptMonsterSpawnService().removeMonsterCreatedListener(onMonsterCreated);
|
||||||
|
this.sceneScriptManager.getScriptMonsterSpawnService().removeMonsterDeadListener(onMonsterDead);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,24 @@
|
|||||||
package emu.grasscutter.server.event.entity;
|
package emu.grasscutter.server.event.entity;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
import emu.grasscutter.game.entity.GameEntity;
|
||||||
|
import emu.grasscutter.game.props.ElementType;
|
||||||
import emu.grasscutter.server.event.Cancellable;
|
import emu.grasscutter.server.event.Cancellable;
|
||||||
import emu.grasscutter.server.event.types.EntityEvent;
|
import emu.grasscutter.server.event.types.EntityEvent;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public final class EntityDamageEvent extends EntityEvent implements Cancellable {
|
public final class EntityDamageEvent extends EntityEvent implements Cancellable {
|
||||||
@Nullable private final GameEntity damager;
|
@Getter @Setter private float damage;
|
||||||
private float damage;
|
@Getter @Setter private ElementType attackElementType;
|
||||||
|
@Getter @Nullable private final GameEntity damager;
|
||||||
|
|
||||||
public EntityDamageEvent(GameEntity entity, float damage, @Nullable GameEntity damager) {
|
public EntityDamageEvent(GameEntity entity, float damage, ElementType attackElementType, @Nullable GameEntity damager) {
|
||||||
super(entity);
|
super(entity);
|
||||||
|
|
||||||
this.damage = damage;
|
this.damage = damage;
|
||||||
|
this.attackElementType = attackElementType;
|
||||||
this.damager = damager;
|
this.damager = damager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float getDamage() {
|
|
||||||
return this.damage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDamage(float damage) {
|
|
||||||
this.damage = damage;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable public GameEntity getDamager() {
|
|
||||||
return this.damager;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import emu.grasscutter.game.chat.ChatSystemHandler;
|
|||||||
import emu.grasscutter.game.combine.CombineManger;
|
import emu.grasscutter.game.combine.CombineManger;
|
||||||
import emu.grasscutter.game.drop.DropSystem;
|
import emu.grasscutter.game.drop.DropSystem;
|
||||||
import emu.grasscutter.game.dungeons.DungeonSystem;
|
import emu.grasscutter.game.dungeons.DungeonSystem;
|
||||||
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
|
|
||||||
import emu.grasscutter.game.expedition.ExpeditionSystem;
|
import emu.grasscutter.game.expedition.ExpeditionSystem;
|
||||||
import emu.grasscutter.game.gacha.GachaSystem;
|
import emu.grasscutter.game.gacha.GachaSystem;
|
||||||
import emu.grasscutter.game.managers.cooking.CookingCompoundManager;
|
import emu.grasscutter.game.managers.cooking.CookingCompoundManager;
|
||||||
@ -91,7 +90,6 @@ public final class GameServer extends KcpServer {
|
|||||||
|
|
||||||
this.init(GameSessionManager.getListener(), channelConfig, address);
|
this.init(GameSessionManager.getListener(), channelConfig, address);
|
||||||
|
|
||||||
DungeonChallenge.initialize();
|
|
||||||
EnergyManager.initialize();
|
EnergyManager.initialize();
|
||||||
StaminaManager.initialize();
|
StaminaManager.initialize();
|
||||||
CookingManager.initialize();
|
CookingManager.initialize();
|
||||||
|
@ -1,41 +1,26 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.game.quest.enums.QuestContent;
|
||||||
import emu.grasscutter.data.excels.QuestData.QuestCondition;
|
|
||||||
import emu.grasscutter.game.quest.enums.QuestTrigger;
|
|
||||||
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;
|
||||||
import emu.grasscutter.net.proto.AddQuestContentProgressReqOuterClass;
|
import emu.grasscutter.net.proto.AddQuestContentProgressReqOuterClass.AddQuestContentProgressReq;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketAddQuestContentProgressRsp;
|
import emu.grasscutter.server.packet.send.PacketAddQuestContentProgressRsp;
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.AddQuestContentProgressReq)
|
@Opcodes(PacketOpcodes.AddQuestContentProgressReq)
|
||||||
public class HandlerAddQuestContentProgressReq extends PacketHandler {
|
public class HandlerAddQuestContentProgressReq 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 {
|
||||||
var req = AddQuestContentProgressReqOuterClass.AddQuestContentProgressReq.parseFrom(payload);
|
var req = AddQuestContentProgressReq.parseFrom(payload);
|
||||||
|
|
||||||
// Find all conditions in quest that are the same as the given one
|
// Find all conditions in quest that are the same as the given one
|
||||||
Stream<QuestCondition> finishCond =
|
var type = QuestContent.getContentTriggerByValue(req.getContentType());
|
||||||
GameData.getQuestDataMap().get(req.getParam()).getFinishCond().stream();
|
if(type != null) {
|
||||||
Stream<QuestCondition> acceptCond =
|
session.getPlayer().getQuestManager().queueEvent(type, req.getParam());
|
||||||
GameData.getQuestDataMap().get(req.getParam()).getAcceptCond().stream();
|
|
||||||
Stream<QuestCondition> failCond =
|
|
||||||
GameData.getQuestDataMap().get(req.getParam()).getFailCond().stream();
|
|
||||||
List<QuestCondition> allCondMatch =
|
|
||||||
Stream.concat(Stream.concat(acceptCond, failCond), finishCond)
|
|
||||||
.filter(p -> p.getType().getValue() == req.getContentType())
|
|
||||||
.toList();
|
|
||||||
for (QuestCondition cond : allCondMatch) {
|
|
||||||
session
|
|
||||||
.getPlayer()
|
|
||||||
.getQuestManager()
|
|
||||||
.triggerEvent(
|
|
||||||
QuestTrigger.getContentTriggerByValue(req.getContentType()), cond.getParam());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
session.send(new PacketAddQuestContentProgressRsp(req.getContentType()));
|
session.send(new PacketAddQuestContentProgressRsp(req.getContentType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,69 +1,39 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.GameConstants;
|
|
||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.excels.avatar.AvatarSkillDepotData;
|
|
||||||
import emu.grasscutter.data.excels.world.WorldAreaData;
|
|
||||||
import emu.grasscutter.game.avatar.Avatar;
|
|
||||||
import emu.grasscutter.game.entity.EntityAvatar;
|
|
||||||
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;
|
||||||
import emu.grasscutter.net.proto.AvatarChangeElementTypeReqOuterClass.AvatarChangeElementTypeReq;
|
import emu.grasscutter.net.proto.AvatarChangeElementTypeReqOuterClass.AvatarChangeElementTypeReq;
|
||||||
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketAbilityChangeNotify;
|
|
||||||
import emu.grasscutter.server.packet.send.PacketAvatarChangeElementTypeRsp;
|
import emu.grasscutter.server.packet.send.PacketAvatarChangeElementTypeRsp;
|
||||||
import emu.grasscutter.server.packet.send.PacketAvatarFightPropNotify;
|
import lombok.val;
|
||||||
import emu.grasscutter.server.packet.send.PacketAvatarSkillDepotChangeNotify;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the currently active avatars Element if possible
|
||||||
|
*/
|
||||||
@Opcodes(PacketOpcodes.AvatarChangeElementTypeReq)
|
@Opcodes(PacketOpcodes.AvatarChangeElementTypeReq)
|
||||||
public class HandlerAvatarChangeElementTypeReq extends PacketHandler {
|
public class HandlerAvatarChangeElementTypeReq 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 {
|
||||||
AvatarChangeElementTypeReq req = AvatarChangeElementTypeReq.parseFrom(payload);
|
var req = AvatarChangeElementTypeReq.parseFrom(payload);
|
||||||
|
var area = GameData.getWorldAreaDataMap().get(req.getAreaId());
|
||||||
|
|
||||||
WorldAreaData area = GameData.getWorldAreaDataMap().get(req.getAreaId());
|
if (area == null || area.getElementType() == null || area.getElementType().getDepotIndex() <= 0) {
|
||||||
|
|
||||||
if (area == null
|
|
||||||
|| area.getElementType() == null
|
|
||||||
|| area.getElementType().getDepotValue() <= 0) {
|
|
||||||
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
|
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current avatar, should be one of the main characters
|
val avatar = session.getPlayer().getTeamManager().getCurrentAvatarEntity().getAvatar();
|
||||||
EntityAvatar mainCharacterEntity =
|
if (!avatar.changeElement(area.getElementType())) {
|
||||||
session.getPlayer().getTeamManager().getCurrentAvatarEntity();
|
|
||||||
Avatar mainCharacter = mainCharacterEntity.getAvatar();
|
|
||||||
|
|
||||||
int skillDepotId = area.getElementType().getDepotValue();
|
|
||||||
switch (mainCharacter.getAvatarId()) {
|
|
||||||
case GameConstants.MAIN_CHARACTER_MALE -> skillDepotId += 500;
|
|
||||||
case GameConstants.MAIN_CHARACTER_FEMALE -> skillDepotId += 700;
|
|
||||||
default -> {
|
|
||||||
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
|
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Sanity checks for skill depots
|
|
||||||
AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(skillDepotId);
|
|
||||||
if (skillDepot == null || skillDepot.getId() == mainCharacter.getSkillDepotId()) {
|
|
||||||
session.send(new PacketAvatarChangeElementTypeRsp(Retcode.RET_SVR_ERROR_VALUE));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set skill depot
|
|
||||||
mainCharacter.setSkillDepotData(skillDepot);
|
|
||||||
|
|
||||||
// Success
|
// Success
|
||||||
session.send(new PacketAvatarChangeElementTypeRsp());
|
session.send(new PacketAvatarChangeElementTypeRsp());
|
||||||
|
|
||||||
// Ability change packet
|
|
||||||
session.send(new PacketAvatarSkillDepotChangeNotify(mainCharacter));
|
|
||||||
session.send(new PacketAbilityChangeNotify(mainCharacterEntity));
|
|
||||||
session.send(new PacketAvatarFightPropNotify(mainCharacter));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleFallOnGround(GameSession session, GameEntity entity, MotionState motionState) {
|
private void handleFallOnGround(GameSession session, GameEntity entity, MotionState motionState) {
|
||||||
if (session.getPlayer().inGodmode()) {
|
if (session.getPlayer().isInGodMode()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// People have reported that after plunge attack (client sends a FIGHT instead of
|
// People have reported that after plunge attack (client sends a FIGHT instead of
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
|
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;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
@ -23,6 +24,6 @@ public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
|
|||||||
// Handle skill notify in other managers.
|
// Handle skill notify in other managers.
|
||||||
player.getStaminaManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
player.getStaminaManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
||||||
player.getEnergyManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
player.getEnergyManager().handleEvtDoSkillSuccNotify(session, skillId, casterId);
|
||||||
player.getQuestManager().triggerEvent(QuestContent.QUEST_CONTENT_SKILL, skillId, 0);
|
player.getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_SKILL, skillId, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
|
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;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
@ -16,7 +17,7 @@ public class HandlerGadgetInteractReq extends PacketHandler {
|
|||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getQuestManager()
|
.getQuestManager()
|
||||||
.triggerEvent(QuestContent.QUEST_CONTENT_INTERACT_GADGET, req.getGadgetId());
|
.queueEvent(QuestContent.QUEST_CONTENT_INTERACT_GADGET, req.getGadgetId());
|
||||||
session.getPlayer().interactWith(req.getGadgetEntityId(), req);
|
session.getPlayer().interactWith(req.getGadgetEntityId(), req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,42 +7,41 @@ import emu.grasscutter.game.props.WatcherTriggerType;
|
|||||||
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;
|
||||||
import emu.grasscutter.net.proto.MusicGameSettleReqOuterClass;
|
import emu.grasscutter.net.proto.MusicGameSettleReqOuterClass.MusicGameSettleReq;
|
||||||
|
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketActivityInfoNotify;
|
import emu.grasscutter.server.packet.send.PacketActivityInfoNotify;
|
||||||
import emu.grasscutter.server.packet.send.PacketMusicGameSettleRsp;
|
import emu.grasscutter.server.packet.send.PacketMusicGameSettleRsp;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.MusicGameSettleReq)
|
@Opcodes(PacketOpcodes.MusicGameSettleReq)
|
||||||
public class HandlerMusicGameSettleReq extends PacketHandler {
|
public class HandlerMusicGameSettleReq 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 {
|
||||||
var req = MusicGameSettleReqOuterClass.MusicGameSettleReq.parseFrom(payload);
|
val req = MusicGameSettleReq.parseFrom(payload);
|
||||||
|
|
||||||
var playerData =
|
val activityManager = session.getPlayer().getActivityManager();
|
||||||
session
|
|
||||||
.getPlayer()
|
val playerDataOpt = activityManager.getPlayerActivityDataByActivityType(ActivityType.NEW_ACTIVITY_MUSIC_GAME);
|
||||||
.getActivityManager()
|
if (playerDataOpt.isEmpty()) {
|
||||||
.getPlayerActivityDataByActivityType(ActivityType.NEW_ACTIVITY_MUSIC_GAME);
|
session.send(new PacketMusicGameSettleRsp(RetcodeOuterClass.Retcode.RET_MUSIC_GAME_LEVEL_CONFIG_NOT_FOUND, req));
|
||||||
if (playerData.isEmpty()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var handler = (MusicGameActivityHandler) playerData.get().getActivityHandler();
|
|
||||||
boolean isNewRecord = false;
|
|
||||||
// check if custom beatmap
|
|
||||||
|
|
||||||
|
val playerData = playerDataOpt.get();
|
||||||
|
val handler = (MusicGameActivityHandler) playerData.getActivityHandler();
|
||||||
|
boolean isNewRecord = false;
|
||||||
|
|
||||||
|
// check if custom beatmap
|
||||||
if (req.getUgcGuid() == 0) {
|
if (req.getUgcGuid() == 0) {
|
||||||
session
|
session.getPlayer().getActivityManager().triggerWatcher(
|
||||||
.getPlayer()
|
|
||||||
.getActivityManager()
|
|
||||||
.triggerWatcher(
|
|
||||||
WatcherTriggerType.TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE,
|
WatcherTriggerType.TRIGGER_FLEUR_FAIR_MUSIC_GAME_REACH_SCORE,
|
||||||
String.valueOf(req.getMusicBasicId()),
|
String.valueOf(req.getMusicBasicId()),
|
||||||
String.valueOf(req.getScore()));
|
String.valueOf(req.getScore())
|
||||||
|
);
|
||||||
|
|
||||||
isNewRecord =
|
isNewRecord = handler.setMusicGameRecord(playerData,
|
||||||
handler.setMusicGameRecord(
|
|
||||||
playerData.get(),
|
|
||||||
MusicGamePlayerData.MusicGameRecord.of()
|
MusicGamePlayerData.MusicGameRecord.of()
|
||||||
.musicId(req.getMusicBasicId())
|
.musicId(req.getMusicBasicId())
|
||||||
.maxCombo(req.getMaxCombo())
|
.maxCombo(req.getMaxCombo())
|
||||||
@ -50,18 +49,18 @@ public class HandlerMusicGameSettleReq extends PacketHandler {
|
|||||||
.build());
|
.build());
|
||||||
|
|
||||||
// update activity info
|
// update activity info
|
||||||
session.send(new PacketActivityInfoNotify(handler.toProto(playerData.get())));
|
session.send(new PacketActivityInfoNotify(handler.toProto(playerData, activityManager.getConditionExecutor())));
|
||||||
} else {
|
} else {
|
||||||
handler.setMusicGameCustomBeatmapRecord(
|
handler.setMusicGameCustomBeatmapRecord(playerData,
|
||||||
playerData.get(),
|
|
||||||
MusicGamePlayerData.CustomBeatmapRecord.of()
|
MusicGamePlayerData.CustomBeatmapRecord.of()
|
||||||
.musicShareId(req.getUgcGuid())
|
.musicShareId(req.getUgcGuid())
|
||||||
.score(req.getMaxCombo())
|
.score(req.getMaxCombo())
|
||||||
// .settle(req.getSuccess())
|
.settle(req.getIsSaveScore())
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
session.send(
|
|
||||||
new PacketMusicGameSettleRsp(req.getMusicBasicId(), req.getUgcGuid(), isNewRecord));
|
session.send(new PacketMusicGameSettleRsp(req.getMusicBasicId(), req.getUgcGuid(), isNewRecord));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package emu.grasscutter.server.packet.recv;
|
|||||||
import emu.grasscutter.data.GameData;
|
import emu.grasscutter.data.GameData;
|
||||||
import emu.grasscutter.data.binout.MainQuestData;
|
import emu.grasscutter.data.binout.MainQuestData;
|
||||||
import emu.grasscutter.data.binout.MainQuestData.TalkData;
|
import emu.grasscutter.data.binout.MainQuestData.TalkData;
|
||||||
|
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;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
@ -49,16 +50,16 @@ public class HandlerNpcTalkReq extends PacketHandler {
|
|||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getQuestManager()
|
.getQuestManager()
|
||||||
.triggerEvent(
|
.queueEvent(
|
||||||
QuestContent.QUEST_CONTENT_COMPLETE_ANY_TALK, String.valueOf(req.getTalkId()), 0, 0);
|
QuestContent.QUEST_CONTENT_COMPLETE_ANY_TALK, String.valueOf(req.getTalkId()), 0, 0);
|
||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getQuestManager()
|
.getQuestManager()
|
||||||
.triggerEvent(QuestContent.QUEST_CONTENT_COMPLETE_TALK, req.getTalkId(), 0);
|
.queueEvent(QuestContent.QUEST_CONTENT_COMPLETE_TALK, req.getTalkId(), 0);
|
||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getQuestManager()
|
.getQuestManager()
|
||||||
.triggerEvent(QuestContent.QUEST_CONTENT_FINISH_PLOT, req.getTalkId(), 0);
|
.queueEvent(QuestContent.QUEST_CONTENT_FINISH_PLOT, req.getTalkId(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
session.send(new PacketNpcTalkRsp(req.getNpcEntityId(), req.getTalkId(), req.getEntityId()));
|
session.send(new PacketNpcTalkRsp(req.getNpcEntityId(), req.getTalkId(), req.getEntityId()));
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.game.props.SceneType;
|
import emu.grasscutter.game.props.SceneType;
|
||||||
|
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;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
@ -16,7 +17,7 @@ public class HandlerPostEnterSceneReq extends PacketHandler {
|
|||||||
session
|
session
|
||||||
.getPlayer()
|
.getPlayer()
|
||||||
.getQuestManager()
|
.getQuestManager()
|
||||||
.triggerEvent(QuestContent.QUEST_CONTENT_ENTER_ROOM, session.getPlayer().getSceneId(), 0);
|
.queueEvent(QuestContent.QUEST_CONTENT_ENTER_ROOM, session.getPlayer().getSceneId(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
session.send(new PacketPostEnterSceneRsp(session.getPlayer()));
|
session.send(new PacketPostEnterSceneRsp(session.getPlayer()));
|
||||||
|
@ -2,12 +2,13 @@ package emu.grasscutter.server.packet.recv;
|
|||||||
|
|
||||||
import emu.grasscutter.game.entity.EntityGadget;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.entity.GameEntity;
|
import emu.grasscutter.game.entity.GameEntity;
|
||||||
|
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.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass.SelectWorktopOptionReq;
|
import emu.grasscutter.net.proto.SelectWorktopOptionReqOuterClass.SelectWorktopOptionReq;
|
||||||
import emu.grasscutter.scripts.constants.EventType;
|
import emu.grasscutter.scripts.constants.EventType;
|
||||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||||
|
import emu.grasscutter.net.packet.PacketHandler;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketSelectWorktopOptionRsp;
|
import emu.grasscutter.server.packet.send.PacketSelectWorktopOptionRsp;
|
||||||
|
|
||||||
@ -25,16 +26,14 @@ public class HandlerSelectWorktopOptionReq extends PacketHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
session.getPlayer().getScene().selectWorktopOptionWith(req);
|
session.getPlayer().getScene().selectWorktopOptionWith(req);
|
||||||
session
|
session.getPlayer().getScene().getScriptManager().callEvent(
|
||||||
.getPlayer()
|
new ScriptArgs(entity.getGroupId(), EventType.EVENT_SELECT_OPTION, entity.getConfigId(), req.getOptionId())
|
||||||
.getScene()
|
);
|
||||||
.getScriptManager()
|
session.getPlayer().getQuestManager().queueEvent(QuestContent.QUEST_CONTENT_WORKTOP_SELECT, entity.getConfigId(), req.getOptionId());
|
||||||
.callEvent(
|
|
||||||
EventType.EVENT_SELECT_OPTION,
|
|
||||||
new ScriptArgs(entity.getConfigId(), req.getOptionId()));
|
|
||||||
} finally {
|
} finally {
|
||||||
// Always send packet
|
// Always send packet
|
||||||
session.send(new PacketSelectWorktopOptionRsp(req.getGadgetEntityId(), req.getOptionId()));
|
session.send(new PacketSelectWorktopOptionRsp(req.getGadgetEntityId(), req.getOptionId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ public class HandlerSkipPlayerGameTimeReq extends PacketHandler {
|
|||||||
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
|
||||||
var req = SkipPlayerGameTimeReqOuterClass.SkipPlayerGameTimeReq.parseFrom(payload);
|
var req = SkipPlayerGameTimeReqOuterClass.SkipPlayerGameTimeReq.parseFrom(payload);
|
||||||
var player = session.getPlayer();
|
var player = session.getPlayer();
|
||||||
player.getScene().setTime(req.getGameTime());
|
player.updatePlayerGameTime(req.getGameTime());
|
||||||
player.getScene().broadcastPacket(new PacketPlayerGameTimeNotify(player));
|
player.getScene().broadcastPacket(new PacketPlayerGameTimeNotify(player));
|
||||||
player.sendPacket(new PacketSkipPlayerGameTimeRsp(req));
|
player.sendPacket(new PacketSkipPlayerGameTimeRsp(req));
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,27 @@
|
|||||||
package emu.grasscutter.server.packet.recv;
|
package emu.grasscutter.server.packet.recv;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.platform.EntityPlatform;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
|
import emu.grasscutter.game.entity.gadget.platform.AbilityRoute;
|
||||||
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;
|
||||||
import emu.grasscutter.net.proto.UpdateAbilityCreatedMovingPlatformNotifyOuterClass;
|
import emu.grasscutter.net.proto.UpdateAbilityCreatedMovingPlatformNotifyOuterClass.UpdateAbilityCreatedMovingPlatformNotify;
|
||||||
import emu.grasscutter.server.game.GameSession;
|
import emu.grasscutter.server.game.GameSession;
|
||||||
import emu.grasscutter.server.packet.send.PacketPlatformStartRouteNotify;
|
|
||||||
import emu.grasscutter.server.packet.send.PacketPlatformStopRouteNotify;
|
|
||||||
|
|
||||||
@Opcodes(PacketOpcodes.UpdateAbilityCreatedMovingPlatformNotify)
|
@Opcodes(PacketOpcodes.UpdateAbilityCreatedMovingPlatformNotify)
|
||||||
public class HandlerUpdateAbilityCreatedMovingPlatformNotify extends PacketHandler {
|
public class HandlerUpdateAbilityCreatedMovingPlatformNotify 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 {
|
||||||
var notify =
|
var notify = UpdateAbilityCreatedMovingPlatformNotify.parseFrom(payload);
|
||||||
UpdateAbilityCreatedMovingPlatformNotifyOuterClass.UpdateAbilityCreatedMovingPlatformNotify
|
|
||||||
.parseFrom(payload);
|
|
||||||
var entity = session.getPlayer().getScene().getEntityById(notify.getEntityId());
|
var entity = session.getPlayer().getScene().getEntityById(notify.getEntityId());
|
||||||
|
|
||||||
if (!(entity instanceof EntityPlatform)) {
|
if (!(entity instanceof EntityGadget entityGadget) || !(entityGadget.getRouteConfig() instanceof AbilityRoute)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var scene = ((EntityPlatform) entity).getOwner().getScene();
|
|
||||||
|
|
||||||
switch (notify.getOpType()) {
|
switch (notify.getOpType()) {
|
||||||
case OP_TYPE_ACTIVATE -> scene.broadcastPacket(
|
case OP_TYPE_ACTIVATE -> entityGadget.startPlatform();
|
||||||
new PacketPlatformStartRouteNotify((EntityPlatform) entity, scene));
|
case OP_TYPE_DEACTIVATE -> entityGadget.stopPlatform();
|
||||||
case OP_TYPE_DEACTIVATE -> scene.broadcastPacket(
|
|
||||||
new PacketPlatformStopRouteNotify((EntityPlatform) entity, scene));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ public class PacketChangeGameTimeRsp extends BasePacket {
|
|||||||
super(PacketOpcodes.ChangeGameTimeRsp);
|
super(PacketOpcodes.ChangeGameTimeRsp);
|
||||||
|
|
||||||
ChangeGameTimeRsp proto =
|
ChangeGameTimeRsp proto =
|
||||||
ChangeGameTimeRsp.newBuilder().setCurGameTime(player.getScene().getTime()).build();
|
ChangeGameTimeRsp.newBuilder().setCurGameTime(player.getWorld().getGameTime()).build();
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
|
@ -1,64 +1,13 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.game.dungeons.challenge.WorldChallenge;
|
import emu.grasscutter.game.dungeons.dungeon_results.BaseDungeonResult;
|
||||||
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.DungeonSettleNotifyOuterClass.DungeonSettleNotify;
|
|
||||||
import emu.grasscutter.net.proto.ItemParamOuterClass;
|
|
||||||
import emu.grasscutter.net.proto.TowerLevelEndNotifyOuterClass.TowerLevelEndNotify;
|
|
||||||
|
|
||||||
public class PacketDungeonSettleNotify extends BasePacket {
|
public class PacketDungeonSettleNotify extends BasePacket {
|
||||||
|
public PacketDungeonSettleNotify(BaseDungeonResult result) {
|
||||||
public PacketDungeonSettleNotify(WorldChallenge challenge) {
|
|
||||||
super(PacketOpcodes.DungeonSettleNotify);
|
super(PacketOpcodes.DungeonSettleNotify);
|
||||||
|
|
||||||
DungeonSettleNotify proto =
|
this.setData(result.getProto());
|
||||||
DungeonSettleNotify.newBuilder()
|
|
||||||
.setDungeonId(challenge.getScene().getDungeonData().getId())
|
|
||||||
.setIsSuccess(challenge.isSuccess())
|
|
||||||
.setCloseTime(challenge.getScene().getAutoCloseTime())
|
|
||||||
.setResult(challenge.isSuccess() ? 1 : 0)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
this.setData(proto);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PacketDungeonSettleNotify(
|
|
||||||
WorldChallenge challenge, boolean canJump, boolean hasNextLevel, int nextFloorId) {
|
|
||||||
super(PacketOpcodes.DungeonSettleNotify);
|
|
||||||
|
|
||||||
var continueStatus =
|
|
||||||
TowerLevelEndNotify.ContinueStateType.CONTINUE_STATE_TYPE_CAN_NOT_CONTINUE_VALUE;
|
|
||||||
if (challenge.isSuccess() && canJump) {
|
|
||||||
continueStatus =
|
|
||||||
hasNextLevel
|
|
||||||
? TowerLevelEndNotify.ContinueStateType.CONTINUE_STATE_TYPE_CAN_ENTER_NEXT_LEVEL_VALUE
|
|
||||||
: TowerLevelEndNotify.ContinueStateType
|
|
||||||
.CONTINUE_STATE_TYPE_CAN_ENTER_NEXT_FLOOR_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
var towerLevelEndNotify =
|
|
||||||
TowerLevelEndNotify.newBuilder()
|
|
||||||
.setIsSuccess(challenge.isSuccess())
|
|
||||||
.setContinueState(continueStatus)
|
|
||||||
.addFinishedStarCondList(1)
|
|
||||||
.addFinishedStarCondList(2)
|
|
||||||
.addFinishedStarCondList(3)
|
|
||||||
.addRewardItemList(
|
|
||||||
ItemParamOuterClass.ItemParam.newBuilder().setItemId(201).setCount(1000).build());
|
|
||||||
if (nextFloorId > 0 && canJump) {
|
|
||||||
towerLevelEndNotify.setNextFloorId(nextFloorId);
|
|
||||||
}
|
|
||||||
|
|
||||||
DungeonSettleNotify proto =
|
|
||||||
DungeonSettleNotify.newBuilder()
|
|
||||||
.setDungeonId(challenge.getScene().getDungeonData().getId())
|
|
||||||
.setIsSuccess(challenge.isSuccess())
|
|
||||||
.setCloseTime(challenge.getScene().getAutoCloseTime())
|
|
||||||
.setResult(challenge.isSuccess() ? 1 : 0)
|
|
||||||
.setTowerLevelEndNotify(towerLevelEndNotify.build())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
this.setData(proto);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,9 @@ import emu.grasscutter.net.packet.BasePacket;
|
|||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
import emu.grasscutter.net.proto.EntityFightPropUpdateNotifyOuterClass.EntityFightPropUpdateNotify;
|
import emu.grasscutter.net.proto.EntityFightPropUpdateNotifyOuterClass.EntityFightPropUpdateNotify;
|
||||||
|
|
||||||
public class PacketEntityFightPropUpdateNotify extends BasePacket {
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class PacketEntityFightPropUpdateNotify extends BasePacket {
|
||||||
public PacketEntityFightPropUpdateNotify(GameEntity entity, FightProperty prop) {
|
public PacketEntityFightPropUpdateNotify(GameEntity entity, FightProperty prop) {
|
||||||
super(PacketOpcodes.EntityFightPropUpdateNotify);
|
super(PacketOpcodes.EntityFightPropUpdateNotify);
|
||||||
|
|
||||||
@ -19,4 +20,14 @@ public class PacketEntityFightPropUpdateNotify extends BasePacket {
|
|||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PacketEntityFightPropUpdateNotify(GameEntity entity, Collection<FightProperty> props) {
|
||||||
|
super(PacketOpcodes.EntityFightPropUpdateNotify);
|
||||||
|
|
||||||
|
var protoBuilder = EntityFightPropUpdateNotify.newBuilder()
|
||||||
|
.setEntityId(entity.getId());
|
||||||
|
props.forEach(p -> protoBuilder.putFightPropMap(p.getId(), entity.getFightProperty(p)));
|
||||||
|
|
||||||
|
this.setData(protoBuilder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,9 @@ public class PacketFinishedParentQuestNotify extends BasePacket {
|
|||||||
FinishedParentQuestNotify.Builder proto = FinishedParentQuestNotify.newBuilder();
|
FinishedParentQuestNotify.Builder proto = FinishedParentQuestNotify.newBuilder();
|
||||||
|
|
||||||
for (GameMainQuest mainQuest : player.getQuestManager().getMainQuests().values()) {
|
for (GameMainQuest mainQuest : player.getQuestManager().getMainQuests().values()) {
|
||||||
// Canceled Quests do not appear in this packet
|
//Canceled Quests do not appear in this packet
|
||||||
if (mainQuest.getState() != ParentQuestState.PARENT_QUEST_STATE_CANCELED) {
|
if (mainQuest.getState() != ParentQuestState.PARENT_QUEST_STATE_CANCELED) {
|
||||||
proto.addParentQuestList(mainQuest.toProto());
|
proto.addParentQuestList(mainQuest.toProto(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import emu.grasscutter.game.quest.GameMainQuest;
|
|||||||
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.FinishedParentQuestUpdateNotifyOuterClass.FinishedParentQuestUpdateNotify;
|
import emu.grasscutter.net.proto.FinishedParentQuestUpdateNotifyOuterClass.FinishedParentQuestUpdateNotify;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class PacketFinishedParentQuestUpdateNotify extends BasePacket {
|
public class PacketFinishedParentQuestUpdateNotify extends BasePacket {
|
||||||
@ -11,8 +12,9 @@ public class PacketFinishedParentQuestUpdateNotify extends BasePacket {
|
|||||||
public PacketFinishedParentQuestUpdateNotify(GameMainQuest quest) {
|
public PacketFinishedParentQuestUpdateNotify(GameMainQuest quest) {
|
||||||
super(PacketOpcodes.FinishedParentQuestUpdateNotify);
|
super(PacketOpcodes.FinishedParentQuestUpdateNotify);
|
||||||
|
|
||||||
FinishedParentQuestUpdateNotify proto =
|
FinishedParentQuestUpdateNotify proto = FinishedParentQuestUpdateNotify.newBuilder()
|
||||||
FinishedParentQuestUpdateNotify.newBuilder().addParentQuestList(quest.toProto()).build();
|
.addParentQuestList(quest.toProto(true))
|
||||||
|
.build();
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
@ -23,7 +25,7 @@ public class PacketFinishedParentQuestUpdateNotify extends BasePacket {
|
|||||||
var proto = FinishedParentQuestUpdateNotify.newBuilder();
|
var proto = FinishedParentQuestUpdateNotify.newBuilder();
|
||||||
|
|
||||||
for (GameMainQuest mainQuest : quests) {
|
for (GameMainQuest mainQuest : quests) {
|
||||||
proto.addParentQuestList(mainQuest.toProto());
|
proto.addParentQuestList(mainQuest.toProto(true));
|
||||||
}
|
}
|
||||||
proto.build();
|
proto.build();
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
//package emu.grasscutter.server.packet.send;
|
||||||
|
//
|
||||||
import emu.grasscutter.net.packet.BasePacket;
|
//import emu.grasscutter.net.packet.BasePacket;
|
||||||
import emu.grasscutter.net.packet.PacketOpcodes;
|
//import emu.grasscutter.net.packet.PacketOpcodes;
|
||||||
|
//
|
||||||
public class PacketHomeUnknown2Rsp extends BasePacket {
|
//public class PacketHomeUnknown2Rsp extends BasePacket {
|
||||||
|
//
|
||||||
public PacketHomeUnknown2Rsp() {
|
// public PacketHomeUnknown2Rsp() {
|
||||||
super(PacketOpcodes.Unk2700_KIIOGMKFNNP_ServerRsp);
|
// super(PacketOpcodes.Unk2700_KIIOGMKFNNP_ServerRsp);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
@ -2,7 +2,9 @@ package emu.grasscutter.server.packet.send;
|
|||||||
|
|
||||||
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.MusicGameSettleReqOuterClass;
|
||||||
import emu.grasscutter.net.proto.MusicGameSettleRspOuterClass;
|
import emu.grasscutter.net.proto.MusicGameSettleRspOuterClass;
|
||||||
|
import emu.grasscutter.net.proto.RetcodeOuterClass;
|
||||||
|
|
||||||
public class PacketMusicGameSettleRsp extends BasePacket {
|
public class PacketMusicGameSettleRsp extends BasePacket {
|
||||||
|
|
||||||
@ -13,6 +15,18 @@ public class PacketMusicGameSettleRsp extends BasePacket {
|
|||||||
|
|
||||||
proto.setMusicBasicId(musicBasicId).setUgcGuid(musicShareId).setIsNewRecord(isNewRecord);
|
proto.setMusicBasicId(musicBasicId).setUgcGuid(musicShareId).setIsNewRecord(isNewRecord);
|
||||||
|
|
||||||
|
this.setData(proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketMusicGameSettleRsp(RetcodeOuterClass.Retcode errorCode, MusicGameSettleReqOuterClass.MusicGameSettleReq req) {
|
||||||
|
super(PacketOpcodes.MusicGameSettleRsp);
|
||||||
|
|
||||||
|
var proto = MusicGameSettleRspOuterClass.MusicGameSettleRsp.newBuilder()
|
||||||
|
.setRetcode(errorCode.getNumber())
|
||||||
|
.setMusicBasicId(req.getMusicBasicId())
|
||||||
|
.setUgcGuid(req.getUgcGuid());
|
||||||
|
|
||||||
|
|
||||||
this.setData(proto);
|
this.setData(proto);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,19 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.platform.EntityPlatform;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.world.Scene;
|
|
||||||
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.PlatformStartRouteNotifyOuterClass;
|
import emu.grasscutter.net.proto.PlatformStartRouteNotifyOuterClass.PlatformStartRouteNotify;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
public class PacketPlatformStartRouteNotify extends BasePacket {
|
public class PacketPlatformStartRouteNotify extends BasePacket {
|
||||||
public PacketPlatformStartRouteNotify(EntityPlatform entity, Scene scene) {
|
public PacketPlatformStartRouteNotify(EntityGadget gadgetEntity) {
|
||||||
super(PacketOpcodes.PlatformStartRouteNotify);
|
super(PacketOpcodes.PlatformStartRouteNotify);
|
||||||
|
|
||||||
var notify =
|
val notify = PlatformStartRouteNotify.newBuilder()
|
||||||
PlatformStartRouteNotifyOuterClass.PlatformStartRouteNotify.newBuilder()
|
.setEntityId(gadgetEntity.getId())
|
||||||
.setEntityId(entity.getId())
|
.setSceneTime(gadgetEntity.getScene().getSceneTime())
|
||||||
.setSceneTime(scene.getSceneTime())
|
.setPlatform(gadgetEntity.getPlatformInfo());
|
||||||
.setPlatform(entity.onStartRoute())
|
|
||||||
.build();
|
|
||||||
|
|
||||||
this.setData(notify);
|
this.setData(notify);
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,18 @@
|
|||||||
package emu.grasscutter.server.packet.send;
|
package emu.grasscutter.server.packet.send;
|
||||||
|
|
||||||
import emu.grasscutter.game.entity.platform.EntityPlatform;
|
import emu.grasscutter.game.entity.EntityGadget;
|
||||||
import emu.grasscutter.game.world.Scene;
|
|
||||||
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.PlatformStopRouteNotifyOuterClass;
|
import emu.grasscutter.net.proto.PlatformStopRouteNotifyOuterClass;
|
||||||
|
|
||||||
public class PacketPlatformStopRouteNotify extends BasePacket {
|
public class PacketPlatformStopRouteNotify extends BasePacket {
|
||||||
public PacketPlatformStopRouteNotify(EntityPlatform entity, Scene scene) {
|
public PacketPlatformStopRouteNotify(EntityGadget gadgetEntity) {
|
||||||
super(PacketOpcodes.PlatformStopRouteNotify);
|
super(PacketOpcodes.PlatformStopRouteNotify);
|
||||||
|
|
||||||
var notify =
|
var notify = PlatformStopRouteNotifyOuterClass.PlatformStopRouteNotify.newBuilder()
|
||||||
PlatformStopRouteNotifyOuterClass.PlatformStopRouteNotify.newBuilder()
|
.setPlatform(gadgetEntity.getPlatformInfo())
|
||||||
.setPlatform(entity.onStopRoute())
|
.setSceneTime(gadgetEntity.getScene().getSceneTime())
|
||||||
.setSceneTime(scene.getSceneTime())
|
.setEntityId(gadgetEntity.getId())
|
||||||
.setEntityId(entity.getId())
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
this.setData(notify);
|
this.setData(notify);
|
||||||
|
@ -12,7 +12,7 @@ public class PacketPlayerGameTimeNotify extends BasePacket {
|
|||||||
|
|
||||||
PlayerGameTimeNotify proto =
|
PlayerGameTimeNotify proto =
|
||||||
PlayerGameTimeNotify.newBuilder()
|
PlayerGameTimeNotify.newBuilder()
|
||||||
.setGameTime(player.getScene().getTime())
|
.setGameTime(player.getWorld().getGameTime())
|
||||||
.setUid(player.getUid())
|
.setUid(player.getUid())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -344,7 +344,7 @@ public final class Language {
|
|||||||
"Cache modified %d, textmap modified %d".formatted(cacheModified, textmapsModified));
|
"Cache modified %d, textmap modified %d".formatted(cacheModified, textmapsModified));
|
||||||
if (textmapsModified < cacheModified) {
|
if (textmapsModified < cacheModified) {
|
||||||
// Try loading from cache
|
// Try loading from cache
|
||||||
Grasscutter.getLogger().info("Loading cached 'TextMaps'...");
|
Grasscutter.getLogger().debug("Loading cached 'TextMaps'...");
|
||||||
textMapStrings = loadTextMapsCache();
|
textMapStrings = loadTextMapsCache();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user