Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
ziqian zhang
Grasscutter
Commits
5c275c2e
Commit
5c275c2e
authored
May 04, 2022
by
gentlespoon
Committed by
Melledy
May 05, 2022
Browse files
SetPlayerPropReq Handler and player.setProperty() sanity check.
parent
37c2ee5e
Changes
4
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/game/player/Player.java
View file @
5c275c2e
...
...
@@ -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
)
{
g
etPropert
ies
().
put
(
prop
.
getId
()
,
value
);
public
boolean
setProperty
(
PlayerProperty
prop
,
int
value
)
{
return
s
etPropert
yWithSanityCheck
(
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
;
}
}
src/main/java/emu/grasscutter/game/props/PlayerProperty.java
View file @
5c275c2e
...
...
@@ -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
);
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerPropReq.java
0 → 100644
View file @
5c275c2e
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
));
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketSetPlayerPropRsp.java
0 → 100644
View file @
5c275c2e
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
());
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment