Skip to content
Snippets Groups Projects
Commit 5c275c2e authored by gentlespoon's avatar gentlespoon Committed by Melledy
Browse files

SetPlayerPropReq Handler and player.setProperty() sanity check.

parent 37c2ee5e
Branches
Tags
No related merge requests found
...@@ -29,19 +29,16 @@ import emu.grasscutter.game.managers.MapMarkManager.*; ...@@ -29,19 +29,16 @@ import emu.grasscutter.game.managers.MapMarkManager.*;
import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.Scene;
import emu.grasscutter.game.world.World; import emu.grasscutter.game.world.World;
import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.proto.*;
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult; import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry; import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType; import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
import emu.grasscutter.net.proto.MpSettingTypeOuterClass.MpSettingType; import emu.grasscutter.net.proto.MpSettingTypeOuterClass.MpSettingType;
import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo; import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo;
import emu.grasscutter.net.proto.PlayerApplyEnterMpResultNotifyOuterClass;
import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo; import emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo;
import emu.grasscutter.net.proto.PlayerWorldLocationInfoOuterClass;
import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture; import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture;
import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass;
import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail;
import emu.grasscutter.net.proto.SocialShowAvatarInfoOuterClass;
import emu.grasscutter.server.event.player.PlayerJoinEvent; import emu.grasscutter.server.event.player.PlayerJoinEvent;
import emu.grasscutter.server.event.player.PlayerQuitEvent; import emu.grasscutter.server.event.player.PlayerQuitEvent;
import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameServer;
...@@ -59,6 +56,9 @@ import java.util.concurrent.LinkedBlockingQueue; ...@@ -59,6 +56,9 @@ import java.util.concurrent.LinkedBlockingQueue;
@Entity(value = "players", useDiscriminator = false) @Entity(value = "players", useDiscriminator = false)
public class Player { public class Player {
@Transient private static int GlobalMaximumSpringVolume = 8500000;
@Transient private static int GlobalMaximumStamina = 24000;
@Id private int id; @Id private int id;
@Indexed(options = @IndexOptions(unique = true)) private String accountId; @Indexed(options = @IndexOptions(unique = true)) private String accountId;
...@@ -395,12 +395,14 @@ public class Player { ...@@ -395,12 +395,14 @@ public class Player {
return playerProfile; return playerProfile;
} }
// TODO: Based on the proto, property value could be int or float.
// Although there's no float value at this moment, our code should be prepared for float values.
public Map<Integer, Integer> getProperties() { public Map<Integer, Integer> getProperties() {
return properties; return properties;
} }
public void setProperty(PlayerProperty prop, int value) { public boolean setProperty(PlayerProperty prop, int value) {
getProperties().put(prop.getId(), value); return setPropertyWithSanityCheck(prop, value);
} }
public int getProperty(PlayerProperty prop) { public int getProperty(PlayerProperty prop) {
...@@ -1107,4 +1109,102 @@ public class Player { ...@@ -1107,4 +1109,102 @@ public class Player {
public void setMessageHandler(MessageHandler messageHandler) { public void setMessageHandler(MessageHandler messageHandler) {
this.messageHandler = messageHandler; this.messageHandler = messageHandler;
} }
private void saveSanityCheckedProperty(PlayerProperty prop, int value) {
getProperties().put(prop.getId(), value);
}
private boolean setPropertyWithSanityCheck(PlayerProperty prop, int value) {
if (prop == PlayerProperty.PROP_EXP) { // 1001
if (!(value >= 0)) { return false; }
} else if (prop == PlayerProperty.PROP_BREAK_LEVEL) { // 1002
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_SATIATION_VAL) { // 1003
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_SATIATION_PENALTY_TIME) { // 1004
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_LEVEL) { // 4001
if (!(value >= 0 && value <= 90)) { return false; }
} else if (prop == PlayerProperty.PROP_LAST_CHANGE_AVATAR_TIME) { // 10001
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_MAX_SPRING_VOLUME) { // 10002
if (!(value >= 0 && value <= GlobalMaximumSpringVolume)) { return false; }
} else if (prop == PlayerProperty.PROP_CUR_SPRING_VOLUME) { // 10003
int playerMaximumSpringVolume = getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME);
if (!(value >= 0 && value <= playerMaximumSpringVolume)) { return false; }
} else if (prop == PlayerProperty.PROP_IS_SPRING_AUTO_USE) { // 10004
if (!(value >= 0 && value <= 1)) { return false; }
} else if (prop == PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT) { // 10005
if (!(value >= 0 && value <= 100)) { return false; }
} else if (prop == PlayerProperty.PROP_IS_FLYABLE) { // 10006
if (!(0 <= value && value <= 1)) { return false; }
} else if (prop == PlayerProperty.PROP_IS_WEATHER_LOCKED) { // 10007
if (!(0 <= value && value <= 1)) { return false; }
} else if (prop == PlayerProperty.PROP_IS_GAME_TIME_LOCKED) { // 10008
if (!(0 <= value && value <= 1)) { return false; }
} else if (prop == PlayerProperty.PROP_IS_TRANSFERABLE) { // 10009
if (!(0 <= value && value <= 1)) { return false; }
} else if (prop == PlayerProperty.PROP_MAX_STAMINA) { // 10010
if (!(value >= 0 && value <= GlobalMaximumStamina)) { return false; }
} else if (prop == PlayerProperty.PROP_CUR_PERSIST_STAMINA) { // 10011
int playerMaximumStamina = getProperty(PlayerProperty.PROP_MAX_STAMINA);
if (!(value >= 0 && value <= playerMaximumStamina)) { return false; }
} else if (prop == PlayerProperty.PROP_CUR_TEMPORARY_STAMINA) { // 10012
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_PLAYER_LEVEL) { // 10013
if (!(0 < value && value <= 90)) { return false; }
} else if (prop == PlayerProperty.PROP_PLAYER_EXP) { // 10014
if (!(0 <= value)) { return false; }
} else if (prop == PlayerProperty.PROP_PLAYER_HCOIN) { // 10015
// see 10015
} else if (prop == PlayerProperty.PROP_PLAYER_SCOIN) { // 10016
// See 10015
} else if (prop == PlayerProperty.PROP_PLAYER_MP_SETTING_TYPE) { // 10017
if (!(0 <= value && value <= 2)) { return false; }
} else if (prop == PlayerProperty.PROP_IS_MP_MODE_AVAILABLE) { // 10018
if (!(0 <= value && value <= 1)) { return false; }
} else if (prop == PlayerProperty.PROP_PLAYER_WORLD_LEVEL) { // 10019
if (!(0 <= value && value <= 8)) { return false; }
} else if (prop == PlayerProperty.PROP_PLAYER_RESIN) { // 10020
// Do not set 160 as a cap, because player can have more than 160 when they use fragile resin.
if (!(0 <= value)) { return false; }
} else if (prop == PlayerProperty.PROP_PLAYER_WAIT_SUB_HCOIN) { // 10022
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_PLAYER_WAIT_SUB_SCOIN) { // 10023
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_IS_ONLY_MP_WITH_PS_PLAYER) { // 10024
if (!(0 <= value && value <= 1)) { return false; }
} else if (prop == PlayerProperty.PROP_PLAYER_MCOIN) { // 10025
// see 10015
} else if (prop == PlayerProperty.PROP_PLAYER_WAIT_SUB_MCOIN) { // 10026
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_PLAYER_LEGENDARY_KEY) { // 10027
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_IS_HAS_FIRST_SHARE) { // 10028
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_PLAYER_FORGE_POINT) { // 10029
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_CUR_CLIMATE_METER) { // 10035
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_CUR_CLIMATE_TYPE) { // 10036
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_CUR_CLIMATE_AREA_ID) { // 10037
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_CUR_CLIMATE_AREA_CLIMATE_TYPE) { // 10038
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_PLAYER_WORLD_LEVEL_LIMIT) { // 10039
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_PLAYER_WORLD_LEVEL_ADJUST_CD) { // 10040
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM) { // 10041
// TODO: implement sanity check
} else if (prop == PlayerProperty.PROP_PLAYER_HOME_COIN) { // 10042
if (!(0 <= value)) { return false; }
} else if (prop == PlayerProperty.PROP_PLAYER_WAIT_SUB_HOME_COIN) { // 10043
// TODO: implement sanity check
}
saveSanityCheckedProperty(prop, value);
return false;
}
} }
...@@ -12,29 +12,31 @@ public enum PlayerProperty { ...@@ -12,29 +12,31 @@ public enum PlayerProperty {
PROP_SATIATION_PENALTY_TIME (1004), PROP_SATIATION_PENALTY_TIME (1004),
PROP_LEVEL (4001), PROP_LEVEL (4001),
PROP_LAST_CHANGE_AVATAR_TIME (10001), PROP_LAST_CHANGE_AVATAR_TIME (10001),
PROP_MAX_SPRING_VOLUME (10002), PROP_MAX_SPRING_VOLUME (10002), // Maximum volume of the Statue of the Seven for the player [0, 8500000]
PROP_CUR_SPRING_VOLUME (10003), PROP_CUR_SPRING_VOLUME (10003), // Current volume of the Statue of the Seven [0, PROP_MAX_SPRING_VOLUME]
PROP_IS_SPRING_AUTO_USE (10004), PROP_IS_SPRING_AUTO_USE (10004), // Auto HP recovery when approaching the Statue of the Seven [0, 1]
PROP_SPRING_AUTO_USE_PERCENT (10005), PROP_SPRING_AUTO_USE_PERCENT (10005), // Auto HP recovery percentage [0, 100]
PROP_IS_FLYABLE (10006), PROP_IS_FLYABLE (10006), // Are you in a state that disables your flying ability? e.g. new player [0, 1]
PROP_IS_WEATHER_LOCKED (10007), PROP_IS_WEATHER_LOCKED (10007),
PROP_IS_GAME_TIME_LOCKED (10008), PROP_IS_GAME_TIME_LOCKED (10008),
PROP_IS_TRANSFERABLE (10009), PROP_IS_TRANSFERABLE (10009),
PROP_MAX_STAMINA (10010), PROP_MAX_STAMINA (10010), // Maximum stamina of the player (0 - 24000)
PROP_CUR_PERSIST_STAMINA (10011), PROP_CUR_PERSIST_STAMINA (10011), // Used stamina of the player (0 - PROP_MAX_STAMINA)
PROP_CUR_TEMPORARY_STAMINA (10012), PROP_CUR_TEMPORARY_STAMINA (10012),
PROP_PLAYER_LEVEL (10013), PROP_PLAYER_LEVEL (10013),
PROP_PLAYER_EXP (10014), PROP_PLAYER_EXP (10014),
PROP_PLAYER_HCOIN (10015), // Primogem PROP_PLAYER_HCOIN (10015), // Primogem (-inf, +inf)
PROP_PLAYER_SCOIN (10016), // Mora // It is known that Mihoyo will make Primogem negative in the cases that a player spends
PROP_PLAYER_MP_SETTING_TYPE (10017), // his gems and then got a money refund, so negative is allowed.
PROP_IS_MP_MODE_AVAILABLE (10018), PROP_PLAYER_SCOIN (10016), // Mora [0, +inf)
PROP_PLAYER_WORLD_LEVEL (10019), PROP_PLAYER_MP_SETTING_TYPE (10017), // Do you allow other players to join your game? [0=no 1=direct 2=approval]
PROP_PLAYER_RESIN (10020), PROP_IS_MP_MODE_AVAILABLE (10018), // Are you not in a quest or something that disables MP? [0, 1]
PROP_PLAYER_WORLD_LEVEL (10019), // [0, 8]
PROP_PLAYER_RESIN (10020), // Original Resin [0, +inf)
PROP_PLAYER_WAIT_SUB_HCOIN (10022), PROP_PLAYER_WAIT_SUB_HCOIN (10022),
PROP_PLAYER_WAIT_SUB_SCOIN (10023), PROP_PLAYER_WAIT_SUB_SCOIN (10023),
PROP_IS_ONLY_MP_WITH_PS_PLAYER (10024), PROP_IS_ONLY_MP_WITH_PS_PLAYER (10024), // Is only MP with PlayStation players? [0, 1]
PROP_PLAYER_MCOIN (10025), // Genesis Crystal PROP_PLAYER_MCOIN (10025), // Genesis Crystal (-inf, +inf) see 10015
PROP_PLAYER_WAIT_SUB_MCOIN (10026), PROP_PLAYER_WAIT_SUB_MCOIN (10026),
PROP_PLAYER_LEGENDARY_KEY (10027), PROP_PLAYER_LEGENDARY_KEY (10027),
PROP_IS_HAS_FIRST_SHARE (10028), PROP_IS_HAS_FIRST_SHARE (10028),
...@@ -46,7 +48,7 @@ public enum PlayerProperty { ...@@ -46,7 +48,7 @@ public enum PlayerProperty {
PROP_PLAYER_WORLD_LEVEL_LIMIT (10039), PROP_PLAYER_WORLD_LEVEL_LIMIT (10039),
PROP_PLAYER_WORLD_LEVEL_ADJUST_CD (10040), PROP_PLAYER_WORLD_LEVEL_ADJUST_CD (10040),
PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM (10041), PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM (10041),
PROP_PLAYER_HOME_COIN (10042), PROP_PLAYER_HOME_COIN (10042), // Realm currency [0, +inf)
PROP_PLAYER_WAIT_SUB_HOME_COIN (10043); PROP_PLAYER_WAIT_SUB_HOME_COIN (10043);
private final int id; private final int id;
...@@ -56,7 +58,7 @@ public enum PlayerProperty { ...@@ -56,7 +58,7 @@ public enum PlayerProperty {
Stream.of(values()).forEach(e -> map.put(e.getId(), e)); Stream.of(values()).forEach(e -> map.put(e.getId(), e));
} }
private PlayerProperty(int id) { PlayerProperty(int id) {
this.id = id; this.id = id;
} }
......
package emu.grasscutter.server.packet.recv;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.game.props.PlayerProperty;
import emu.grasscutter.net.packet.Opcodes;
import emu.grasscutter.net.packet.PacketHandler;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.PropValueOuterClass.PropValue;
import emu.grasscutter.net.proto.SetPlayerPropReqOuterClass.SetPlayerPropReq;
import emu.grasscutter.server.game.GameSession;
import emu.grasscutter.server.packet.send.PacketSetPlayerNameRsp;
import emu.grasscutter.server.packet.send.PacketSetPlayerPropRsp;
import java.util.ArrayList;
import java.util.List;
@Opcodes(PacketOpcodes.SetPlayerPropReq)
public class HandlerSetPlayerPropReq extends PacketHandler {
@Override
public void handle(GameSession session, byte[] header, byte[] payload) throws Exception {
// Auto template
SetPlayerPropReq req = SetPlayerPropReq.parseFrom(payload);
Player player = session.getPlayer();
List<PropValue> propList = req.getPropListList();
for (int i = 0; i < propList.size(); i++) {
if (!player.setProperty(PlayerProperty.getPropById(propList.get(i).getType()), (int)propList.get(i).getVal())) {
session.send(new PacketSetPlayerPropRsp(1));
}
}
player.save();
session.send(new PacketSetPlayerPropRsp(0));
}
}
package emu.grasscutter.server.packet.send;
import emu.grasscutter.game.player.Player;
import emu.grasscutter.net.packet.BasePacket;
import emu.grasscutter.net.packet.PacketOpcodes;
import emu.grasscutter.net.proto.SetPlayerPropRspOuterClass;
import emu.grasscutter.net.proto.SetPlayerPropRspOuterClass.SetPlayerPropRsp;
public class PacketSetPlayerPropRsp extends BasePacket {
public PacketSetPlayerPropRsp(int retCode) {
super(PacketOpcodes.SetPlayerPropRsp);
SetPlayerPropRspOuterClass.SetPlayerPropRsp.Builder proto = SetPlayerPropRspOuterClass.SetPlayerPropRsp.newBuilder();
if (retCode != 0) {
proto.setRetcode(retCode);
}
this.setData(proto.build());
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment