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
ff0e1c64
Commit
ff0e1c64
authored
May 07, 2022
by
Akka
Committed by
GitHub
May 07, 2022
Browse files
Merge pull request #3 from Akka0/development
Development
parents
17242a24
c2d2a37f
Changes
17
Show whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java
View file @
ff0e1c64
...
...
@@ -99,6 +99,7 @@ public class DungeonManager {
// clean temp team if it has
player
.
getTeamManager
().
cleanTemporaryTeam
();
player
.
getTowerManager
().
clearEntry
();
// Transfer player back to world
player
.
getWorld
().
transferPlayerToScene
(
player
,
prevScene
,
prevPos
);
player
.
sendPacket
(
new
BasePacket
(
PacketOpcodes
.
PlayerQuitDungeonRsp
));
...
...
src/main/java/emu/grasscutter/game/entity/EntityAvatar.java
View file @
ff0e1c64
...
...
@@ -105,6 +105,11 @@ public class EntityAvatar extends GameEntity {
this
.
killedBy
=
killerId
;
}
public
void
onDeath
(
PlayerDieType
dieType
,
int
killerId
)
{
this
.
killedType
=
dieType
;
this
.
killedBy
=
killerId
;
}
public
SceneAvatarInfo
getSceneAvatarInfo
()
{
SceneAvatarInfo
.
Builder
avatarInfo
=
SceneAvatarInfo
.
newBuilder
()
.
setUid
(
this
.
getPlayer
().
getUid
())
...
...
src/main/java/emu/grasscutter/game/managers/MotionManager/MotionManager.java
deleted
100644 → 0
View file @
17242a24
package
emu.grasscutter.game.managers.MotionManager
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.entity.GameEntity
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.net.proto.EntityMoveInfoOuterClass
;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.net.proto.VectorOuterClass
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify
;
import
emu.grasscutter.server.packet.send.PacketPlayerPropNotify
;
import
emu.grasscutter.utils.Position
;
import
java.util.ArrayList
;
import
java.lang.Math
;
public
class
MotionManager
{
private
enum
Consumption
{
None
(
0
),
// consumers
CLIMB_START
(-
500
),
CLIMBING
(-
150
),
CLIMB_JUMP
(-
2500
),
DASH
(-
1800
),
SPRINT
(-
360
),
FLY
(-
60
),
SWIM_DASH_START
(-
200
),
SWIM_DASH
(-
200
),
SWIMMING
(-
80
),
// restorers
STANDBY
(
500
),
RUN
(
500
),
WALK
(
500
),
STANDBY_MOVE
(
500
);
public
final
int
amount
;
Consumption
(
int
amount
)
{
this
.
amount
=
amount
;
}
}
private
EntityMoveInfoOuterClass
.
EntityMoveInfo
moveInfo
;
private
MotionState
previousState
=
MotionState
.
MOTION_STANDBY
;
private
ArrayList
<
Position
>
previousCoordinates
=
new
ArrayList
<>();
private
final
Player
player
;
private
float
landSpeed
=
0
;
public
MotionManager
(
Player
player
)
{
previousCoordinates
.
add
(
new
Position
(
0
,
0
,
0
));
this
.
player
=
player
;
}
public
void
handle
(
GameSession
session
,
GameEntity
entity
,
EntityMoveInfoOuterClass
.
EntityMoveInfo
moveInfo
)
{
MotionState
state
=
moveInfo
.
getMotionInfo
().
getState
();
setMoveInfo
(
moveInfo
);
if
(
state
==
MotionState
.
MOTION_LAND_SPEED
)
{
setLandSpeed
(
moveInfo
.
getMotionInfo
().
getSpeed
().
getY
());
}
if
(
state
==
MotionState
.
MOTION_FALL_ON_GROUND
)
{
handleFallOnGround
(
session
,
entity
);
}
}
public
void
tick
()
{
if
(
Grasscutter
.
getConfig
().
OpenStamina
){
EntityMoveInfoOuterClass
.
EntityMoveInfo
mInfo
=
moveInfo
;
if
(
mInfo
==
null
)
{
return
;
}
MotionState
state
=
moveInfo
.
getMotionInfo
().
getState
();
Consumption
consumption
=
Consumption
.
None
;
boolean
isMoving
=
false
;
VectorOuterClass
.
Vector
posVector
=
moveInfo
.
getMotionInfo
().
getPos
();
Position
currentCoordinates
=
new
Position
(
posVector
.
getX
(),
posVector
.
getY
(),
posVector
.
getZ
());
float
diffX
=
currentCoordinates
.
getX
()
-
previousCoordinates
.
get
(
0
).
getX
();
float
diffY
=
currentCoordinates
.
getY
()
-
previousCoordinates
.
get
(
0
).
getY
();
float
diffZ
=
currentCoordinates
.
getZ
()
-
previousCoordinates
.
get
(
0
).
getZ
();
if
(
Math
.
abs
(
diffX
)
>
0.3
||
Math
.
abs
(
diffY
)
>
0.3
||
Math
.
abs
(
diffZ
)
>
0.3
)
{
isMoving
=
true
;
}
if
(
isMoving
)
{
// TODO: refactor these conditions.
// CLIMB
if
(
state
==
MotionState
.
MOTION_CLIMB
)
{
if
(
previousState
!=
MotionState
.
MOTION_CLIMB
&&
previousState
!=
MotionState
.
MOTION_CLIMB_JUMP
)
{
consumption
=
Consumption
.
CLIMB_START
;
}
else
{
consumption
=
Consumption
.
CLIMBING
;
}
}
// JUMP
if
(
state
==
MotionState
.
MOTION_CLIMB_JUMP
)
{
if
(
previousState
!=
MotionState
.
MOTION_CLIMB_JUMP
)
{
consumption
=
Consumption
.
CLIMB_JUMP
;
}
}
if
(
state
==
MotionState
.
MOTION_JUMP
)
{
if
(
previousState
==
MotionState
.
MOTION_CLIMB
)
{
consumption
=
Consumption
.
CLIMB_JUMP
;
}
}
// SWIM
if
(
state
==
MotionState
.
MOTION_SWIM_MOVE
)
{
consumption
=
Consumption
.
SWIMMING
;
}
if
(
state
==
MotionState
.
MOTION_SWIM_DASH
)
{
if
(
previousState
!=
MotionState
.
MOTION_SWIM_DASH
)
{
consumption
=
Consumption
.
SWIM_DASH_START
;
}
else
{
consumption
=
Consumption
.
SWIM_DASH
;
}
}
// DASH
if
(
state
==
MotionState
.
MOTION_DASH
)
{
if
(
previousState
==
MotionState
.
MOTION_DASH
)
{
consumption
=
Consumption
.
SPRINT
;
}
else
{
consumption
=
Consumption
.
DASH
;
}
}
// RUN and WALK
if
(
state
==
MotionState
.
MOTION_RUN
)
{
consumption
=
Consumption
.
RUN
;
}
if
(
state
==
MotionState
.
MOTION_WALK
)
{
consumption
=
Consumption
.
WALK
;
}
// FLY
if
(
state
==
MotionState
.
MOTION_FLY
)
{
consumption
=
Consumption
.
FLY
;
}
}
// STAND
if
(
state
==
MotionState
.
MOTION_STANDBY
)
{
consumption
=
Consumption
.
STANDBY
;
}
if
(
state
==
MotionState
.
MOTION_STANDBY_MOVE
)
{
consumption
=
Consumption
.
STANDBY_MOVE
;
}
GameSession
session
=
player
.
getSession
();
updateStamina
(
session
,
consumption
.
amount
);
session
.
send
(
new
PacketPlayerPropNotify
(
session
.
getPlayer
(),
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
));
Grasscutter
.
getLogger
().
debug
(
session
.
getPlayer
().
getProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
)
+
" "
+
state
+
" "
+
isMoving
+
" "
+
consumption
+
" "
+
consumption
.
amount
);
previousState
=
state
;
previousCoordinates
.
add
(
currentCoordinates
);
if
(
previousCoordinates
.
size
()
>
3
)
{
previousCoordinates
.
remove
(
0
);
}
}
}
public
void
updateStamina
(
GameSession
session
,
int
amount
)
{
if
(
amount
==
0
)
{
return
;
}
int
currentStamina
=
session
.
getPlayer
().
getProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
int
playerMaxStamina
=
session
.
getPlayer
().
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
);
int
newStamina
=
currentStamina
+
amount
;
if
(
newStamina
<
0
)
{
newStamina
=
0
;
}
if
(
newStamina
>
playerMaxStamina
)
{
newStamina
=
playerMaxStamina
;
}
session
.
getPlayer
().
setProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
,
newStamina
);
}
public
void
setMoveInfo
(
EntityMoveInfoOuterClass
.
EntityMoveInfo
moveInfo
)
{
this
.
moveInfo
=
moveInfo
;
}
public
EntityMoveInfoOuterClass
.
EntityMoveInfo
getMoveInfo
()
{
return
moveInfo
;
}
public
void
handleFallOnGround
(
GameSession
session
,
GameEntity
entity
)
{
float
currentHP
=
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
);
float
maxHP
=
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
);
float
damage
=
0
;
Grasscutter
.
getLogger
().
debug
(
"LandSpeed: "
+
landSpeed
);
if
(
landSpeed
<
-
23.5
)
{
damage
=
(
float
)(
maxHP
*
0.33
);
}
if
(
landSpeed
<
-
25
)
{
damage
=
(
float
)(
maxHP
*
0.5
);
}
if
(
landSpeed
<
-
26.5
)
{
damage
=
(
float
)(
maxHP
*
0.66
);
}
if
(
landSpeed
<
-
28
)
{
damage
=
(
maxHP
*
1
);
}
float
newHP
=
currentHP
-
damage
;
if
(
newHP
<
0
)
{
newHP
=
0
;
}
Grasscutter
.
getLogger
().
debug
(
"Max: "
+
maxHP
+
"\tCurr: "
+
currentHP
+
"\tDamage: "
+
damage
+
"\tnewHP: "
+
newHP
);
entity
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
newHP
);
entity
.
getWorld
().
broadcastPacket
(
new
PacketEntityFightPropUpdateNotify
(
entity
,
FightProperty
.
FIGHT_PROP_CUR_HP
));
if
(
newHP
==
0
)
{
entity
.
getWorld
().
broadcastPacket
(
new
PacketLifeStateChangeNotify
(
0
,
entity
,
LifeState
.
LIFE_DEAD
));
session
.
getPlayer
().
getScene
().
removeEntity
(
entity
);
entity
.
onDeath
(
0
);
}
}
public
void
setLandSpeed
(
float
landSpeed
)
{
this
.
landSpeed
=
landSpeed
;
}
}
src/main/java/emu/grasscutter/game/managers/MovementManager/MovementManager.java
0 → 100644
View file @
ff0e1c64
package
emu.grasscutter.game.managers.MovementManager
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.entity.EntityAvatar
;
import
emu.grasscutter.game.entity.GameEntity
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.net.proto.EntityMoveInfoOuterClass
;
import
emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo
;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType
;
import
emu.grasscutter.net.proto.VectorOuterClass
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.*
;
import
emu.grasscutter.utils.Position
;
import
org.jetbrains.annotations.NotNull
;
import
java.lang.Math
;
import
java.util.*
;
public
class
MovementManager
{
public
HashMap
<
String
,
HashSet
<
MotionState
>>
MotionStatesCategorized
=
new
HashMap
<>();
private
enum
Consumption
{
None
(
0
),
// consume
CLIMB_START
(-
500
),
CLIMBING
(-
150
),
CLIMB_JUMP
(-
2500
),
DASH
(-
1800
),
SPRINT
(-
360
),
FLY
(-
60
),
SWIM_DASH_START
(-
200
),
SWIM_DASH
(-
200
),
SWIMMING
(-
80
),
// restore
STANDBY
(
500
),
RUN
(
500
),
WALK
(
500
),
STANDBY_MOVE
(
500
),
POWERED_FLY
(
500
);
public
final
int
amount
;
Consumption
(
int
amount
)
{
this
.
amount
=
amount
;
}
}
private
MotionState
previousState
=
MotionState
.
MOTION_STANDBY
;
private
MotionState
currentState
=
MotionState
.
MOTION_STANDBY
;
private
Position
previousCoordinates
=
new
Position
(
0
,
0
,
0
);
private
Position
currentCoordinates
=
new
Position
(
0
,
0
,
0
);
private
final
Player
player
;
private
float
landSpeed
=
0
;
private
Timer
movementManagerTickTimer
;
private
GameSession
cachedSession
=
null
;
private
GameEntity
cachedEntity
=
null
;
private
int
staminaRecoverDelay
=
0
;
public
MovementManager
(
Player
player
)
{
previousCoordinates
.
add
(
new
Position
(
0
,
0
,
0
));
this
.
player
=
player
;
MotionStatesCategorized
.
put
(
"SWIM"
,
new
HashSet
<>(
Arrays
.
asList
(
MotionState
.
MOTION_SWIM_MOVE
,
MotionState
.
MOTION_SWIM_IDLE
,
MotionState
.
MOTION_SWIM_DASH
,
MotionState
.
MOTION_SWIM_JUMP
)));
MotionStatesCategorized
.
put
(
"STANDBY"
,
new
HashSet
<>(
Arrays
.
asList
(
MotionState
.
MOTION_STANDBY
,
MotionState
.
MOTION_STANDBY_MOVE
,
MotionState
.
MOTION_DANGER_STANDBY
,
MotionState
.
MOTION_DANGER_STANDBY_MOVE
,
MotionState
.
MOTION_LADDER_TO_STANDBY
,
MotionState
.
MOTION_JUMP_UP_WALL_FOR_STANDBY
)));
MotionStatesCategorized
.
put
(
"CLIMB"
,
new
HashSet
<>(
Arrays
.
asList
(
MotionState
.
MOTION_CLIMB
,
MotionState
.
MOTION_CLIMB_JUMP
,
MotionState
.
MOTION_STANDBY_TO_CLIMB
,
MotionState
.
MOTION_LADDER_IDLE
,
MotionState
.
MOTION_LADDER_MOVE
,
MotionState
.
MOTION_LADDER_SLIP
,
MotionState
.
MOTION_STANDBY_TO_LADDER
)));
MotionStatesCategorized
.
put
(
"FLY"
,
new
HashSet
<>(
Arrays
.
asList
(
MotionState
.
MOTION_FLY
,
MotionState
.
MOTION_FLY_IDLE
,
MotionState
.
MOTION_FLY_SLOW
,
MotionState
.
MOTION_FLY_FAST
,
MotionState
.
MOTION_POWERED_FLY
)));
MotionStatesCategorized
.
put
(
"RUN"
,
new
HashSet
<>(
Arrays
.
asList
(
MotionState
.
MOTION_DASH
,
MotionState
.
MOTION_DANGER_DASH
,
MotionState
.
MOTION_DASH_BEFORE_SHAKE
,
MotionState
.
MOTION_RUN
,
MotionState
.
MOTION_DANGER_RUN
,
MotionState
.
MOTION_WALK
,
MotionState
.
MOTION_DANGER_WALK
)));
}
public
void
handle
(
GameSession
session
,
EntityMoveInfoOuterClass
.
EntityMoveInfo
moveInfo
,
GameEntity
entity
)
{
if
(
movementManagerTickTimer
==
null
)
{
movementManagerTickTimer
=
new
Timer
();
movementManagerTickTimer
.
scheduleAtFixedRate
(
new
MotionManagerTick
(),
0
,
200
);
}
// cache info for later use in tick
cachedSession
=
session
;
cachedEntity
=
entity
;
MotionInfo
motionInfo
=
moveInfo
.
getMotionInfo
();
moveEntity
(
entity
,
moveInfo
);
VectorOuterClass
.
Vector
posVector
=
motionInfo
.
getPos
();
Position
newPos
=
new
Position
(
posVector
.
getX
(),
posVector
.
getY
(),
posVector
.
getZ
());;
if
(
newPos
.
getX
()
!=
0
&&
newPos
.
getY
()
!=
0
&&
newPos
.
getZ
()
!=
0
)
{
currentCoordinates
=
newPos
;
}
currentState
=
motionInfo
.
getState
();
Grasscutter
.
getLogger
().
debug
(
""
+
currentState
);
handleFallOnGround
(
motionInfo
);
}
public
void
resetTimer
()
{
movementManagerTickTimer
.
cancel
();
movementManagerTickTimer
=
null
;
}
private
void
moveEntity
(
GameEntity
entity
,
EntityMoveInfoOuterClass
.
EntityMoveInfo
moveInfo
)
{
entity
.
getPosition
().
set
(
moveInfo
.
getMotionInfo
().
getPos
());
entity
.
getRotation
().
set
(
moveInfo
.
getMotionInfo
().
getRot
());
entity
.
setLastMoveSceneTimeMs
(
moveInfo
.
getSceneTime
());
entity
.
setLastMoveReliableSeq
(
moveInfo
.
getReliableSeq
());
entity
.
setMotionState
(
moveInfo
.
getMotionInfo
().
getState
());
}
private
boolean
isPlayerMoving
()
{
float
diffX
=
currentCoordinates
.
getX
()
-
previousCoordinates
.
getX
();
float
diffY
=
currentCoordinates
.
getY
()
-
previousCoordinates
.
getY
();
float
diffZ
=
currentCoordinates
.
getZ
()
-
previousCoordinates
.
getZ
();
// Grasscutter.getLogger().debug("isPlayerMoving: " + previousCoordinates + ", " + currentCoordinates + ", " + diffX + ", " + diffY + ", " + diffZ);
return
Math
.
abs
(
diffX
)
>
0.2
||
Math
.
abs
(
diffY
)
>
0.1
||
Math
.
abs
(
diffZ
)
>
0.2
;
}
private
int
getCurrentStamina
()
{
return
player
.
getProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
}
private
int
getMaximumStamina
()
{
return
player
.
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
);
}
// Returns new stamina
public
int
updateStamina
(
GameSession
session
,
int
amount
)
{
int
currentStamina
=
session
.
getPlayer
().
getProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
if
(
amount
==
0
)
{
return
currentStamina
;
}
int
playerMaxStamina
=
session
.
getPlayer
().
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
);
int
newStamina
=
currentStamina
+
amount
;
if
(
newStamina
<
0
)
{
newStamina
=
0
;
}
if
(
newStamina
>
playerMaxStamina
)
{
newStamina
=
playerMaxStamina
;
}
session
.
getPlayer
().
setProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
,
newStamina
);
return
newStamina
;
}
private
void
handleFallOnGround
(
@NotNull
MotionInfo
motionInfo
)
{
MotionState
state
=
motionInfo
.
getState
();
// land speed and fall on ground event arrive in different packets
// cache land speed
if
(
state
==
MotionState
.
MOTION_LAND_SPEED
)
{
landSpeed
=
motionInfo
.
getSpeed
().
getY
();
}
if
(
state
==
MotionState
.
MOTION_FALL_ON_GROUND
)
{
float
currentHP
=
cachedEntity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
);
float
maxHP
=
cachedEntity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
);
float
damage
=
0
;
// Grasscutter.getLogger().debug("LandSpeed: " + landSpeed);
if
(
landSpeed
<
-
23.5
)
{
damage
=
(
float
)(
maxHP
*
0.33
);
}
if
(
landSpeed
<
-
25
)
{
damage
=
(
float
)(
maxHP
*
0.5
);
}
if
(
landSpeed
<
-
26.5
)
{
damage
=
(
float
)(
maxHP
*
0.66
);
}
if
(
landSpeed
<
-
28
)
{
damage
=
(
maxHP
*
1
);
}
float
newHP
=
currentHP
-
damage
;
if
(
newHP
<
0
)
{
newHP
=
0
;
}
// Grasscutter.getLogger().debug("Max: " + maxHP + "\tCurr: " + currentHP + "\tDamage: " + damage + "\tnewHP: " + newHP);
cachedEntity
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
newHP
);
cachedEntity
.
getWorld
().
broadcastPacket
(
new
PacketEntityFightPropUpdateNotify
(
cachedEntity
,
FightProperty
.
FIGHT_PROP_CUR_HP
));
if
(
newHP
==
0
)
{
killAvatar
(
cachedSession
,
cachedEntity
,
PlayerDieType
.
PLAYER_DIE_FALL
);
}
landSpeed
=
0
;
}
}
private
void
handleDrowning
()
{
int
stamina
=
getCurrentStamina
();
if
(
stamina
<
10
)
{
boolean
isSwimming
=
MotionStatesCategorized
.
get
(
"SWIM"
).
contains
(
currentState
);
Grasscutter
.
getLogger
().
debug
(
player
.
getProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
)
+
"/"
+
player
.
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
)
+
"\t"
+
currentState
+
"\t"
+
isSwimming
);
if
(
isSwimming
&&
currentState
!=
MotionState
.
MOTION_SWIM_IDLE
)
{
killAvatar
(
cachedSession
,
cachedEntity
,
PlayerDieType
.
PLAYER_DIE_DRAWN
);
}
}
}
public
void
killAvatar
(
GameSession
session
,
GameEntity
entity
,
PlayerDieType
dieType
)
{
cachedSession
.
send
(
new
PacketAvatarLifeStateChangeNotify
(
cachedSession
.
getPlayer
().
getTeamManager
().
getCurrentAvatarEntity
().
getAvatar
(),
LifeState
.
LIFE_DEAD
,
dieType
));
cachedSession
.
send
(
new
PacketLifeStateChangeNotify
(
cachedEntity
,
LifeState
.
LIFE_DEAD
,
dieType
));
cachedEntity
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
0
);
cachedEntity
.
getWorld
().
broadcastPacket
(
new
PacketEntityFightPropUpdateNotify
(
cachedEntity
,
FightProperty
.
FIGHT_PROP_CUR_HP
));
entity
.
getWorld
().
broadcastPacket
(
new
PacketLifeStateChangeNotify
(
0
,
entity
,
LifeState
.
LIFE_DEAD
));
session
.
getPlayer
().
getScene
().
removeEntity
(
entity
);
((
EntityAvatar
)
entity
).
onDeath
(
dieType
,
0
);
}
private
class
MotionManagerTick
extends
TimerTask
{
public
void
run
()
{
if
(
Grasscutter
.
getConfig
().
OpenStamina
)
{
boolean
moving
=
isPlayerMoving
();
if
(
moving
||
(
getCurrentStamina
()
<
getMaximumStamina
()))
{
Grasscutter
.
getLogger
().
debug
(
"Player moving: "
+
moving
+
", stamina full: "
+
(
getCurrentStamina
()
>=
getMaximumStamina
())
+
", recalculate stamina"
);
Consumption
consumption
=
Consumption
.
None
;
// TODO: refactor these conditions.
if
(
MotionStatesCategorized
.
get
(
"CLIMB"
).
contains
(
currentState
))
{
if
(
currentState
==
MotionState
.
MOTION_CLIMB
)
{
// CLIMB
if
(
previousState
!=
MotionState
.
MOTION_CLIMB
&&
previousState
!=
MotionState
.
MOTION_CLIMB_JUMP
)
{
consumption
=
Consumption
.
CLIMB_START
;
}
else
{
consumption
=
Consumption
.
CLIMBING
;
}
}
if
(
currentState
==
MotionState
.
MOTION_CLIMB_JUMP
)
{
if
(
previousState
!=
MotionState
.
MOTION_CLIMB_JUMP
)
{
consumption
=
Consumption
.
CLIMB_JUMP
;
}
}
if
(
currentState
==
MotionState
.
MOTION_JUMP
)
{
if
(
previousState
==
MotionState
.
MOTION_CLIMB
)
{
consumption
=
Consumption
.
CLIMB_JUMP
;
}
}
}
else
if
(
MotionStatesCategorized
.
get
(
"SWIM"
).
contains
((
currentState
)))
{
// SWIM
if
(
currentState
==
MotionState
.
MOTION_SWIM_MOVE
)
{
consumption
=
Consumption
.
SWIMMING
;
}
if
(
currentState
==
MotionState
.
MOTION_SWIM_DASH
)
{
if
(
previousState
!=
MotionState
.
MOTION_SWIM_DASH
)
{
consumption
=
Consumption
.
SWIM_DASH_START
;
}
else
{
consumption
=
Consumption
.
SWIM_DASH
;
}
}
}
else
if
(
MotionStatesCategorized
.
get
(
"RUN"
).
contains
(
currentState
))
{
// RUN, DASH and WALK
// DASH
if
(
currentState
==
MotionState
.
MOTION_DASH
)
{
if
(
previousState
==
MotionState
.
MOTION_DASH
)
{
consumption
=
Consumption
.
SPRINT
;
}
else
{
// cost more to start dashing
consumption
=
Consumption
.
DASH
;
}
}
// RUN
if
(
currentState
==
MotionState
.
MOTION_RUN
)
{
consumption
=
Consumption
.
RUN
;
}
// WALK
if
(
currentState
==
MotionState
.
MOTION_WALK
)
{
consumption
=
Consumption
.
WALK
;
}
}
else
if
(
MotionStatesCategorized
.
get
(
"FLY"
).
contains
(
currentState
))
{
// FLY
consumption
=
Consumption
.
FLY
;
// POWERED_FLY, e.g. wind tunnel
if
(
currentState
==
MotionState
.
MOTION_POWERED_FLY
)
{
consumption
=
Consumption
.
POWERED_FLY
;
}
}
else
if
(
MotionStatesCategorized
.
get
(
"STANDBY"
).
contains
(
currentState
))
{
// STAND
if
(
currentState
==
MotionState
.
MOTION_STANDBY
)
{
consumption
=
Consumption
.
STANDBY
;
}
if
(
currentState
==
MotionState
.
MOTION_STANDBY_MOVE
)
{
consumption
=
Consumption
.
STANDBY_MOVE
;
}
}
// tick triggered
handleDrowning
();
if
(
cachedSession
!=
null
)
{
if
(
consumption
.
amount
<
0
)
{
staminaRecoverDelay
=
0
;
}
if
(
consumption
.
amount
>
0
)
{
if
(
staminaRecoverDelay
<
5
)
{
staminaRecoverDelay
++;
consumption
=
Consumption
.
None
;
}
}
int
newStamina
=
updateStamina
(
cachedSession
,
consumption
.
amount
);
cachedSession
.
send
(
new
PacketPlayerPropNotify
(
player
,
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
));
Grasscutter
.
getLogger
().
debug
(
player
.
getProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
)
+
"/"
+
player
.
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
)
+
"\t"
+
currentState
+
"\t"
+
"isMoving: "
+
isPlayerMoving
()
+
"\t"
+
consumption
+
"("
+
consumption
.
amount
+
")"
);
}
}
}
previousState
=
currentState
;
previousCoordinates
=
new
Position
(
currentCoordinates
.
getX
(),
currentCoordinates
.
getY
(),
currentCoordinates
.
getZ
());;
}
}
}
src/main/java/emu/grasscutter/game/managers/SotSManager/SotSManager.java
0 → 100644
View file @
ff0e1c64
package
emu.grasscutter.game.managers.SotSManager
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.avatar.Avatar
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.net.proto.ChangeHpReasonOuterClass
;
import
emu.grasscutter.net.proto.PropChangeReasonOuterClass
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify
;
import
java.util.List
;
// Statue of the Seven Manager
public
class
SotSManager
{
// NOTE: Spring volume balance *1 = fight prop HP *100
private
final
Player
player
;
public
SotSManager
(
Player
player
)
{
this
.
player
=
player
;
}
public
boolean
getIsAutoRecoveryEnabled
()
{
return
player
.
getProperty
(
PlayerProperty
.
PROP_IS_SPRING_AUTO_USE
)
==
1
;
}
public
void
setIsAutoRecoveryEnabled
(
boolean
enabled
)
{
player
.
setProperty
(
PlayerProperty
.
PROP_IS_SPRING_AUTO_USE
,
enabled
?
1
:
0
);
}
public
int
getAutoRecoveryPercentage
()
{
return
player
.
getProperty
(
PlayerProperty
.
PROP_SPRING_AUTO_USE_PERCENT
);
}
public
void
setAutoRecoveryPercentage
(
int
percentage
)
{
player
.
setProperty
(
PlayerProperty
.
PROP_SPRING_AUTO_USE_PERCENT
,
percentage
);
}
// autoRevive automatically revives all team members.
public
void
autoRevive
(
GameSession
session
)
{
player
.
getTeamManager
().
getActiveTeam
().
forEach
(
entity
->
{
boolean
isAlive
=
entity
.
isAlive
();
if
(!
isAlive
)
{
float
maxHP
=
entity
.
getAvatar
().
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
);
float
newHP
=
(
float
)(
maxHP
*
0.3
);
entity
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
newHP
);
entity
.
getWorld
().
broadcastPacket
(
new
PacketAvatarLifeStateChangeNotify
(
entity
.
getAvatar
()));
}
});
}
public
void
scheduleAutoRecover
(
GameSession
session
)
{
// TODO: play audio effects? possibly client side? - client automatically plays.
// delay 2.5 seconds
new
Thread
(()
->
{
try
{
Thread
.
sleep
(
2500
);
autoRecover
(
session
);
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
e
.
getMessage
());
}
}).
start
();
}
public
void
refillSpringVolume
()
{
// TODO: max spring volume depends on level of the statues in Mondstadt and Liyue.
// https://genshin-impact.fandom.com/wiki/Statue_of_The_Seven#:~:text=region%20of%20Inazuma.-,Statue%20Levels,-Upon%20first%20unlocking
player
.
setProperty
(
PlayerProperty
.
PROP_MAX_SPRING_VOLUME
,
8500000
);
long
now
=
System
.
currentTimeMillis
()
/
1000
;
long
secondsSinceLastUsed
=
now
-
player
.
getSpringLastUsed
();
float
percentageRefilled
=
(
float
)
secondsSinceLastUsed
/
15
/
100
;
// 15s = 1% max volume
int
maxVolume
=
player
.
getProperty
(
PlayerProperty
.
PROP_MAX_SPRING_VOLUME
);
int
currentVolume
=
player
.
getProperty
(
PlayerProperty
.
PROP_CUR_SPRING_VOLUME
);
if
(
currentVolume
<
maxVolume
)
{
int
volumeRefilled
=
(
int
)(
percentageRefilled
*
maxVolume
);
int
newVolume
=
currentVolume
+
volumeRefilled
;
if
(
currentVolume
+
volumeRefilled
>
maxVolume
)
{
newVolume
=
maxVolume
;
}
player
.
setProperty
(
PlayerProperty
.
PROP_CUR_SPRING_VOLUME
,
newVolume
);
}
player
.
setSpringLastUsed
(
now
);
player
.
save
();
}
// autoRecover checks player setting to see if auto recover is enabled, and refill HP to the predefined level.
public
void
autoRecover
(
GameSession
session
)
{
// TODO: In MP, respect SotS settings from the HOST.
boolean
isAutoRecoveryEnabled
=
getIsAutoRecoveryEnabled
();
int
autoRecoverPercentage
=
getAutoRecoveryPercentage
();
Grasscutter
.
getLogger
().
debug
(
"isAutoRecoveryEnabled: "
+
isAutoRecoveryEnabled
+
"\tautoRecoverPercentage: "
+
autoRecoverPercentage
);
if
(
isAutoRecoveryEnabled
)
{
player
.
getTeamManager
().
getActiveTeam
().
forEach
(
entity
->
{
float
maxHP
=
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
);
float
currentHP
=
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
);
if
(
currentHP
==
maxHP
)
{
return
;
}
float
targetHP
=
maxHP
*
autoRecoverPercentage
/
100
;
if
(
targetHP
>
currentHP
)
{
float
needHP
=
targetHP
-
currentHP
;
float
needSV
=
needHP
*
100
;
// convert HP needed to Spring Volume needed
int
sotsSVBalance
=
player
.
getProperty
(
PlayerProperty
.
PROP_CUR_SPRING_VOLUME
);
if
(
sotsSVBalance
>=
needSV
)
{
// sufficient
sotsSVBalance
-=
needSV
;
}
else
{
// insufficient balance
needSV
=
sotsSVBalance
;
sotsSVBalance
=
0
;
}
player
.
setProperty
(
PlayerProperty
.
PROP_CUR_SPRING_VOLUME
,
sotsSVBalance
);
player
.
setSpringLastUsed
(
System
.
currentTimeMillis
()
/
1000
);
float
newHP
=
currentHP
+
needSV
/
100
;
// convert SV to HP
// TODO: Figure out why client shows current HP instead of added HP.
// Say an avatar had 12000 and now has 14000, it should show "2000".
// The client always show "+14000" which is incorrect.
entity
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
newHP
);
session
.
send
(
new
PacketEntityFightPropChangeReasonNotify
(
entity
,
FightProperty
.
FIGHT_PROP_CUR_HP
,
newHP
,
List
.
of
(
3
),
PropChangeReasonOuterClass
.
PropChangeReason
.
PROP_CHANGE_STATUE_RECOVER
,
ChangeHpReasonOuterClass
.
ChangeHpReason
.
ChangeHpAddStatue
));
session
.
send
(
new
PacketEntityFightPropUpdateNotify
(
entity
,
FightProperty
.
FIGHT_PROP_CUR_HP
));
Avatar
avatar
=
entity
.
getAvatar
();
avatar
.
setCurrentHp
(
newHP
);
session
.
send
(
new
PacketAvatarFightPropUpdateNotify
(
avatar
,
FightProperty
.
FIGHT_PROP_CUR_HP
));
player
.
save
();
}
});
}
}
}
src/main/java/emu/grasscutter/game/player/Player.java
View file @
ff0e1c64
...
...
@@ -21,7 +21,8 @@ import emu.grasscutter.game.inventory.GameItem;
import
emu.grasscutter.game.inventory.Inventory
;
import
emu.grasscutter.game.mail.Mail
;
import
emu.grasscutter.game.mail.MailHandler
;
import
emu.grasscutter.game.managers.MotionManager.MotionManager
;
import
emu.grasscutter.game.managers.MovementManager.MovementManager
;
import
emu.grasscutter.game.managers.SotSManager.SotSManager
;
import
emu.grasscutter.game.props.ActionReason
;
import
emu.grasscutter.game.props.EntityType
;
import
emu.grasscutter.game.props.PlayerProperty
;
...
...
@@ -90,6 +91,8 @@ public class Player {
@Transient
private
MailHandler
mailHandler
;
@Transient
private
MessageHandler
messageHandler
;
@Transient
private
SotSManager
sotsManager
;
private
TeamManager
teamManager
;
private
TowerManager
towerManager
;
...
...
@@ -126,7 +129,9 @@ public class Player {
@Transient
private
final
InvokeHandler
<
AbilityInvokeEntry
>
clientAbilityInitFinishHandler
;
private
MapMarksManager
mapMarksManager
;
@Transient
private
MotionManager
motionManager
;
@Transient
private
MovementManager
movementManager
;
private
long
springLastUsed
;
@Deprecated
...
...
@@ -168,7 +173,8 @@ public class Player {
this
.
shopLimit
=
new
ArrayList
<>();
this
.
messageHandler
=
null
;
this
.
mapMarksManager
=
new
MapMarksManager
();
this
.
motionManager
=
new
MotionManager
(
this
);
this
.
movementManager
=
new
MovementManager
(
this
);
this
.
sotsManager
=
new
SotSManager
(
this
);
}
// On player creation
...
...
@@ -196,7 +202,8 @@ public class Player {
this
.
getRotation
().
set
(
0
,
307
,
0
);
this
.
messageHandler
=
null
;
this
.
mapMarksManager
=
new
MapMarksManager
();
this
.
motionManager
=
new
MotionManager
(
this
);
this
.
movementManager
=
new
MovementManager
(
this
);
this
.
sotsManager
=
new
SotSManager
(
this
);
}
public
int
getUid
()
{
...
...
@@ -531,6 +538,14 @@ public class Player {
}
}
public
long
getSpringLastUsed
()
{
return
springLastUsed
;
}
public
void
setSpringLastUsed
(
long
val
)
{
springLastUsed
=
val
;
}
public
SceneLoadState
getSceneLoadState
()
{
return
sceneState
;
}
...
...
@@ -983,7 +998,9 @@ public class Player {
return
mapMarksManager
;
}
public
MotionManager
getMotionManager
()
{
return
motionManager
;
}
public
MovementManager
getMovementManager
()
{
return
movementManager
;
}
public
SotSManager
getSotSManager
()
{
return
sotsManager
;
}
public
synchronized
void
onTick
()
{
// Check ping
...
...
@@ -1013,33 +1030,9 @@ public class Player {
this
.
resetSendPlayerLocTime
();
}
}
scheduleStaminaNotify
();
}
private
void
scheduleStaminaNotify
()
{
// stamina tick
EntityMoveInfoOuterClass
.
EntityMoveInfo
moveInfo
=
getMotionManager
().
getMoveInfo
();
if
(
moveInfo
==
null
)
{
return
;
}
if
(
getMotionManager
().
getMoveInfo
().
getMotionInfo
().
getState
()
==
MotionStateOuterClass
.
MotionState
.
MOTION_STANDBY
)
{
if
(
getProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
)
==
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
)
)
{
return
;
}
}
for
(
int
i
=
0
;
i
<=
1000
;
i
+=
200
)
{
Timer
timer
=
new
Timer
();
timer
.
schedule
(
new
TimerTask
()
{
@Override
public
void
run
()
{
getMotionManager
().
tick
();
}
},
i
);
}
}
public
void
resetSendPlayerLocTime
()
{
...
...
src/main/java/emu/grasscutter/game/player/TeamManager.java
View file @
ff0e1c64
...
...
@@ -18,6 +18,7 @@ import emu.grasscutter.net.packet.BasePacket;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType
;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType
;
import
emu.grasscutter.server.packet.send.PacketAvatarDieAnimationEndRsp
;
import
emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify
;
...
...
@@ -468,6 +469,15 @@ public class TeamManager {
return
;
}
PlayerDieType
dieType
=
deadAvatar
.
getKilledType
();
int
killedBy
=
deadAvatar
.
getKilledBy
();
if
(
dieType
==
PlayerDieType
.
PLAYER_DIE_DRAWN
)
{
// Died in water. Do not replace
// The official server has skipped this notify and will just respawn the team immediately after the animation.
// TODO: Perhaps find a way to get vanilla experience?
getPlayer
().
sendPacket
(
new
PacketWorldPlayerDieNotify
(
dieType
,
killedBy
));
}
else
{
// Replacement avatar
EntityAvatar
replacement
=
null
;
int
replaceIndex
=
-
1
;
...
...
@@ -483,12 +493,13 @@ public class TeamManager {
if
(
replacement
==
null
)
{
// No more living team members...
getPlayer
().
sendPacket
(
new
PacketWorldPlayerDieNotify
(
d
eadAvatar
.
getKilledType
(),
deadAvatar
.
getK
illedBy
()
));
getPlayer
().
sendPacket
(
new
PacketWorldPlayerDieNotify
(
d
ieType
,
k
illedBy
));
}
else
{
// Set index and spawn replacement member
this
.
setCurrentCharacterIndex
(
replaceIndex
);
getPlayer
().
getScene
().
addEntity
(
replacement
);
}
}
// Response packet
getPlayer
().
sendPacket
(
new
PacketAvatarDieAnimationEndRsp
(
deadAvatar
.
getId
(),
0
));
...
...
@@ -540,11 +551,13 @@ public class TeamManager {
public
void
respawnTeam
()
{
// Make sure all team members are dead
for
(
EntityAvatar
entity
:
getActiveTeam
())
{
if
(
entity
.
isAlive
())
{
return
;
}
}
// Drowning needs revive when there may be other team members still alive.
// for (EntityAvatar entity : getActiveTeam()) {
// if (entity.isAlive()) {
// return;
// }
// }
player
.
getMovementManager
().
resetTimer
();
// prevent drowning immediately after respawn
// Revive all team members
for
(
EntityAvatar
entity
:
getActiveTeam
())
{
...
...
src/main/java/emu/grasscutter/game/tower/TowerManager.java
View file @
ff0e1c64
...
...
@@ -8,18 +8,21 @@ import emu.grasscutter.game.dungeons.DungeonSettleListener;
import
emu.grasscutter.game.dungeons.TowerDungeonSettleListener
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.server.packet.send.PacketTowerCurLevelRecordChangeNotify
;
import
emu.grasscutter.server.packet.send.PacketTowerEnterLevelRsp
;
import
java.util.List
;
@Entity
public
class
TowerManager
{
@Transient
private
Player
player
;
@Transient
private
final
Player
player
;
public
TowerManager
(
Player
player
)
{
this
.
player
=
player
;
}
public
void
setPlayer
(
Player
player
)
{
this
.
player
=
player
;
}
...
...
@@ -52,6 +55,7 @@ public class TowerManager {
entryScene
=
player
.
getSceneId
();
}
player
.
getTeamManager
().
setupTemporaryTeam
(
towerTeams
);
}
...
...
src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java
View file @
ff0e1c64
package
emu.grasscutter.net.packet
;
import
java.util.Arrays
;
import
java.util.List
;
public
class
PacketOpcodes
{
// Empty
public
static
final
int
NONE
=
0
;
...
...
@@ -1566,4 +1569,6 @@ public class PacketOpcodes {
public
static
final
int
UNKNOWN_43
=
8877
;
public
static
final
int
UNKNOWN_44
=
8983
;
public
static
final
int
UNKNOWN_45
=
943
;
public
static
final
List
<
Integer
>
BANNED_PACKETS
=
Arrays
.
asList
(
PacketOpcodes
.
WindSeedClientNotify
,
PacketOpcodes
.
PlayerLuaShellNotify
);
}
src/main/java/emu/grasscutter/server/game/GameSession.java
View file @
ff0e1c64
...
...
@@ -158,6 +158,12 @@ public class GameSession extends KcpChannel {
return
;
}
// DO NOT REMOVE (unless we find a way to validate code before sending to client which I don't think we can)
// Stop WindSeedClientNotify from being sent for security purposes.
if
(
PacketOpcodes
.
BANNED_PACKETS
.
contains
(
packet
.
getOpcode
()))
{
return
;
}
// Header
if
(
packet
.
shouldBuildHeader
())
{
packet
.
buildHeader
(
this
.
getNextClientSequence
());
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java
View file @
ff0e1c64
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.game.entity.GameEntity
;
import
emu.grasscutter.game.managers.MotionManager.MotionManager
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify
;
...
...
@@ -11,9 +8,7 @@ import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
import
emu.grasscutter.net.proto.EntityMoveInfoOuterClass.EntityMoveInfo
;
import
emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.*
;
@Opcodes
(
PacketOpcodes
.
CombatInvocationsNotify
)
public
class
HandlerCombatInvocationsNotify
extends
PacketHandler
{
...
...
@@ -33,13 +28,7 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
EntityMoveInfo
moveInfo
=
EntityMoveInfo
.
parseFrom
(
entry
.
getCombatData
());
GameEntity
entity
=
session
.
getPlayer
().
getScene
().
getEntityById
(
moveInfo
.
getEntityId
());
if
(
entity
!=
null
)
{
//move
entity
.
getPosition
().
set
(
moveInfo
.
getMotionInfo
().
getPos
());
entity
.
getRotation
().
set
(
moveInfo
.
getMotionInfo
().
getRot
());
entity
.
setLastMoveSceneTimeMs
(
moveInfo
.
getSceneTime
());
entity
.
setLastMoveReliableSeq
(
moveInfo
.
getReliableSeq
());
entity
.
setMotionState
(
moveInfo
.
getMotionInfo
().
getState
());
session
.
getPlayer
().
getMotionManager
().
handle
(
session
,
entity
,
moveInfo
);
session
.
getPlayer
().
getMovementManager
().
handle
(
session
,
moveInfo
,
entity
);
}
break
;
default
:
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerEnterTransPointRegionNotify.java
View file @
ff0e1c64
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.game.managers.SotSManager.SotSManager
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
...
...
@@ -18,26 +20,12 @@ import java.util.List;
public
class
HandlerEnterTransPointRegionNotify
extends
PacketHandler
{
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
session
.
getPlayer
().
getTeamManager
().
getActiveTeam
().
forEach
(
entity
->
{
boolean
isAlive
=
entity
.
isAlive
();
if
(
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
)
!=
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
)){
Float
hp
=
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
)-
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
);
Player
player
=
session
.
getPlayer
();
SotSManager
sotsManager
=
player
.
getSotSManager
();
session
.
send
(
new
PacketEntityFightPropUpdateNotify
(
entity
,
FightProperty
.
FIGHT_PROP_MAX_HP
));
session
.
send
(
new
PacketEntityFightPropChangeReasonNotify
(
entity
,
FightProperty
.
FIGHT_PROP_CUR_HP
,
hp
,
List
.
of
(
3
),
PropChangeReason
.
PROP_CHANGE_STATUE_RECOVER
,
ChangeHpReason
.
ChangeHpAddStatue
));
entity
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
)
);
session
.
send
(
new
PacketAvatarFightPropUpdateNotify
(
entity
.
getAvatar
(),
FightProperty
.
FIGHT_PROP_CUR_HP
));
if
(!
isAlive
)
{
entity
.
getWorld
().
broadcastPacket
(
new
PacketAvatarLifeStateChangeNotify
(
entity
.
getAvatar
()));
}
}
});
sotsManager
.
refillSpringVolume
();
sotsManager
.
autoRevive
(
session
);
sotsManager
.
scheduleAutoRecover
(
session
);
// TODO: allow interaction with the SotS?
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerWorldPlayerReviveReq.java
View file @
ff0e1c64
...
...
@@ -3,7 +3,9 @@ package emu.grasscutter.server.packet.recv;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.proto.WorldPlayerDieNotifyOuterClass
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketWorldPlayerReviveRsp
;
@Opcodes
(
PacketOpcodes
.
WorldPlayerReviveReq
)
public
class
HandlerWorldPlayerReviveReq
extends
PacketHandler
{
...
...
@@ -11,6 +13,7 @@ public class HandlerWorldPlayerReviveReq extends PacketHandler {
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
session
.
getPlayer
().
getTeamManager
().
respawnTeam
();
session
.
send
(
new
PacketWorldPlayerReviveRsp
());
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketAvatarLifeStateChangeNotify.java
View file @
ff0e1c64
...
...
@@ -9,6 +9,10 @@ import emu.grasscutter.net.packet.BasePacket;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.AvatarLifeStateChangeNotifyOuterClass.AvatarLifeStateChangeNotify
;
import
emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType
;
import
emu.grasscutter.net.proto.ServerBuffOuterClass
;
import
emu.grasscutter.net.proto.ServerBuffOuterClass.ServerBuff
;
import
java.util.ArrayList
;
public
class
PacketAvatarLifeStateChangeNotify
extends
BasePacket
{
...
...
@@ -22,7 +26,7 @@ public class PacketAvatarLifeStateChangeNotify extends BasePacket {
this
.
setData
(
proto
);
}
public
PacketAvatarLifeStateChangeNotify
(
Avatar
avatar
,
int
attackerId
,
LifeState
lifeState
)
{
public
PacketAvatarLifeStateChangeNotify
(
Avatar
avatar
,
int
attackerId
,
LifeState
lifeState
)
{
super
(
PacketOpcodes
.
AvatarLifeStateChangeNotify
);
AvatarLifeStateChangeNotify
proto
=
AvatarLifeStateChangeNotify
.
newBuilder
()
...
...
@@ -33,4 +37,26 @@ public class PacketAvatarLifeStateChangeNotify extends BasePacket {
this
.
setData
(
proto
);
}
public
PacketAvatarLifeStateChangeNotify
(
Avatar
avatar
,
LifeState
lifeState
,
PlayerDieType
dieType
)
{
this
(
avatar
,
lifeState
,
null
,
""
,
dieType
);
}
public
PacketAvatarLifeStateChangeNotify
(
Avatar
avatar
,
LifeState
lifeState
,
GameEntity
sourceEntity
,
String
attackTag
,
PlayerDieType
dieType
)
{
super
(
PacketOpcodes
.
AvatarLifeStateChangeNotify
);
AvatarLifeStateChangeNotify
.
Builder
proto
=
AvatarLifeStateChangeNotify
.
newBuilder
();
proto
.
setAvatarGuid
(
avatar
.
getGuid
());
proto
.
setLifeState
(
lifeState
.
getValue
());
if
(
sourceEntity
!=
null
)
{
proto
.
setSourceEntityId
(
sourceEntity
.
getId
());
}
proto
.
setDieType
(
dieType
);
proto
.
setAttackTag
((
attackTag
));
this
.
setData
(
proto
.
build
());
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketLifeStateChangeNotify.java
View file @
ff0e1c64
package
emu.grasscutter.server.packet.send
;
import
emu.grasscutter.game.avatar.Avatar
;
import
emu.grasscutter.game.entity.GameEntity
;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.LifeStateChangeNotifyOuterClass.LifeStateChangeNotify
;
import
emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType
;
import
emu.grasscutter.net.proto.ServerBuffOuterClass.ServerBuff
;
import
java.util.ArrayList
;
public
class
PacketLifeStateChangeNotify
extends
BasePacket
{
public
PacketLifeStateChangeNotify
(
GameEntity
attacker
,
GameEntity
target
,
LifeState
lifeState
)
{
...
...
@@ -29,4 +34,26 @@ public class PacketLifeStateChangeNotify extends BasePacket {
this
.
setData
(
proto
);
}
public
PacketLifeStateChangeNotify
(
GameEntity
entity
,
LifeState
lifeState
,
PlayerDieType
dieType
)
{
this
(
entity
,
lifeState
,
null
,
""
,
dieType
);
}
public
PacketLifeStateChangeNotify
(
GameEntity
entity
,
LifeState
lifeState
,
GameEntity
sourceEntity
,
String
attackTag
,
PlayerDieType
dieType
)
{
super
(
PacketOpcodes
.
LifeStateChangeNotify
);
LifeStateChangeNotify
.
Builder
proto
=
LifeStateChangeNotify
.
newBuilder
();
proto
.
setEntityId
(
entity
.
getId
());
proto
.
setLifeState
(
lifeState
.
getValue
());
if
(
sourceEntity
!=
null
)
{
proto
.
setSourceEntityId
(
sourceEntity
.
getId
());
}
proto
.
setAttackTag
(
attackTag
);
proto
.
setDieType
(
dieType
);
this
.
setData
(
proto
.
build
());
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketTakeAchievementRewardReq.java
View file @
ff0e1c64
...
...
@@ -15,14 +15,7 @@ public class PacketTakeAchievementRewardReq extends BasePacket {
public
PacketTakeAchievementRewardReq
(
GameSession
session
)
{
super
(
PacketOpcodes
.
TakeAchievementRewardReq
);
List
<
AchievementInfo
>
a_list
=
new
ArrayList
<>();
a_list
.
add
(
AchievementInfo
.
newBuilder
().
setId
(
82044
).
setStatusValue
(
2
).
setCurrent
(
0
).
setGoal
(
1
).
build
());
a_list
.
add
(
AchievementInfo
.
newBuilder
().
setId
(
81205
).
setStatusValue
(
2
).
setCurrent
(
0
).
setGoal
(
1
).
build
());
TakeAchievementRewardReq
proto
=
TakeAchievementRewardReq
.
newBuilder
()
.
addAllAList
(
a_list
)
.
build
();
TakeAchievementRewardReq
proto
=
TakeAchievementRewardReq
.
newBuilder
().
build
();
this
.
setData
(
proto
);
}
...
...
src/main/java/emu/grasscutter/server/packet/send/PacketWorldPlayerReviveRsp.java
0 → 100644
View file @
ff0e1c64
package
emu.grasscutter.server.packet.send
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.world.World
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.WorldPlayerReviveRspOuterClass.WorldPlayerReviveRsp
;
public
class
PacketWorldPlayerReviveRsp
extends
BasePacket
{
public
PacketWorldPlayerReviveRsp
()
{
super
(
PacketOpcodes
.
WorldPlayerReviveRsp
);
WorldPlayerReviveRsp
.
Builder
proto
=
WorldPlayerReviveRsp
.
newBuilder
();
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