mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-12-17 09:25:06 +01:00
Better SceneTags (#2361)
* Add scene tag handling * Move warns to debug * Move to PlayerProgressManager * Add success message * Inline check * Improve per-scene handling * Update src/main/java/emu/grasscutter/command/commands/SetSceneTagCommand.java Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com> * Update src/main/java/emu/grasscutter/command/commands/SetSceneTagCommand.java Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com> * Fix types * Small fix * Update ScriptLib.java --------- Co-authored-by: Magix <27646710+KingRainbow44@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
package emu.grasscutter.command.commands;
|
||||
|
||||
import emu.grasscutter.command.*;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.scene.SceneTagData;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import lombok.val;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Command(label = "setSceneTag", aliases = { "tag" }, usage = {
|
||||
"<add|remove|unlockall> <sceneTagId>" }, permission = "player.setscenetag", permissionTargeted = "player.setscenetag.others")
|
||||
public final class SetSceneTagCommand implements CommandHandler {
|
||||
private final Int2ObjectMap<SceneTagData> sceneTagData = GameData.getSceneTagDataMap();
|
||||
|
||||
@Override
|
||||
public void execute(Player sender, Player targetPlayer, List<String> args) {
|
||||
if (args.size() == 0) {
|
||||
sendUsageMessage(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
val actionStr = args.get(0).toLowerCase();
|
||||
var value = -1;
|
||||
|
||||
if (args.size() > 1) {
|
||||
try {
|
||||
value = Integer.parseInt(args.get(1));
|
||||
} catch (NumberFormatException ignored) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (actionStr.equals("unlockall")) {
|
||||
unlockAllSceneTags(targetPlayer);
|
||||
return;
|
||||
} else {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
val userVal = value;
|
||||
|
||||
var sceneData = sceneTagData.values().stream().filter(sceneTag -> sceneTag.getId() == userVal).findFirst();
|
||||
if (sceneData == null) {
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.id");
|
||||
return;
|
||||
}
|
||||
int scene = sceneData.get().getSceneId();
|
||||
|
||||
switch (actionStr) {
|
||||
case "add", "set" -> addSceneTag(targetPlayer, scene, value);
|
||||
case "remove", "del" -> removeSceneTag(targetPlayer, scene, value);
|
||||
default -> CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error");
|
||||
}
|
||||
|
||||
CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_to", value, actionStr);
|
||||
|
||||
}
|
||||
|
||||
private void addSceneTag(Player targetPlayer, int scene, int value) {
|
||||
targetPlayer.getProgressManager().addSceneTag(scene, value);
|
||||
}
|
||||
|
||||
private void removeSceneTag(Player targetPlayer, int scene, int value) {
|
||||
targetPlayer.getProgressManager().delSceneTag(scene, value);
|
||||
}
|
||||
|
||||
private void unlockAllSceneTags(Player targetPlayer) {
|
||||
var allData = sceneTagData.values();
|
||||
|
||||
// Add all SceneTags
|
||||
allData.stream().toList().forEach(sceneTag -> {
|
||||
if (targetPlayer.getSceneTags().get(sceneTag.getSceneId()) == null) {
|
||||
targetPlayer.getSceneTags().put(sceneTag.getSceneId(), new HashSet<>());
|
||||
}
|
||||
targetPlayer.getSceneTags().get(sceneTag.getSceneId()).add(sceneTag.getId());
|
||||
});
|
||||
|
||||
// Remove default SceneTags, as most are "before" or "locked" states
|
||||
allData.stream().filter(sceneTag -> sceneTag.isDefaultValid())
|
||||
// Only remove for big world as some other scenes only have defaults
|
||||
.filter(sceneTag -> sceneTag.getSceneId() == 3)
|
||||
.forEach(sceneTag -> {
|
||||
targetPlayer.getSceneTags().get(sceneTag.getSceneId()).remove(sceneTag.getId());
|
||||
});
|
||||
|
||||
this.setSceneTags(targetPlayer);
|
||||
}
|
||||
|
||||
private void setSceneTags(Player targetPlayer) {
|
||||
targetPlayer.sendPacket(new PacketPlayerWorldSceneInfoListNotify(targetPlayer));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -116,6 +116,7 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
@Getter private Map<Integer, ActiveCookCompoundData> activeCookCompounds;
|
||||
@Getter private Map<Integer, Integer> questGlobalVariables;
|
||||
@Getter private Map<Integer, Integer> openStates;
|
||||
@Getter private Map<Integer, Set<Integer>> sceneTags;
|
||||
@Getter @Setter private Map<Integer, Set<Integer>> unlockedSceneAreas;
|
||||
@Getter @Setter private Map<Integer, Set<Integer>> unlockedScenePoints;
|
||||
@Getter @Setter private List<Integer> chatEmojiIdList;
|
||||
@@ -244,6 +245,7 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
this.unlockedRecipies = new HashMap<>();
|
||||
this.questGlobalVariables = new HashMap<>();
|
||||
this.openStates = new HashMap<>();
|
||||
this.sceneTags = new HashMap<>();
|
||||
this.unlockedSceneAreas = new HashMap<>();
|
||||
this.unlockedScenePoints = new HashMap<>();
|
||||
this.chatEmojiIdList = new ArrayList<>();
|
||||
@@ -295,6 +297,7 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
this.codex = new PlayerCodex(this);
|
||||
|
||||
this.applyProperties();
|
||||
this.applyStartingSceneTags();
|
||||
this.getFlyCloakList().add(140001);
|
||||
this.getNameCardList().add(210001);
|
||||
|
||||
@@ -587,6 +590,20 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
this.getProperty(PlayerProperty.PROP_DIVE_MAX_STAMINA));
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies all default scenetags to the player.
|
||||
*/
|
||||
private void applyStartingSceneTags() {
|
||||
GameData.getSceneTagDataMap().values().stream()
|
||||
.filter(sceneTag -> sceneTag.isDefaultValid())
|
||||
.forEach(sceneTag -> {
|
||||
if (this.getSceneTags().get(sceneTag.getSceneId()) == null) {
|
||||
this.getSceneTags().put(sceneTag.getSceneId(), new HashSet<>());
|
||||
}
|
||||
this.getSceneTags().get(sceneTag.getSceneId()).add(sceneTag.getId());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a property to the player if it doesn't exist in the database.
|
||||
*
|
||||
@@ -1384,6 +1401,10 @@ public class Player implements PlayerHook, FieldFetch {
|
||||
}
|
||||
*/
|
||||
|
||||
// Ensure the player has valid scenetags, allows old accounts to work
|
||||
if (this.getSceneTags().isEmpty() || this.getSceneTags() == null) {
|
||||
this.applyStartingSceneTags();
|
||||
}
|
||||
|
||||
if (GameHome.HOME_SCENE_IDS.contains(this.getSceneId())) {
|
||||
this.setSceneId(this.prevScene <= 0 ? 3 : this.prevScene); // if the player in home, make the player go back.
|
||||
|
||||
@@ -12,6 +12,8 @@ import emu.grasscutter.game.quest.enums.*;
|
||||
import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode;
|
||||
import emu.grasscutter.scripts.data.ScriptArgs;
|
||||
import emu.grasscutter.server.packet.send.*;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -313,4 +315,28 @@ public final class PlayerProgressManager extends BasePlayerDataManager {
|
||||
player.save();
|
||||
player.getQuestManager().queueEvent(QuestCond.QUEST_COND_HISTORY_GOT_ANY_ITEM, id, newCount);
|
||||
}
|
||||
|
||||
/******************************************************************************************************************
|
||||
******************************************************************************************************************
|
||||
* SCENETAGS
|
||||
******************************************************************************************************************
|
||||
*****************************************************************************************************************/
|
||||
public void addSceneTag(int sceneId, int sceneTagId) {
|
||||
player.getSceneTags().computeIfAbsent(sceneId, k -> new HashSet<>()).add(sceneTagId);
|
||||
player.sendPacket(new PacketPlayerWorldSceneInfoListNotify(player));
|
||||
}
|
||||
|
||||
public void delSceneTag(int sceneId, int sceneTagId) {
|
||||
// Sanity check
|
||||
if (player.getSceneTags().get(sceneId) == null) {
|
||||
// Can't delete something that doesn't exist
|
||||
return;
|
||||
}
|
||||
player.getSceneTags().get(sceneId).remove(sceneTagId);
|
||||
player.sendPacket(new PacketPlayerWorldSceneInfoListNotify(player));
|
||||
}
|
||||
|
||||
public boolean checkSceneTag(int sceneId, int sceneTagId) {
|
||||
return player.getSceneTags().get(sceneId).contains(sceneTagId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1013,22 +1013,22 @@ public class ScriptLib {
|
||||
}
|
||||
|
||||
public int AddSceneTag(int sceneId, int sceneTagId){
|
||||
logger.warn("[LUA] Call unimplemented AddSceneTag with {}, {}", sceneId, sceneTagId);
|
||||
//TODO implement
|
||||
logger.debug("[LUA] Call AddSceneTag with {}, {}", sceneId, sceneTagId);
|
||||
getSceneScriptManager().getScene().getHost().getProgressManager().addSceneTag(sceneId, sceneTagId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int DelSceneTag(int sceneId, int sceneTagId){
|
||||
logger.warn("[LUA] Call unimplemented DelSceneTag with {}, {}", sceneId, sceneTagId);
|
||||
//TODO implement
|
||||
logger.debug("[LUA] Call DelSceneTag with {}, {}", sceneId, sceneTagId);
|
||||
getSceneScriptManager().getScene().getHost().getProgressManager().delSceneTag(sceneId, sceneTagId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean CheckSceneTag(int sceneId, int sceneTagId){
|
||||
logger.warn("[LUA] Call unimplemented CheckSceneTag with {}, {}", sceneId, sceneTagId);
|
||||
//TODO implement
|
||||
return false;
|
||||
logger.debug("[LUA] Call CheckSceneTag with {}, {}", sceneId, sceneTagId);
|
||||
return getSceneScriptManager().getScene().getHost().getProgressManager().checkSceneTag(sceneId, sceneTagId);
|
||||
}
|
||||
|
||||
public int StartHomeGallery(int galleryId, int uid){
|
||||
logger.warn("[LUA] Call unimplemented StartHomeGallery with {} {}", galleryId, uid);
|
||||
//TODO implement
|
||||
|
||||
@@ -17,7 +17,7 @@ public class HandlerSceneInitFinishReq extends PacketHandler {
|
||||
session.send(new PacketServerTimeNotify());
|
||||
session.send(new PacketWorldPlayerInfoNotify(world));
|
||||
session.send(new PacketWorldDataNotify(world));
|
||||
session.send(new PacketPlayerWorldSceneInfoListNotify());
|
||||
session.send(new PacketPlayerWorldSceneInfoListNotify(player));
|
||||
session.send(new BasePacket(PacketOpcodes.SceneForceUnlockNotify));
|
||||
session.send(new PacketHostPlayerNotify(world));
|
||||
|
||||
|
||||
@@ -1,46 +1,48 @@
|
||||
package emu.grasscutter.server.packet.send;
|
||||
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.excels.scene.SceneTagData;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.net.packet.*;
|
||||
import emu.grasscutter.net.proto.MapLayerInfoOuterClass;
|
||||
import emu.grasscutter.net.proto.PlayerWorldSceneInfoListNotifyOuterClass.PlayerWorldSceneInfoListNotify;
|
||||
import emu.grasscutter.net.proto.PlayerWorldSceneInfoOuterClass.PlayerWorldSceneInfo;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class PacketPlayerWorldSceneInfoListNotify extends BasePacket {
|
||||
|
||||
public PacketPlayerWorldSceneInfoListNotify() {
|
||||
public PacketPlayerWorldSceneInfoListNotify(Player player) {
|
||||
super(PacketOpcodes.PlayerWorldSceneInfoListNotify); // Rename opcode later
|
||||
|
||||
var sceneTags = player.getSceneTags();
|
||||
|
||||
PlayerWorldSceneInfoListNotify.Builder proto =
|
||||
PlayerWorldSceneInfoListNotify.newBuilder()
|
||||
.addInfoList(PlayerWorldSceneInfo.newBuilder().setSceneId(1).setIsLocked(false).build())
|
||||
.addInfoList(
|
||||
PlayerWorldSceneInfo.newBuilder()
|
||||
.setSceneId(3)
|
||||
.setIsLocked(false)
|
||||
.addInfoList(PlayerWorldSceneInfo.newBuilder().setSceneId(1).setIsLocked(false).build());
|
||||
|
||||
// Iterate over all scenes
|
||||
for (int scene : GameData.getSceneDataMap().keySet()) {
|
||||
var worldInfoBuilder = PlayerWorldSceneInfo.newBuilder()
|
||||
.setSceneId(scene)
|
||||
.setIsLocked(false);
|
||||
|
||||
/** Add scene-specific data */
|
||||
|
||||
// Scenetags
|
||||
if (sceneTags.keySet().contains(scene)) {
|
||||
worldInfoBuilder
|
||||
.addAllSceneTagIdList(
|
||||
GameData.getSceneTagDataMap().values().stream()
|
||||
.filter(sceneTag -> sceneTag.getSceneId() == 3)
|
||||
.filter(
|
||||
sceneTag ->
|
||||
sceneTag.isDefaultValid()
|
||||
|| sceneTag.getCond().get(0).getCondType() != null)
|
||||
.map(SceneTagData::getId)
|
||||
.toList())
|
||||
// .addSceneTagIdList(102) // Jade chamber (alr added)
|
||||
// .addSceneTagIdList(113)
|
||||
// .addSceneTagIdList(117)
|
||||
// .addSceneTagIdList(1093) // 3.0 Vana_real
|
||||
.addSceneTagIdList(1094) // 3.0 Vana_dream
|
||||
// .addSceneTagIdList(1095) // 3.0 Vana_first
|
||||
// .addSceneTagIdList(1096) // 3.0 Vana_festival
|
||||
.addSceneTagIdList(152) // 3.1 event
|
||||
.addSceneTagIdList(153) // 3.1 event
|
||||
.addSceneTagIdList(1164) // Desert Arena (XMSM_CWLTop)
|
||||
.addSceneTagIdList(1166) // Desert Pyramid (CWL_Trans_02)
|
||||
.setMapLayerInfo(
|
||||
sceneTags.entrySet().stream()
|
||||
.filter(e -> e.getKey().equals(scene))
|
||||
.map(Map.Entry::getValue)
|
||||
.toList()
|
||||
.get(0)
|
||||
);
|
||||
}
|
||||
|
||||
// Map layer information (Big world)
|
||||
if (scene == 3) {
|
||||
worldInfoBuilder.setMapLayerInfo(
|
||||
MapLayerInfoOuterClass.MapLayerInfo.newBuilder()
|
||||
.addAllUnlockedMapLayerIdList(
|
||||
GameData.getMapLayerDataMap().keySet()) // MapLayer Ids
|
||||
@@ -49,31 +51,11 @@ public class PacketPlayerWorldSceneInfoListNotify extends BasePacket {
|
||||
.addAllUnlockedMapLayerGroupIdList(
|
||||
GameData.getMapLayerGroupDataMap()
|
||||
.keySet()) // will show MapLayer options when hovered over
|
||||
.build()) // map layer test
|
||||
.build())
|
||||
.addInfoList(
|
||||
PlayerWorldSceneInfo.newBuilder()
|
||||
.setSceneId(4)
|
||||
.setIsLocked(false)
|
||||
.addSceneTagIdList(106)
|
||||
.addSceneTagIdList(109)
|
||||
.addSceneTagIdList(117)
|
||||
.build())
|
||||
.addInfoList(PlayerWorldSceneInfo.newBuilder().setSceneId(5).setIsLocked(false).build())
|
||||
.addInfoList(PlayerWorldSceneInfo.newBuilder().setSceneId(6).setIsLocked(false).build())
|
||||
.addInfoList(PlayerWorldSceneInfo.newBuilder().setSceneId(7).setIsLocked(false).build())
|
||||
.addInfoList(
|
||||
PlayerWorldSceneInfo.newBuilder()
|
||||
.setSceneId(9)
|
||||
.setIsLocked(false)
|
||||
.addAllSceneTagIdList(IntStream.range(0, 3000).boxed().toList())
|
||||
.build())
|
||||
.addInfoList(
|
||||
PlayerWorldSceneInfo.newBuilder()
|
||||
.setSceneId(10)
|
||||
.setIsLocked(false)
|
||||
.addAllSceneTagIdList(IntStream.range(0, 3000).boxed().toList())
|
||||
.build()); // 3.8
|
||||
.build()); // map layer test
|
||||
}
|
||||
|
||||
proto.addInfoList(worldInfoBuilder.build());
|
||||
}
|
||||
|
||||
this.setData(proto);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user