mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-22 23:06:00 +00:00
SetPlayerPropReq Handler and player.setProperty() sanity check.
This commit is contained in:
parent
37c2ee5e2c
commit
5c275c2e3c
@ -29,19 +29,16 @@ import emu.grasscutter.game.managers.MapMarkManager.*;
|
||||
import emu.grasscutter.game.world.Scene;
|
||||
import emu.grasscutter.game.world.World;
|
||||
import emu.grasscutter.net.packet.BasePacket;
|
||||
import emu.grasscutter.net.proto.*;
|
||||
import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry;
|
||||
import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult;
|
||||
import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
|
||||
import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType;
|
||||
import emu.grasscutter.net.proto.MpSettingTypeOuterClass.MpSettingType;
|
||||
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.PlayerWorldLocationInfoOuterClass;
|
||||
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.SocialShowAvatarInfoOuterClass;
|
||||
import emu.grasscutter.server.event.player.PlayerJoinEvent;
|
||||
import emu.grasscutter.server.event.player.PlayerQuitEvent;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
@ -59,6 +56,9 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
@Entity(value = "players", useDiscriminator = false)
|
||||
public class Player {
|
||||
|
||||
@Transient private static int GlobalMaximumSpringVolume = 8500000;
|
||||
@Transient private static int GlobalMaximumStamina = 24000;
|
||||
|
||||
@Id private int id;
|
||||
@Indexed(options = @IndexOptions(unique = true)) private String accountId;
|
||||
|
||||
@ -395,12 +395,14 @@ public class Player {
|
||||
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() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
public void setProperty(PlayerProperty prop, int value) {
|
||||
getProperties().put(prop.getId(), value);
|
||||
public boolean setProperty(PlayerProperty prop, int value) {
|
||||
return setPropertyWithSanityCheck(prop, value);
|
||||
}
|
||||
|
||||
public int getProperty(PlayerProperty prop) {
|
||||
@ -1107,4 +1109,102 @@ public class Player {
|
||||
public void setMessageHandler(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,65 +6,67 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
public enum PlayerProperty {
|
||||
PROP_EXP (1001),
|
||||
PROP_BREAK_LEVEL (1002),
|
||||
PROP_SATIATION_VAL (1003),
|
||||
PROP_SATIATION_PENALTY_TIME (1004),
|
||||
PROP_LEVEL (4001),
|
||||
PROP_LAST_CHANGE_AVATAR_TIME (10001),
|
||||
PROP_MAX_SPRING_VOLUME (10002),
|
||||
PROP_CUR_SPRING_VOLUME (10003),
|
||||
PROP_IS_SPRING_AUTO_USE (10004),
|
||||
PROP_SPRING_AUTO_USE_PERCENT (10005),
|
||||
PROP_IS_FLYABLE (10006),
|
||||
PROP_IS_WEATHER_LOCKED (10007),
|
||||
PROP_IS_GAME_TIME_LOCKED (10008),
|
||||
PROP_IS_TRANSFERABLE (10009),
|
||||
PROP_MAX_STAMINA (10010),
|
||||
PROP_CUR_PERSIST_STAMINA (10011),
|
||||
PROP_CUR_TEMPORARY_STAMINA (10012),
|
||||
PROP_PLAYER_LEVEL (10013),
|
||||
PROP_PLAYER_EXP (10014),
|
||||
PROP_PLAYER_HCOIN (10015), // Primogem
|
||||
PROP_PLAYER_SCOIN (10016), // Mora
|
||||
PROP_PLAYER_MP_SETTING_TYPE (10017),
|
||||
PROP_IS_MP_MODE_AVAILABLE (10018),
|
||||
PROP_PLAYER_WORLD_LEVEL (10019),
|
||||
PROP_PLAYER_RESIN (10020),
|
||||
PROP_PLAYER_WAIT_SUB_HCOIN (10022),
|
||||
PROP_PLAYER_WAIT_SUB_SCOIN (10023),
|
||||
PROP_IS_ONLY_MP_WITH_PS_PLAYER (10024),
|
||||
PROP_PLAYER_MCOIN (10025), // Genesis Crystal
|
||||
PROP_PLAYER_WAIT_SUB_MCOIN (10026),
|
||||
PROP_PLAYER_LEGENDARY_KEY (10027),
|
||||
PROP_IS_HAS_FIRST_SHARE (10028),
|
||||
PROP_PLAYER_FORGE_POINT (10029),
|
||||
PROP_CUR_CLIMATE_METER (10035),
|
||||
PROP_CUR_CLIMATE_TYPE (10036),
|
||||
PROP_CUR_CLIMATE_AREA_ID (10037),
|
||||
PROP_CUR_CLIMATE_AREA_CLIMATE_TYPE (10038),
|
||||
PROP_PLAYER_WORLD_LEVEL_LIMIT (10039),
|
||||
PROP_PLAYER_WORLD_LEVEL_ADJUST_CD (10040),
|
||||
PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM (10041),
|
||||
PROP_PLAYER_HOME_COIN (10042),
|
||||
PROP_PLAYER_WAIT_SUB_HOME_COIN (10043);
|
||||
|
||||
private final int id;
|
||||
private static final Int2ObjectMap<PlayerProperty> map = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
static {
|
||||
Stream.of(values()).forEach(e -> map.put(e.getId(), e));
|
||||
}
|
||||
|
||||
private PlayerProperty(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
PROP_EXP (1001),
|
||||
PROP_BREAK_LEVEL (1002),
|
||||
PROP_SATIATION_VAL (1003),
|
||||
PROP_SATIATION_PENALTY_TIME (1004),
|
||||
PROP_LEVEL (4001),
|
||||
PROP_LAST_CHANGE_AVATAR_TIME (10001),
|
||||
PROP_MAX_SPRING_VOLUME (10002), // Maximum volume of the Statue of the Seven for the player [0, 8500000]
|
||||
PROP_CUR_SPRING_VOLUME (10003), // Current volume of the Statue of the Seven [0, PROP_MAX_SPRING_VOLUME]
|
||||
PROP_IS_SPRING_AUTO_USE (10004), // Auto HP recovery when approaching the Statue of the Seven [0, 1]
|
||||
PROP_SPRING_AUTO_USE_PERCENT (10005), // Auto HP recovery percentage [0, 100]
|
||||
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_GAME_TIME_LOCKED (10008),
|
||||
PROP_IS_TRANSFERABLE (10009),
|
||||
PROP_MAX_STAMINA (10010), // Maximum stamina of the player (0 - 24000)
|
||||
PROP_CUR_PERSIST_STAMINA (10011), // Used stamina of the player (0 - PROP_MAX_STAMINA)
|
||||
PROP_CUR_TEMPORARY_STAMINA (10012),
|
||||
PROP_PLAYER_LEVEL (10013),
|
||||
PROP_PLAYER_EXP (10014),
|
||||
PROP_PLAYER_HCOIN (10015), // Primogem (-inf, +inf)
|
||||
// It is known that Mihoyo will make Primogem negative in the cases that a player spends
|
||||
// his gems and then got a money refund, so negative is allowed.
|
||||
PROP_PLAYER_SCOIN (10016), // Mora [0, +inf)
|
||||
PROP_PLAYER_MP_SETTING_TYPE (10017), // Do you allow other players to join your game? [0=no 1=direct 2=approval]
|
||||
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_SCOIN (10023),
|
||||
PROP_IS_ONLY_MP_WITH_PS_PLAYER (10024), // Is only MP with PlayStation players? [0, 1]
|
||||
PROP_PLAYER_MCOIN (10025), // Genesis Crystal (-inf, +inf) see 10015
|
||||
PROP_PLAYER_WAIT_SUB_MCOIN (10026),
|
||||
PROP_PLAYER_LEGENDARY_KEY (10027),
|
||||
PROP_IS_HAS_FIRST_SHARE (10028),
|
||||
PROP_PLAYER_FORGE_POINT (10029),
|
||||
PROP_CUR_CLIMATE_METER (10035),
|
||||
PROP_CUR_CLIMATE_TYPE (10036),
|
||||
PROP_CUR_CLIMATE_AREA_ID (10037),
|
||||
PROP_CUR_CLIMATE_AREA_CLIMATE_TYPE (10038),
|
||||
PROP_PLAYER_WORLD_LEVEL_LIMIT (10039),
|
||||
PROP_PLAYER_WORLD_LEVEL_ADJUST_CD (10040),
|
||||
PROP_PLAYER_LEGENDARY_DAILY_TASK_NUM (10041),
|
||||
PROP_PLAYER_HOME_COIN (10042), // Realm currency [0, +inf)
|
||||
PROP_PLAYER_WAIT_SUB_HOME_COIN (10043);
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static PlayerProperty getPropById(int value) {
|
||||
return map.getOrDefault(value, null);
|
||||
}
|
||||
private final int id;
|
||||
private static final Int2ObjectMap<PlayerProperty> map = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
static {
|
||||
Stream.of(values()).forEach(e -> map.put(e.getId(), e));
|
||||
}
|
||||
|
||||
PlayerProperty(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static PlayerProperty getPropById(int value) {
|
||||
return map.getOrDefault(value, null);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user