Merge branch 'development' into unstable

# Conflicts:
#	src/main/java/emu/grasscutter/command/commands/SetPropCommand.java
This commit is contained in:
KingRainbow44 2023-04-24 20:58:14 -04:00
commit 18124bd053
No known key found for this signature in database
GPG Key ID: FC2CB64B00D257BE
2 changed files with 281 additions and 287 deletions

View File

@ -20,7 +20,7 @@
## Quick setup guide ## Quick setup guide
**Note:** For support please join our [Discord](https://discord.gg/T5vZU6UyeG). **Note**: For support please join our [Discord](https://discord.gg/T5vZU6UyeG).
### Requirements ### Requirements
@ -86,7 +86,7 @@ cd Grasscutter
.\gradlew jar # Compile .\gradlew jar # Compile
``` ```
##### Linux ##### Linux (GNU)
```bash ```bash
git clone https://github.com/Grasscutters/Grasscutter.git git clone https://github.com/Grasscutters/Grasscutter.git
@ -97,10 +97,6 @@ chmod +x gradlew
You can find the output jar in the root of the project folder. You can find the output jar in the root of the project folder.
### Commands have moved to the [wiki](https://github.com/Grasscutters/Grasscutter/wiki/Commands)! ### Troubleshooting
# Quick Troubleshooting For a list of common issues and solutions and to ask for help, please join [our Discord server](https://discord.gg/T5vZU6UyeG) and go to the support channel.
* If compiling wasn't successful, please check your JDK installation (Make sure its JDK 17 or higher and validated JDK's bin PATH variable).
* My client doesn't connect, doesn't login, 4206, etc... - Mostly your proxy daemon setup is *the issue*. If you're using Fiddler, change the default port to anything other than 8888.
* Startup sequence: MongoDB > Grasscutter > Proxy Daemon (mitmdump, fiddler, etc.) > Game

View File

@ -1,279 +1,277 @@
package emu.grasscutter.command.commands; package emu.grasscutter.command.commands;
import emu.grasscutter.command.Command; import java.util.HashMap;
import emu.grasscutter.command.CommandHandler; import java.util.List;
import emu.grasscutter.data.GameData; import java.util.Map;
import emu.grasscutter.game.player.Player; import java.util.stream.IntStream;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.game.tower.TowerLevelRecord; import emu.grasscutter.command.Command;
import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify; import emu.grasscutter.command.CommandHandler;
import emu.grasscutter.server.packet.send.PacketSceneAreaUnlockNotify; import emu.grasscutter.data.GameData;
import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify; import emu.grasscutter.game.player.Player;
import java.util.HashMap; import emu.grasscutter.game.props.PlayerProperty;
import java.util.List; import emu.grasscutter.game.tower.TowerLevelRecord;
import java.util.Map; import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify;
import emu.grasscutter.server.packet.send.PacketSceneAreaUnlockNotify;
@Command( import emu.grasscutter.server.packet.send.PacketScenePointUnlockNotify;
label = "setProp",
aliases = {"prop"}, @Command(
usage = {"<prop> <value>"}, label = "setProp",
permission = "player.setprop", aliases = {"prop"},
permissionTargeted = "player.setprop.others") usage = {"<prop> <value>"},
public final class SetPropCommand implements CommandHandler { permission = "player.setprop",
// List of map areas. Unfortunately, there is no readily available source for them in excels or permissionTargeted = "player.setprop.others")
// bins. public final class SetPropCommand implements CommandHandler {
private static final List<Integer> sceneAreas = // List of map areas. Unfortunately, there is no readily available source for them in excels or
List.of( // bins.
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, private static final List<Integer> sceneAreas = IntStream.range(1, 1000).boxed().toList();Map<String, Prop> props;
28, 29, 32, 100, 101, 102, 103, 200, 210, 300, 400, 401, 402, 403);
Map<String, Prop> props; public SetPropCommand() {
this.props = new HashMap<>();
public SetPropCommand() { // Full PlayerProperty enum that won't be advertised but can be used by devs
this.props = new HashMap<>(); for (PlayerProperty prop : PlayerProperty.values()) {
// Full PlayerProperty enum that won't be advertised but can be used by devs String name = prop.toString().substring(5); // PROP_EXP -> EXP
for (PlayerProperty prop : PlayerProperty.values()) { String key = name.toLowerCase(); // EXP -> exp
String name = prop.toString().substring(5); // PROP_EXP -> EXP this.props.put(key, new Prop(name, prop));
String key = name.toLowerCase(); // EXP -> exp }
this.props.put(key, new Prop(name, prop)); // Add special props
} Prop worldlevel =
// Add special props new Prop("World Level", PlayerProperty.PROP_PLAYER_WORLD_LEVEL, PseudoProp.WORLD_LEVEL);
Prop worldlevel = this.props.put("worldlevel", worldlevel);
new Prop("World Level", PlayerProperty.PROP_PLAYER_WORLD_LEVEL, PseudoProp.WORLD_LEVEL); this.props.put("wl", worldlevel);
this.props.put("worldlevel", worldlevel);
this.props.put("wl", worldlevel); Prop abyss = new Prop("Tower Level", PseudoProp.TOWER_LEVEL);
this.props.put("abyss", abyss);
Prop abyss = new Prop("Tower Level", PseudoProp.TOWER_LEVEL); this.props.put("abyssfloor", abyss);
this.props.put("abyss", abyss); this.props.put("ut", abyss);
this.props.put("abyssfloor", abyss); this.props.put("tower", abyss);
this.props.put("ut", abyss); this.props.put("towerlevel", abyss);
this.props.put("tower", abyss); this.props.put("unlocktower", abyss);
this.props.put("towerlevel", abyss);
this.props.put("unlocktower", abyss); Prop bplevel = new Prop("BP Level", PseudoProp.BP_LEVEL);
this.props.put("bplevel", bplevel);
Prop bplevel = new Prop("BP Level", PseudoProp.BP_LEVEL); this.props.put("bp", bplevel);
this.props.put("bplevel", bplevel); this.props.put("battlepass", bplevel);
this.props.put("bp", bplevel);
this.props.put("battlepass", bplevel); Prop godmode = new Prop("GodMode", PseudoProp.GOD_MODE);
this.props.put("godmode", godmode);
Prop godmode = new Prop("GodMode", PseudoProp.GOD_MODE); this.props.put("god", godmode);
this.props.put("godmode", godmode);
this.props.put("god", godmode); Prop nostamina = new Prop("UnlimitedStamina", PseudoProp.UNLIMITED_STAMINA);
this.props.put("unlimitedstamina", nostamina);
Prop nostamina = new Prop("UnlimitedStamina", PseudoProp.UNLIMITED_STAMINA); this.props.put("us", nostamina);
this.props.put("unlimitedstamina", nostamina); this.props.put("nostamina", nostamina);
this.props.put("us", nostamina); this.props.put("nostam", nostamina);
this.props.put("nostamina", nostamina); this.props.put("ns", nostamina);
this.props.put("nostam", nostamina);
this.props.put("ns", nostamina); Prop unlimitedenergy = new Prop("UnlimitedEnergy", PseudoProp.UNLIMITED_ENERGY);
this.props.put("unlimitedenergy", unlimitedenergy);
Prop unlimitedenergy = new Prop("UnlimitedEnergy", PseudoProp.UNLIMITED_ENERGY); this.props.put("ue", unlimitedenergy);
this.props.put("unlimitedenergy", unlimitedenergy);
this.props.put("ue", unlimitedenergy); Prop setopenstate = new Prop("SetOpenstate", PseudoProp.SET_OPENSTATE);
this.props.put("setopenstate", setopenstate);
Prop setopenstate = new Prop("SetOpenstate", PseudoProp.SET_OPENSTATE); this.props.put("so", setopenstate);
this.props.put("setopenstate", setopenstate);
this.props.put("so", setopenstate); Prop unsetopenstate = new Prop("UnsetOpenstate", PseudoProp.UNSET_OPENSTATE);
this.props.put("unsetopenstate", unsetopenstate);
Prop unsetopenstate = new Prop("UnsetOpenstate", PseudoProp.UNSET_OPENSTATE); this.props.put("uo", unsetopenstate);
this.props.put("unsetopenstate", unsetopenstate);
this.props.put("uo", unsetopenstate); Prop unlockmap = new Prop("UnlockMap", PseudoProp.UNLOCK_MAP);
this.props.put("unlockmap", unlockmap);
Prop unlockmap = new Prop("UnlockMap", PseudoProp.UNLOCK_MAP); this.props.put("um", unlockmap);
this.props.put("unlockmap", unlockmap); }
this.props.put("um", unlockmap);
} @Override
public void execute(Player sender, Player targetPlayer, List<String> args) {
@Override if (args.size() != 2) {
public void execute(Player sender, Player targetPlayer, List<String> args) { sendUsageMessage(sender);
if (args.size() != 2) { return;
sendUsageMessage(sender); }
return; String propStr = args.get(0).toLowerCase();
} String valueStr = args.get(1).toLowerCase();
String propStr = args.get(0).toLowerCase(); int value;
String valueStr = args.get(1).toLowerCase();
int value; if (!props.containsKey(propStr)) {
sendUsageMessage(sender);
if (!props.containsKey(propStr)) { return;
sendUsageMessage(sender); }
return; try {
} value =
try { switch (valueStr.toLowerCase()) {
value = case "on", "true" -> 1;
switch (valueStr.toLowerCase()) { case "off", "false" -> 0;
case "on", "true" -> 1; case "toggle" -> -1;
case "off", "false" -> 0; default -> Integer.parseInt(valueStr);
case "toggle" -> -1; };
default -> Integer.parseInt(valueStr); } catch (NumberFormatException ignored) {
}; CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error");
} catch (NumberFormatException ignored) { return;
CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error"); }
return;
} boolean success = false;
Prop prop = props.get(propStr);
boolean success = false;
Prop prop = props.get(propStr); success =
switch (prop.pseudoProp) {
success = case WORLD_LEVEL -> targetPlayer.setWorldLevel(value);
switch (prop.pseudoProp) { case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value);
case WORLD_LEVEL -> targetPlayer.setWorldLevel(value); case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value);
case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value); case GOD_MODE, UNLIMITED_STAMINA, UNLIMITED_ENERGY -> this.setBool(
case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value); sender, targetPlayer, prop.pseudoProp, value);
case GOD_MODE, UNLIMITED_STAMINA, UNLIMITED_ENERGY -> this.setBool( case SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1);
sender, targetPlayer, prop.pseudoProp, value); case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0);
case SET_OPENSTATE -> this.setOpenState(targetPlayer, value, 1); case UNLOCK_MAP -> unlockMap(targetPlayer);
case UNSET_OPENSTATE -> this.setOpenState(targetPlayer, value, 0); default -> targetPlayer.setProperty(prop.prop, value);
case UNLOCK_MAP -> unlockMap(targetPlayer); };
default -> targetPlayer.setProperty(prop.prop, value);
}; if (success) {
if (targetPlayer == sender) {
if (success) { CommandHandler.sendTranslatedMessage(
if (targetPlayer == sender) { sender, "commands.generic.set_to", prop.name, valueStr);
CommandHandler.sendTranslatedMessage( } else {
sender, "commands.generic.set_to", prop.name, valueStr); String uidStr = targetPlayer.getAccount().getId();
} else { CommandHandler.sendTranslatedMessage(
String uidStr = targetPlayer.getAccount().getId(); sender, "commands.generic.set_for_to", prop.name, uidStr, valueStr);
CommandHandler.sendTranslatedMessage( }
sender, "commands.generic.set_for_to", prop.name, uidStr, valueStr); } else {
} if (prop.prop
} else { != PlayerProperty.PROP_NONE) { // PseudoProps need to do their own error messages
if (prop.prop int min = targetPlayer.getPropertyMin(prop.prop);
!= PlayerProperty.PROP_NONE) { // PseudoProps need to do their own error messages int max = targetPlayer.getPropertyMax(prop.prop);
int min = targetPlayer.getPropertyMin(prop.prop); CommandHandler.sendTranslatedMessage(
int max = targetPlayer.getPropertyMax(prop.prop); sender, "commands.generic.invalid.value_between", prop.name, min, max);
CommandHandler.sendTranslatedMessage( }
sender, "commands.generic.invalid.value_between", prop.name, min, max); }
} }
}
} private boolean setTowerLevel(Player sender, Player targetPlayer, int topFloor) {
List<Integer> floorIds = targetPlayer.getServer().getTowerSystem().getAllFloors();
private boolean setTowerLevel(Player sender, Player targetPlayer, int topFloor) { if (topFloor < 0 || topFloor > floorIds.size()) {
List<Integer> floorIds = targetPlayer.getServer().getTowerSystem().getAllFloors(); CommandHandler.sendTranslatedMessage(
if (topFloor < 0 || topFloor > floorIds.size()) { sender, "commands.generic.invalid.value_between", "Tower Level", 0, floorIds.size());
CommandHandler.sendTranslatedMessage( return false;
sender, "commands.generic.invalid.value_between", "Tower Level", 0, floorIds.size()); }
return false;
} Map<Integer, TowerLevelRecord> recordMap = targetPlayer.getTowerManager().getRecordMap();
// Add records for each unlocked floor
Map<Integer, TowerLevelRecord> recordMap = targetPlayer.getTowerManager().getRecordMap(); for (int floor : floorIds.subList(0, topFloor)) {
// Add records for each unlocked floor if (!recordMap.containsKey(floor)) {
for (int floor : floorIds.subList(0, topFloor)) { recordMap.put(floor, new TowerLevelRecord(floor));
if (!recordMap.containsKey(floor)) { }
recordMap.put(floor, new TowerLevelRecord(floor)); }
} // Remove records for each floor past our target
} for (int floor : floorIds.subList(topFloor, floorIds.size())) {
// Remove records for each floor past our target recordMap.remove(floor);
for (int floor : floorIds.subList(topFloor, floorIds.size())) { }
recordMap.remove(floor); // Six stars required on Floor 8 to unlock Floor 9+
} if (topFloor > 8) {
// Six stars required on Floor 8 to unlock Floor 9+ recordMap
if (topFloor > 8) { .get(floorIds.get(7))
recordMap .setLevelStars(
.get(floorIds.get(7)) 0,
.setLevelStars( 6); // levelIds seem to start at 1 for Floor 1 Chamber 1, so this doesn't get shown at
0, // all
6); // levelIds seem to start at 1 for Floor 1 Chamber 1, so this doesn't get shown at }
// all return true;
} }
return true;
} private boolean setBool(Player sender, Player targetPlayer, PseudoProp pseudoProp, int value) {
boolean enabled =
private boolean setBool(Player sender, Player targetPlayer, PseudoProp pseudoProp, int value) { switch (pseudoProp) {
boolean enabled = case GOD_MODE -> targetPlayer.inGodmode();
switch (pseudoProp) { case UNLIMITED_STAMINA -> targetPlayer.getUnlimitedStamina();
case GOD_MODE -> targetPlayer.inGodmode(); case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().getEnergyUsage();
case UNLIMITED_STAMINA -> targetPlayer.getUnlimitedStamina(); default -> false;
case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().getEnergyUsage(); };
default -> false; enabled =
}; switch (value) {
enabled = case -1 -> !enabled;
switch (value) { case 0 -> false;
case -1 -> !enabled; default -> true;
case 0 -> false; };
default -> true;
}; switch (pseudoProp) {
case GOD_MODE:
switch (pseudoProp) { targetPlayer.setGodmode(enabled);
case GOD_MODE: break;
targetPlayer.setGodmode(enabled); case UNLIMITED_STAMINA:
break; targetPlayer.setUnlimitedStamina(enabled);
case UNLIMITED_STAMINA: break;
targetPlayer.setUnlimitedStamina(enabled); case UNLIMITED_ENERGY:
break; targetPlayer.getEnergyManager().setEnergyUsage(!enabled);
case UNLIMITED_ENERGY: break;
targetPlayer.getEnergyManager().setEnergyUsage(!enabled); default:
break; return false;
default: }
return false; return true;
} }
return true;
} private boolean setOpenState(Player targetPlayer, int state, int value) {
targetPlayer.sendPacket(new PacketOpenStateChangeNotify(state, value));
private boolean setOpenState(Player targetPlayer, int state, int value) { return true;
targetPlayer.sendPacket(new PacketOpenStateChangeNotify(state, value)); }
return true;
} private boolean unlockMap(Player targetPlayer) {
// Unlock.
private boolean unlockMap(Player targetPlayer) { GameData.getScenePointsPerScene()
// Unlock. .forEach(
GameData.getScenePointsPerScene() (sceneId, scenePoints) -> {
.forEach( // Unlock trans points.
(sceneId, scenePoints) -> { targetPlayer.getUnlockedScenePoints(sceneId).addAll(scenePoints);
// Unlock trans points.
targetPlayer.getUnlockedScenePoints(sceneId).addAll(scenePoints); // Unlock map areas.
targetPlayer.getUnlockedSceneAreas(sceneId).addAll(sceneAreas);
// Unlock map areas. });
targetPlayer.getUnlockedSceneAreas(sceneId).addAll(sceneAreas);
}); // Send notify.
int playerScene = targetPlayer.getSceneId();
// Send notify. targetPlayer.sendPacket(
int playerScene = targetPlayer.getSceneId(); new PacketScenePointUnlockNotify(
targetPlayer.sendPacket( playerScene, targetPlayer.getUnlockedScenePoints(playerScene)));
new PacketScenePointUnlockNotify( targetPlayer.sendPacket(
playerScene, targetPlayer.getUnlockedScenePoints(playerScene))); new PacketSceneAreaUnlockNotify(
targetPlayer.sendPacket( playerScene, targetPlayer.getUnlockedSceneAreas(playerScene)));
new PacketSceneAreaUnlockNotify( return true;
playerScene, targetPlayer.getUnlockedSceneAreas(playerScene))); }
return true;
} enum PseudoProp {
NONE,
enum PseudoProp { WORLD_LEVEL,
NONE, TOWER_LEVEL,
WORLD_LEVEL, BP_LEVEL,
TOWER_LEVEL, GOD_MODE,
BP_LEVEL, UNLIMITED_STAMINA,
GOD_MODE, UNLIMITED_ENERGY,
UNLIMITED_STAMINA, SET_OPENSTATE,
UNLIMITED_ENERGY, UNSET_OPENSTATE,
SET_OPENSTATE, UNLOCK_MAP
UNSET_OPENSTATE, }
UNLOCK_MAP
} static class Prop {
String name;
static class Prop { PlayerProperty prop;
String name; PseudoProp pseudoProp;
PlayerProperty prop;
PseudoProp pseudoProp; public Prop(PlayerProperty prop) {
this(prop.toString(), prop, PseudoProp.NONE);
public Prop(PlayerProperty prop) { }
this(prop.toString(), prop, PseudoProp.NONE);
} public Prop(String name) {
this(name, PlayerProperty.PROP_NONE, PseudoProp.NONE);
public Prop(String name) { }
this(name, PlayerProperty.PROP_NONE, PseudoProp.NONE);
} public Prop(String name, PseudoProp pseudoProp) {
this(name, PlayerProperty.PROP_NONE, pseudoProp);
public Prop(String name, PseudoProp pseudoProp) { }
this(name, PlayerProperty.PROP_NONE, pseudoProp);
} public Prop(String name, PlayerProperty prop) {
this(name, prop, PseudoProp.NONE);
public Prop(String name, PlayerProperty prop) { }
this(name, prop, PseudoProp.NONE);
} public Prop(String name, PlayerProperty prop, PseudoProp pseudoProp) {
this.name = name;
public Prop(String name, PlayerProperty prop, PseudoProp pseudoProp) { this.prop = prop;
this.name = name; this.pseudoProp = pseudoProp;
this.prop = prop; }
this.pseudoProp = pseudoProp; }
} }
}
}