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
d56ca209
Commit
d56ca209
authored
Aug 07, 2022
by
Magix
Committed by
GitHub
Aug 07, 2022
Browse files
Implement working* burst/ultimate invincibility
Merge pull request #1622 from Grasscutters/ult-invincibility
parents
423b235c
6ec372e6
Changes
4
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/game/ability/AbilityManager.java
View file @
d56ca209
...
...
@@ -17,43 +17,84 @@ import emu.grasscutter.net.proto.AbilityMetaReInitOverrideMapOuterClass.AbilityM
import
emu.grasscutter.net.proto.AbilityMixinCostStaminaOuterClass.AbilityMixinCostStamina
;
import
emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry
;
import
emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction
;
import
lombok.Getter
;
public
class
AbilityManager
extends
BasePlayerManager
{
public
final
class
AbilityManager
extends
BasePlayerManager
{
HealAbilityManager
healAbilityManager
;
@Getter
private
boolean
abilityInvulnerable
=
false
;
public
AbilityManager
(
Player
player
)
{
super
(
player
);
this
.
healAbilityManager
=
new
HealAbilityManager
(
player
);
}
public
void
onAbilityInvoke
(
AbilityInvokeEntry
invoke
)
throws
Exception
{
healAbilityManager
.
healHandler
(
invoke
);
this
.
healAbilityManager
.
healHandler
(
invoke
);
//Grasscutter.getLogger().info(invoke.getArgumentType() + " (" + invoke.getArgumentTypeValue() + "): " + Utils.bytesToHex(invoke.toByteArray()));
switch
(
invoke
.
getArgumentType
())
{
case
ABILITY_INVOKE_ARGUMENT_META_OVERRIDE_PARAM:
handleOverrideParam
(
invoke
);
break
;
case
ABILITY_INVOKE_ARGUMENT_META_REINIT_OVERRIDEMAP:
handleReinitOverrideMap
(
invoke
);
break
;
case
ABILITY_INVOKE_ARGUMENT_META_MODIFIER_CHANGE:
handleModifierChange
(
invoke
);
break
;
case
ABILITY_INVOKE_ARGUMENT_MIXIN_COST_STAMINA:
handleMixinCostStamina
(
invoke
);
break
;
case
ABILITY_INVOKE_ARGUMENT_ACTION_GENERATE_ELEM_BALL:
handleGenerateElemBall
(
invoke
);
break
;
default
:
break
;
case
ABILITY_INVOKE_ARGUMENT_META_OVERRIDE_PARAM
->
this
.
handleOverrideParam
(
invoke
);
case
ABILITY_INVOKE_ARGUMENT_META_REINIT_OVERRIDEMAP
->
this
.
handleReinitOverrideMap
(
invoke
);
case
ABILITY_INVOKE_ARGUMENT_META_MODIFIER_CHANGE
->
this
.
handleModifierChange
(
invoke
);
case
ABILITY_INVOKE_ARGUMENT_MIXIN_COST_STAMINA
->
this
.
handleMixinCostStamina
(
invoke
);
case
ABILITY_INVOKE_ARGUMENT_ACTION_GENERATE_ELEM_BALL
->
this
.
handleGenerateElemBall
(
invoke
);
default
->
{}
}
}
/**
* Invoked when a player starts a skill.
* @param player The player who started the skill.
* @param skillId The skill ID.
* @param casterId The caster ID.
*/
public
void
onSkillStart
(
Player
player
,
int
skillId
,
int
casterId
)
{
// Check if the player matches this player.
if
(
player
.
getUid
()
!=
this
.
player
.
getUid
())
{
return
;
}
// Check if the caster matches the player.
if
(
player
.
getTeamManager
().
getCurrentAvatarEntity
().
getId
()
!=
casterId
)
{
return
;
}
var
skillData
=
GameData
.
getAvatarSkillDataMap
().
get
(
skillId
);
if
(
skillData
==
null
)
{
return
;
}
// Check if the skill is an elemental burst.
if
(
skillData
.
getCostElemVal
()
<=
0
)
{
return
;
}
// Set the player as invulnerable.
this
.
abilityInvulnerable
=
true
;
}
/**
* Invoked when a player ends a skill.
* @param player The player who started the skill.
*/
public
void
onSkillEnd
(
Player
player
)
{
// Check if the player matches this player.
if
(
player
.
getUid
()
!=
this
.
player
.
getUid
())
{
return
;
}
// Check if the player is invulnerable.
if
(!
this
.
abilityInvulnerable
)
{
return
;
}
// Set the player as not invulnerable.
this
.
abilityInvulnerable
=
false
;
}
private
void
handleOverrideParam
(
AbilityInvokeEntry
invoke
)
throws
Exception
{
GameEntity
entity
=
player
.
getScene
().
getEntityById
(
invoke
.
getEntityId
());
GameEntity
entity
=
this
.
player
.
getScene
().
getEntityById
(
invoke
.
getEntityId
());
if
(
entity
==
null
)
{
return
;
...
...
@@ -65,7 +106,7 @@ public class AbilityManager extends BasePlayerManager {
}
private
void
handleReinitOverrideMap
(
AbilityInvokeEntry
invoke
)
throws
Exception
{
GameEntity
entity
=
player
.
getScene
().
getEntityById
(
invoke
.
getEntityId
());
GameEntity
entity
=
this
.
player
.
getScene
().
getEntityById
(
invoke
.
getEntityId
());
if
(
entity
==
null
)
{
return
;
...
...
@@ -80,7 +121,7 @@ public class AbilityManager extends BasePlayerManager {
private
void
handleModifierChange
(
AbilityInvokeEntry
invoke
)
throws
Exception
{
// Sanity checks
GameEntity
target
=
player
.
getScene
().
getEntityById
(
invoke
.
getEntityId
());
GameEntity
target
=
this
.
player
.
getScene
().
getEntityById
(
invoke
.
getEntityId
());
if
(
target
==
null
)
{
return
;
}
...
...
@@ -104,7 +145,7 @@ public class AbilityManager extends BasePlayerManager {
return
;
}
GameEntity
sourceEntity
=
player
.
getScene
().
getEntityById
(
data
.
getApplyEntityId
());
GameEntity
sourceEntity
=
this
.
player
.
getScene
().
getEntityById
(
data
.
getApplyEntityId
());
if
(
sourceEntity
==
null
)
{
return
;
}
...
...
@@ -117,7 +158,7 @@ public class AbilityManager extends BasePlayerManager {
if
(
modifier
!=
null
&&
modifier
.
getOnAdded
().
size
()
>
0
)
{
for
(
AbilityModifierAction
action
:
modifier
.
getOnAdded
())
{
invokeAction
(
action
,
target
,
sourceEntity
);
this
.
invokeAction
(
action
,
target
,
sourceEntity
);
}
}
...
...
@@ -133,7 +174,7 @@ public class AbilityManager extends BasePlayerManager {
if
(
modifier
!=
null
&&
modifier
.
getOnRemoved
().
size
()
>
0
)
{
for
(
AbilityModifierAction
action
:
modifier
.
getOnRemoved
())
{
invokeAction
(
action
,
target
,
sourceEntity
);
this
.
invokeAction
(
action
,
target
,
sourceEntity
);
}
}
...
...
@@ -145,7 +186,7 @@ public class AbilityManager extends BasePlayerManager {
private
void
handleMixinCostStamina
(
AbilityInvokeEntry
invoke
)
throws
InvalidProtocolBufferException
{
AbilityMixinCostStamina
costStamina
=
AbilityMixinCostStamina
.
parseFrom
((
invoke
.
getAbilityData
()));
getPlayer
().
getStaminaManager
().
handleMixinCostStamina
(
costStamina
.
getIsSwim
());
this
.
getPlayer
().
getStaminaManager
().
handleMixinCostStamina
(
costStamina
.
getIsSwim
());
}
private
void
handleGenerateElemBall
(
AbilityInvokeEntry
invoke
)
throws
InvalidProtocolBufferException
{
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerClientAbilityInitFinishNotify.java
View file @
d56ca209
...
...
@@ -11,20 +11,23 @@ import emu.grasscutter.utils.Utils;
@Opcodes
(
PacketOpcodes
.
ClientAbilityInitFinishNotify
)
public
class
HandlerClientAbilityInitFinishNotify
extends
PacketHandler
{
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
ClientAbilityInitFinishNotify
notif
=
ClientAbilityInitFinishNotify
.
parseFrom
(
payload
);
Player
player
=
session
.
getPlayer
();
// Call skill end in the player's ability manager.
player
.
getAbilityManager
().
onSkillEnd
(
player
);
for
(
AbilityInvokeEntry
entry
:
notif
.
getInvokesList
())
{
player
.
getAbilityManager
().
onAbilityInvoke
(
entry
);
player
.
getClientAbilityInitFinishHandler
().
addEntry
(
entry
.
getForwardType
(),
entry
);
}
if
(
notif
.
getInvokesList
().
size
()
>
0
)
{
session
.
getPlayer
().
getClientAbilityInitFinishHandler
().
update
(
session
.
getPlayer
());
}
}
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java
View file @
d56ca209
...
...
@@ -6,7 +6,6 @@ import emu.grasscutter.game.player.Player;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.AttackResultOuterClass
;
import
emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult
;
import
emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify
;
import
emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry
;
...
...
@@ -18,7 +17,6 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.net.proto.PlayerDieTypeOuterClass
;
import
emu.grasscutter.server.event.entity.EntityMoveEvent
;
import
emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify
;
import
emu.grasscutter.utils.Position
;
...
...
@@ -35,23 +33,29 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
CombatInvocationsNotify
notif
=
CombatInvocationsNotify
.
parseFrom
(
payload
);
for
(
CombatInvokeEntry
entry
:
notif
.
getInvokeListList
())
{
// Handle combat invoke
switch
(
entry
.
getArgumentType
())
{
case
COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT
:
EvtBeingHitInfo
hitInfo
=
EvtBeingHitInfo
.
parseFrom
(
entry
.
getCombatData
());
AttackResult
attackResult
=
hitInfo
.
getAttackResult
();
Player
player
=
session
.
getPlayer
();
switch
(
entry
.
getArgumentType
())
{
case
COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT
->
{
EvtBeingHitInfo
hitInfo
=
EvtBeingHitInfo
.
parseFrom
(
entry
.
getCombatData
());
AttackResult
attackResult
=
hitInfo
.
getAttackResult
();
Player
player
=
session
.
getPlayer
();
// Handle damage
player
.
getAttackResults
().
add
(
attackResult
);
player
.
getEnergyManager
().
handleAttackHit
(
hitInfo
);
break
;
case
COMBAT_TYPE_ARGUMENT_ENTITY_MOVE:
// Handle movement
EntityMoveInfo
moveInfo
=
EntityMoveInfo
.
parseFrom
(
entry
.
getCombatData
());
GameEntity
entity
=
session
.
getPlayer
().
getScene
().
getEntityById
(
moveInfo
.
getEntityId
());
if
(
entity
!=
null
)
{
// Move player
MotionInfo
motionInfo
=
moveInfo
.
getMotionInfo
();
// Check if the player is invulnerable.
if
(
attackResult
.
getAttackerId
()
!=
player
.
getTeamManager
().
getCurrentAvatarEntity
().
getId
()
&&
player
.
getAbilityManager
().
isAbilityInvulnerable
()
)
break
;
// Handle damage
player
.
getAttackResults
().
add
(
attackResult
);
player
.
getEnergyManager
().
handleAttackHit
(
hitInfo
);
}
case
COMBAT_TYPE_ARGUMENT_ENTITY_MOVE
->
{
// Handle movement
EntityMoveInfo
moveInfo
=
EntityMoveInfo
.
parseFrom
(
entry
.
getCombatData
());
GameEntity
entity
=
session
.
getPlayer
().
getScene
().
getEntityById
(
moveInfo
.
getEntityId
());
if
(
entity
!=
null
)
{
// Move player
MotionInfo
motionInfo
=
moveInfo
.
getMotionInfo
();
MotionState
motionState
=
motionInfo
.
getState
();
// Call entity move event.
...
...
@@ -60,48 +64,47 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
new
Position
(
motionInfo
.
getRot
()),
motionState
);
event
.
call
();
entity
.
move
(
event
.
getPosition
(),
event
.
getRotation
());
entity
.
setLastMoveSceneTimeMs
(
moveInfo
.
getSceneTime
());
entity
.
setLastMoveReliableSeq
(
moveInfo
.
getReliableSeq
());
entity
.
setMotionState
(
motionState
);
entity
.
move
(
event
.
getPosition
(),
event
.
getRotation
());
entity
.
setLastMoveSceneTimeMs
(
moveInfo
.
getSceneTime
());
entity
.
setLastMoveReliableSeq
(
moveInfo
.
getReliableSeq
());
entity
.
setMotionState
(
motionState
);
session
.
getPlayer
().
getStaminaManager
().
handleCombatInvocationsNotify
(
session
,
moveInfo
,
entity
);
session
.
getPlayer
().
getStaminaManager
().
handleCombatInvocationsNotify
(
session
,
moveInfo
,
entity
);
// TODO: handle MOTION_FIGHT landing which has a different damage factor
// Also, for plunge attacks, LAND_SPEED is always -30 and is not useful.
// May need the height when starting plunge attack.
// TODO: handle MOTION_FIGHT landing which has a different damage factor
// Also, for plunge attacks, LAND_SPEED is always -30 and is not useful.
// May need the height when starting plunge attack.
// MOTION_LAND_SPEED and MOTION_FALL_ON_GROUND arrive in different packets.
// Cache land speed for later use.
if
(
motionState
==
MotionState
.
MOTION_STATE_LAND_SPEED
)
{
cachedLandingSpeed
=
motionInfo
.
getSpeed
().
getY
();
cachedLandingTimeMillisecond
=
System
.
currentTimeMillis
();
monitorLandingEvent
=
true
;
}
if
(
monitorLandingEvent
)
{
if
(
motionState
==
MotionState
.
MOTION_STATE_FALL_ON_GROUND
)
{
monitorLandingEvent
=
false
;
handleFallOnGround
(
session
,
entity
,
motionState
);
}
}
// MOTION_LAND_SPEED and MOTION_FALL_ON_GROUND arrive in different packets.
// Cache land speed for later use.
if
(
motionState
==
MotionState
.
MOTION_STATE_LAND_SPEED
)
{
cachedLandingSpeed
=
motionInfo
.
getSpeed
().
getY
();
cachedLandingTimeMillisecond
=
System
.
currentTimeMillis
();
monitorLandingEvent
=
true
;
}
if
(
monitorLandingEvent
)
{
if
(
motionState
==
MotionState
.
MOTION_STATE_FALL_ON_GROUND
)
{
monitorLandingEvent
=
false
;
handleFallOnGround
(
session
,
entity
,
motionState
);
}
}
// MOTION_STATE_NOTIFY = Dont send to other players
if
(
motionState
==
MotionState
.
MOTION_STATE_NOTIFY
)
{
continue
;
}
}
break
;
case
COMBAT_TYPE_ARGUMENT_ANIMATOR_PARAMETER_CHANGED:
EvtAnimatorParameterInfo
paramInfo
=
EvtAnimatorParameterInfo
.
parseFrom
(
entry
.
getCombatData
());
if
(
paramInfo
.
getIsServerCache
())
{
paramInfo
=
paramInfo
.
toBuilder
().
setIsServerCache
(
false
).
build
();
entry
=
entry
.
toBuilder
().
setCombatData
(
paramInfo
.
toByteString
()).
build
();
}
break
;
default
:
break
;
}
// MOTION_STATE_NOTIFY = Dont send to other players
if
(
motionState
==
MotionState
.
MOTION_STATE_NOTIFY
)
{
continue
;
}
}
}
case
COMBAT_TYPE_ARGUMENT_ANIMATOR_PARAMETER_CHANGED
->
{
EvtAnimatorParameterInfo
paramInfo
=
EvtAnimatorParameterInfo
.
parseFrom
(
entry
.
getCombatData
());
if
(
paramInfo
.
getIsServerCache
())
{
paramInfo
=
paramInfo
.
toBuilder
().
setIsServerCache
(
false
).
build
();
entry
=
entry
.
toBuilder
().
setCombatData
(
paramInfo
.
toByteString
()).
build
();
}
}
default
->
{
}
}
session
.
getPlayer
().
getCombatInvokeHandler
().
addEntry
(
entry
.
getForwardType
(),
entry
);
}
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtDoSkillSuccNotify.java
View file @
d56ca209
...
...
@@ -12,10 +12,16 @@ public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
EvtDoSkillSuccNotify
notify
=
EvtDoSkillSuccNotify
.
parseFrom
(
payload
);
var
player
=
session
.
getPlayer
();
int
skillId
=
notify
.
getSkillId
();
int
casterId
=
notify
.
getCasterId
();
session
.
getPlayer
().
getStaminaManager
().
handleEvtDoSkillSuccNotify
(
session
,
skillId
,
casterId
);
session
.
getPlayer
().
getEnergyManager
().
handleEvtDoSkillSuccNotify
(
session
,
skillId
,
casterId
);
// Call skill perform in the player's ability manager.
player
.
getAbilityManager
().
onSkillStart
(
session
.
getPlayer
(),
skillId
,
casterId
);
// Handle skill notify in other managers.
player
.
getStaminaManager
().
handleEvtDoSkillSuccNotify
(
session
,
skillId
,
casterId
);
player
.
getEnergyManager
().
handleEvtDoSkillSuccNotify
(
session
,
skillId
,
casterId
);
}
}
}
\ No newline at end of file
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