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
2531ae36
Commit
2531ae36
authored
May 11, 2022
by
gentlespoon
Committed by
Melledy
May 11, 2022
Browse files
Feature: vehicle stamina
1. Remove references. 2. Handle vehicle stamina.
parent
ba5635bf
Changes
7
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/game/managers/StaminaManager/AfterUpdateStaminaListener.java
View file @
2531ae36
...
@@ -8,5 +8,5 @@ public interface AfterUpdateStaminaListener {
...
@@ -8,5 +8,5 @@ public interface AfterUpdateStaminaListener {
* @param reason Why updating stamina.
* @param reason Why updating stamina.
* @param newStamina New Stamina value.
* @param newStamina New Stamina value.
*/
*/
void
onAfterUpdateStamina
(
String
reason
,
int
newStamina
);
void
onAfterUpdateStamina
(
String
reason
,
int
newStamina
,
boolean
isCharacterStamina
);
}
}
src/main/java/emu/grasscutter/game/managers/StaminaManager/BeforeUpdateStaminaListener.java
View file @
2531ae36
...
@@ -8,7 +8,7 @@ public interface BeforeUpdateStaminaListener {
...
@@ -8,7 +8,7 @@ public interface BeforeUpdateStaminaListener {
* @param newStamina New ABSOLUTE stamina value.
* @param newStamina New ABSOLUTE stamina value.
* @return true if you want to cancel this update, otherwise false.
* @return true if you want to cancel this update, otherwise false.
*/
*/
int
onBeforeUpdateStamina
(
String
reason
,
int
newStamina
);
int
onBeforeUpdateStamina
(
String
reason
,
int
newStamina
,
boolean
isCharacterStamina
);
/**
/**
* onBeforeUpdateStamina() will be called before StaminaManager attempt to update the player's current stamina.
* onBeforeUpdateStamina() will be called before StaminaManager attempt to update the player's current stamina.
* This gives listeners a chance to intercept this update.
* This gives listeners a chance to intercept this update.
...
@@ -16,5 +16,5 @@ public interface BeforeUpdateStaminaListener {
...
@@ -16,5 +16,5 @@ public interface BeforeUpdateStaminaListener {
* @param consumption ConsumptionType and RELATIVE stamina change amount.
* @param consumption ConsumptionType and RELATIVE stamina change amount.
* @return true if you want to cancel this update, otherwise false.
* @return true if you want to cancel this update, otherwise false.
*/
*/
Consumption
onBeforeUpdateStamina
(
String
reason
,
Consumption
consumption
);
Consumption
onBeforeUpdateStamina
(
String
reason
,
Consumption
consumption
,
boolean
isCharacterStamina
);
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/game/managers/StaminaManager/ConsumptionType.java
View file @
2531ae36
...
@@ -13,18 +13,19 @@ public enum ConsumptionType {
...
@@ -13,18 +13,19 @@ public enum ConsumptionType {
// Slow swimming is handled per movement, not per second.
// Slow swimming is handled per movement, not per second.
// Arm movement frequency depends on gender/age/height.
// Arm movement frequency depends on gender/age/height.
// TODO: Instead of cost -80 per tick, find a proper way to calculate cost.
// TODO: Instead of cost -80 per tick, find a proper way to calculate cost.
SKIFF
(-
300
),
// TODO: Get real value
SKIFF
_DASH
(-
204
),
SPRINT
(-
1800
),
SPRINT
(-
1800
),
SWIM_DASH_START
(-
20
),
SWIM_DASH_START
(-
20
00
),
SWIM_DASH
(-
204
),
// -10.2 per second, 5Hz = -204 each tick
SWIM_DASH
(-
204
),
// -10.2 per second, 5Hz = -204 each tick
SWIMMING
(-
80
),
SWIMMING
(-
80
),
TALENT_DASH
(-
300
),
// -1500 per second, 5Hz = -300 each tick
TALENT_DASH
(-
300
),
// -1500 per second, 5Hz = -300 each tick
TALENT_DASH_START
(-
1000
),
TALENT_DASH_START
(-
1000
),
// restore
// restore
POWERED_FLY
(
500
),
// TODO: Get real value
POWERED_FLY
(
500
),
POWERED_SKIFF
(
20
00
),
// TODO: Get real value
POWERED_SKIFF
(
5
00
),
RUN
(
500
),
RUN
(
500
),
SKIFF
(
500
),
STANDBY
(
500
),
STANDBY
(
500
),
WALK
(
500
);
WALK
(
500
);
...
...
src/main/java/emu/grasscutter/game/managers/StaminaManager/StaminaManager.java
View file @
2531ae36
...
@@ -14,6 +14,7 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
...
@@ -14,6 +14,7 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType
;
import
emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.net.proto.VehicleInteractTypeOuterClass.VehicleInteractType
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.*
;
import
emu.grasscutter.server.packet.send.*
;
import
emu.grasscutter.utils.Position
;
import
emu.grasscutter.utils.Position
;
...
@@ -48,7 +49,7 @@ public class StaminaManager {
...
@@ -48,7 +49,7 @@ public class StaminaManager {
)));
)));
put
(
"SKIFF"
,
new
HashSet
<>(
List
.
of
(
put
(
"SKIFF"
,
new
HashSet
<>(
List
.
of
(
MotionState
.
MOTION_SKIFF_BOARDING
,
// NOT OBSERVED even when boarding
MotionState
.
MOTION_SKIFF_BOARDING
,
// NOT OBSERVED even when boarding
MotionState
.
MOTION_SKIFF_DASH
,
//
NOT OBSERVED e
ve
n
w
hen dashing
MotionState
.
MOTION_SKIFF_DASH
,
//
sustained, obser
ve
d
w
ith waverider entity ID.
MotionState
.
MOTION_SKIFF_NORMAL
,
// sustained, OBSERVED when both normal and dashing
MotionState
.
MOTION_SKIFF_NORMAL
,
// sustained, OBSERVED when both normal and dashing
MotionState
.
MOTION_SKIFF_POWERED_DASH
// sustained, recover
MotionState
.
MOTION_SKIFF_POWERED_DASH
// sustained, recover
)));
)));
...
@@ -108,7 +109,8 @@ public class StaminaManager {
...
@@ -108,7 +109,8 @@ public class StaminaManager {
}};
}};
private
final
Logger
logger
=
Grasscutter
.
getLogger
();
private
final
Logger
logger
=
Grasscutter
.
getLogger
();
public
final
static
int
GlobalMaximumStamina
=
24000
;
public
final
static
int
GlobalCharacterMaximumStamina
=
24000
;
public
final
static
int
GlobalVehicleMaxStamina
=
24000
;
private
Position
currentCoordinates
=
new
Position
(
0
,
0
,
0
);
private
Position
currentCoordinates
=
new
Position
(
0
,
0
,
0
);
private
Position
previousCoordinates
=
new
Position
(
0
,
0
,
0
);
private
Position
previousCoordinates
=
new
Position
(
0
,
0
,
0
);
private
MotionState
currentState
=
MotionState
.
MOTION_STANDBY
;
private
MotionState
currentState
=
MotionState
.
MOTION_STANDBY
;
...
@@ -122,9 +124,10 @@ public class StaminaManager {
...
@@ -122,9 +124,10 @@ public class StaminaManager {
private
int
lastSkillId
=
0
;
private
int
lastSkillId
=
0
;
private
int
lastSkillCasterId
=
0
;
private
int
lastSkillCasterId
=
0
;
private
boolean
lastSkillFirstTick
=
true
;
private
boolean
lastSkillFirstTick
=
true
;
private
int
vehicleId
=
-
1
;
private
int
vehicleStamina
=
GlobalVehicleMaxStamina
;
private
static
final
HashSet
<
Integer
>
TalentMovements
=
new
HashSet
<>(
List
.
of
(
private
static
final
HashSet
<
Integer
>
TalentMovements
=
new
HashSet
<>(
List
.
of
(
10013
,
// Kamisato Ayaka
10013
,
10413
10413
// Mona
));
));
private
static
final
HashMap
<
Integer
,
Float
>
ClimbFoodReductionMap
=
new
HashMap
<>()
{{
private
static
final
HashMap
<
Integer
,
Float
>
ClimbFoodReductionMap
=
new
HashMap
<>()
{{
// TODO: get real food id
// TODO: get real food id
...
@@ -143,15 +146,15 @@ public class StaminaManager {
...
@@ -143,15 +146,15 @@ public class StaminaManager {
put
(
0
,
0.8f
);
// Sample food
put
(
0
,
0.8f
);
// Sample food
}};
}};
private
static
final
HashMap
<
Integer
,
Float
>
ClimbTalentReductionMap
=
new
HashMap
<>()
{{
private
static
final
HashMap
<
Integer
,
Float
>
ClimbTalentReductionMap
=
new
HashMap
<>()
{{
put
(
262301
,
0.8f
);
// Xiao
put
(
262301
,
0.8f
);
}};
}};
private
static
final
HashMap
<
Integer
,
Float
>
FlyTalentReductionMap
=
new
HashMap
<>()
{{
private
static
final
HashMap
<
Integer
,
Float
>
FlyTalentReductionMap
=
new
HashMap
<>()
{{
put
(
212301
,
0.8f
);
// Amber
put
(
212301
,
0.8f
);
put
(
222301
,
0.8f
);
// Venti
put
(
222301
,
0.8f
);
}};
}};
private
static
final
HashMap
<
Integer
,
Float
>
SwimTalentReductionMap
=
new
HashMap
<>()
{{
private
static
final
HashMap
<
Integer
,
Float
>
SwimTalentReductionMap
=
new
HashMap
<>()
{{
put
(
242301
,
0.8f
);
// Beidou
put
(
242301
,
0.8f
);
put
(
542301
,
0.8f
);
// Sangonomiya Kokomi
put
(
542301
,
0.8f
);
}};
}};
public
static
final
HashSet
<
Integer
>
BowAvatars
=
new
HashSet
<>();
public
static
final
HashSet
<
Integer
>
BowAvatars
=
new
HashSet
<>();
...
@@ -163,25 +166,15 @@ public class StaminaManager {
...
@@ -163,25 +166,15 @@ public class StaminaManager {
public
static
void
initialize
()
{
public
static
void
initialize
()
{
// Initialize skill categories
// Initialize skill categories
GameData
.
getAvatarDataMap
().
forEach
((
avatarId
,
avatarData
)
->
{
GameData
.
getAvatarDataMap
().
forEach
((
avatarId
,
avatarData
)
->
{
switch
(
avatarData
.
getWeaponType
())
{
switch
(
avatarData
.
getWeaponType
())
{
case
"WEAPON_BOW"
:
case
"WEAPON_BOW"
->
BowAvatars
.
add
(
avatarId
);
BowAvatars
.
add
(
avatarId
);
case
"WEAPON_CLAYMORE"
->
ClaymoreAvatars
.
add
(
avatarId
);
break
;
case
"WEAPON_CATALYST"
->
CatalystAvatars
.
add
(
avatarId
);
case
"WEAPON_CLAYMORE"
:
case
"WEAPON_POLE"
->
PolearmAvatars
.
add
(
avatarId
);
ClaymoreAvatars
.
add
(
avatarId
);
case
"WEAPON_SWORD_ONE_HAND"
->
SwordAvatars
.
add
(
avatarId
);
break
;
case
"WEAPON_CATALYST"
:
CatalystAvatars
.
add
(
avatarId
);
break
;
case
"WEAPON_POLE"
:
PolearmAvatars
.
add
(
avatarId
);
break
;
case
"WEAPON_SWORD_ONE_HAND"
:
SwordAvatars
.
add
(
avatarId
);
break
;
}
}
// TODO: Initialize foods etc.
});
});
// TODO: Initialize foods etc.
}
}
public
StaminaManager
(
Player
player
)
{
public
StaminaManager
(
Player
player
)
{
...
@@ -196,6 +189,22 @@ public class StaminaManager {
...
@@ -196,6 +189,22 @@ public class StaminaManager {
lastSkillCasterId
=
skillCasterId
;
lastSkillCasterId
=
skillCasterId
;
}
}
public
int
getMaxCharacterStamina
()
{
return
player
.
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
);
}
public
int
getCurrentCharacterStamina
()
{
return
player
.
getProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
}
public
int
getMaxVehicleStamina
()
{
return
GlobalVehicleMaxStamina
;
}
public
int
getCurrentVehicleStamina
()
{
return
vehicleStamina
;
}
public
boolean
registerBeforeUpdateStaminaListener
(
String
listenerName
,
BeforeUpdateStaminaListener
listener
)
{
public
boolean
registerBeforeUpdateStaminaListener
(
String
listenerName
,
BeforeUpdateStaminaListener
listener
)
{
if
(
beforeUpdateStaminaListeners
.
containsKey
(
listenerName
))
{
if
(
beforeUpdateStaminaListeners
.
containsKey
(
listenerName
))
{
return
false
;
return
false
;
...
@@ -237,14 +246,14 @@ public class StaminaManager {
...
@@ -237,14 +246,14 @@ public class StaminaManager {
return
Math
.
abs
(
diffX
)
>
0.3
||
Math
.
abs
(
diffY
)
>
0.2
||
Math
.
abs
(
diffZ
)
>
0.3
;
return
Math
.
abs
(
diffX
)
>
0.3
||
Math
.
abs
(
diffY
)
>
0.2
||
Math
.
abs
(
diffZ
)
>
0.3
;
}
}
public
int
updateStaminaRelative
(
GameSession
session
,
Consumption
consumption
,
PlayerProperty
s
tamina
Type
)
{
public
int
updateStaminaRelative
(
GameSession
session
,
Consumption
consumption
,
boolean
isCharacterS
tamina
)
{
int
currentStamina
=
player
.
getProperty
(
s
tamina
Type
);
int
currentStamina
=
isCharacterStamina
?
getCurrentCharacterStamina
()
:
getCurrentVehicleS
tamina
(
);
if
(
consumption
.
amount
==
0
)
{
if
(
consumption
.
amount
==
0
)
{
return
currentStamina
;
return
currentStamina
;
}
}
// notify will update
// notify will update
for
(
Map
.
Entry
<
String
,
BeforeUpdateStaminaListener
>
listener
:
beforeUpdateStaminaListeners
.
entrySet
())
{
for
(
Map
.
Entry
<
String
,
BeforeUpdateStaminaListener
>
listener
:
beforeUpdateStaminaListeners
.
entrySet
())
{
Consumption
overriddenConsumption
=
listener
.
getValue
().
onBeforeUpdateStamina
(
consumption
.
type
.
toString
(),
consumption
);
Consumption
overriddenConsumption
=
listener
.
getValue
().
onBeforeUpdateStamina
(
consumption
.
type
.
toString
(),
consumption
,
isCharacterStamina
);
if
((
overriddenConsumption
.
type
!=
consumption
.
type
)
&&
(
overriddenConsumption
.
amount
!=
consumption
.
amount
))
{
if
((
overriddenConsumption
.
type
!=
consumption
.
type
)
&&
(
overriddenConsumption
.
amount
!=
consumption
.
amount
))
{
logger
.
debug
(
"Stamina update relative("
+
logger
.
debug
(
"Stamina update relative("
+
consumption
.
type
.
toString
()
+
", "
+
consumption
.
amount
+
") overridden to relative("
+
consumption
.
type
.
toString
()
+
", "
+
consumption
.
amount
+
") overridden to relative("
+
...
@@ -252,24 +261,24 @@ public class StaminaManager {
...
@@ -252,24 +261,24 @@ public class StaminaManager {
return
currentStamina
;
return
currentStamina
;
}
}
}
}
int
playerM
axStamina
=
player
.
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
);
int
m
axStamina
=
isCharacterStamina
?
getMaxCharacterStamina
()
:
getMaxVehicleStamina
(
);
logger
.
trace
(
currentStamina
+
"/"
+
playerM
axStamina
+
"\t"
+
currentState
+
"\t"
+
logger
.
warn
((
isCharacterStamina
?
"C "
:
"V "
)
+
currentStamina
+
"/"
+
m
axStamina
+
"\t"
+
currentState
+
"\t"
+
(
isPlayerMoving
()
?
"moving"
:
" "
)
+
"\t("
+
consumption
.
type
+
","
+
(
isPlayerMoving
()
?
"moving"
:
" "
)
+
"\t("
+
consumption
.
type
+
","
+
consumption
.
amount
+
")"
);
consumption
.
amount
+
")"
);
int
newStamina
=
currentStamina
+
consumption
.
amount
;
int
newStamina
=
currentStamina
+
consumption
.
amount
;
if
(
newStamina
<
0
)
{
if
(
newStamina
<
0
)
{
newStamina
=
0
;
newStamina
=
0
;
}
else
if
(
newStamina
>
playerM
axStamina
)
{
}
else
if
(
newStamina
>
m
axStamina
)
{
newStamina
=
playerM
axStamina
;
newStamina
=
m
axStamina
;
}
}
return
setStamina
(
session
,
consumption
.
type
.
toString
(),
newStamina
,
s
tamina
Type
);
return
setStamina
(
session
,
consumption
.
type
.
toString
(),
newStamina
,
isCharacterS
tamina
);
}
}
public
int
updateStaminaAbsolute
(
GameSession
session
,
String
reason
,
int
newStamina
,
PlayerProperty
s
tamina
Type
)
{
public
int
updateStaminaAbsolute
(
GameSession
session
,
String
reason
,
int
newStamina
,
boolean
isCharacterS
tamina
)
{
int
currentStamina
=
player
.
getProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
int
currentStamina
=
isCharacterStamina
?
getCurrentCharacterStamina
()
:
getCurrentVehicleStamina
(
);
// notify will update
// notify will update
for
(
Map
.
Entry
<
String
,
BeforeUpdateStaminaListener
>
listener
:
beforeUpdateStaminaListeners
.
entrySet
())
{
for
(
Map
.
Entry
<
String
,
BeforeUpdateStaminaListener
>
listener
:
beforeUpdateStaminaListeners
.
entrySet
())
{
int
overriddenNewStamina
=
listener
.
getValue
().
onBeforeUpdateStamina
(
reason
,
newStamina
);
int
overriddenNewStamina
=
listener
.
getValue
().
onBeforeUpdateStamina
(
reason
,
newStamina
,
isCharacterStamina
);
if
(
overriddenNewStamina
!=
newStamina
)
{
if
(
overriddenNewStamina
!=
newStamina
)
{
logger
.
debug
(
"Stamina update absolute("
+
logger
.
debug
(
"Stamina update absolute("
+
reason
+
", "
+
newStamina
+
") overridden to absolute("
+
reason
+
", "
+
newStamina
+
") overridden to absolute("
+
...
@@ -277,31 +286,31 @@ public class StaminaManager {
...
@@ -277,31 +286,31 @@ public class StaminaManager {
return
currentStamina
;
return
currentStamina
;
}
}
}
}
int
playerM
axStamina
=
player
.
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
);
int
m
axStamina
=
isCharacterStamina
?
getMaxCharacterStamina
()
:
getMaxVehicleStamina
(
);
if
(
newStamina
<
0
)
{
if
(
newStamina
<
0
)
{
newStamina
=
0
;
newStamina
=
0
;
}
else
if
(
newStamina
>
playerM
axStamina
)
{
}
else
if
(
newStamina
>
m
axStamina
)
{
newStamina
=
playerM
axStamina
;
newStamina
=
m
axStamina
;
}
}
return
setStamina
(
session
,
reason
,
newStamina
,
s
tamina
Type
);
return
setStamina
(
session
,
reason
,
newStamina
,
isCharacterS
tamina
);
}
}
// Returns new stamina and sends PlayerPropNotify
// Returns new stamina and sends PlayerPropNotify
or VehicleStaminaNotify
public
int
setStamina
(
GameSession
session
,
String
reason
,
int
newStamina
,
PlayerProperty
s
tamina
Type
)
{
public
int
setStamina
(
GameSession
session
,
String
reason
,
int
newStamina
,
boolean
isCharacterS
tamina
)
{
if
(!
GAME_OPTIONS
.
staminaUsage
)
{
if
(!
GAME_OPTIONS
.
staminaUsage
)
{
newStamina
=
player
.
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
);
newStamina
=
getMaxCharacterStamina
(
);
}
}
// set stamina
// set stamina if is character stamina
player
.
setProperty
(
staminaType
,
newStamina
);
if
(
isCharacterStamina
)
{
if
(
staminaType
==
PlayerProperty
.
PROP_CUR_TEMPORARY_STAMINA
)
{
player
.
setProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
,
newStamina
);
// TODO: Implement
// session.send(new PacketVehicleStaminaNotify(vehicleEntity, newStamina));
}
else
{
session
.
send
(
new
PacketPlayerPropNotify
(
player
,
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
));
session
.
send
(
new
PacketPlayerPropNotify
(
player
,
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
));
}
else
{
vehicleStamina
=
newStamina
;
session
.
send
(
new
PacketVehicleStaminaNotify
(
vehicleId
,
((
float
)
newStamina
)
/
100
));
}
}
// notify updated
// notify updated
for
(
Map
.
Entry
<
String
,
AfterUpdateStaminaListener
>
listener
:
afterUpdateStaminaListeners
.
entrySet
())
{
for
(
Map
.
Entry
<
String
,
AfterUpdateStaminaListener
>
listener
:
afterUpdateStaminaListeners
.
entrySet
())
{
listener
.
getValue
().
onAfterUpdateStamina
(
reason
,
newStamina
);
listener
.
getValue
().
onAfterUpdateStamina
(
reason
,
newStamina
,
isCharacterStamina
);
}
}
return
newStamina
;
return
newStamina
;
}
}
...
@@ -379,11 +388,11 @@ public class StaminaManager {
...
@@ -379,11 +388,11 @@ public class StaminaManager {
MotionState
motionState
=
motionInfo
.
getState
();
MotionState
motionState
=
motionInfo
.
getState
();
int
notifyEntityId
=
entity
.
getId
();
int
notifyEntityId
=
entity
.
getId
();
int
currentAvatarEntityId
=
session
.
getPlayer
().
getTeamManager
().
getCurrentAvatarEntity
().
getId
();
int
currentAvatarEntityId
=
session
.
getPlayer
().
getTeamManager
().
getCurrentAvatarEntity
().
getId
();
if
(
notifyEntityId
!=
currentAvatarEntityId
)
{
if
(
notifyEntityId
!=
currentAvatarEntityId
&&
notifyEntityId
!=
vehicleId
)
{
return
;
return
;
}
}
currentState
=
motionState
;
currentState
=
motionState
;
// logger.trace(
"" +
currentState);
// logger.trace(currentState
+ "\t" + (notifyEntityId == currentAvatarEntityId ? "character" : "vehicle")
);
Vector
posVector
=
motionInfo
.
getPos
();
Vector
posVector
=
motionInfo
.
getPos
();
Position
newPos
=
new
Position
(
posVector
.
getX
(),
posVector
.
getY
(),
posVector
.
getZ
());
Position
newPos
=
new
Position
(
posVector
.
getX
(),
posVector
.
getY
(),
posVector
.
getZ
());
if
(
newPos
.
getX
()
!=
0
&&
newPos
.
getY
()
!=
0
&&
newPos
.
getZ
()
!=
0
)
{
if
(
newPos
.
getX
()
!=
0
&&
newPos
.
getY
()
!=
0
&&
newPos
.
getZ
()
!=
0
)
{
...
@@ -393,28 +402,40 @@ public class StaminaManager {
...
@@ -393,28 +402,40 @@ public class StaminaManager {
handleImmediateStamina
(
session
,
motionState
);
handleImmediateStamina
(
session
,
motionState
);
}
}
public
void
handleVehicleInteractReq
(
GameSession
session
,
int
vehicleId
,
VehicleInteractType
vehicleInteractType
)
{
if
(
vehicleInteractType
==
VehicleInteractType
.
VEHICLE_INTERACT_IN
)
{
this
.
vehicleId
=
vehicleId
;
// Reset character stamina here to prevent falling into water immediately on ejection if char stamina is
// close to empty when boarding.
updateStaminaAbsolute
(
session
,
"board vehicle"
,
getMaxCharacterStamina
(),
true
);
updateStaminaAbsolute
(
session
,
"board vehicle"
,
getMaxVehicleStamina
(),
false
);
}
else
{
this
.
vehicleId
=
-
1
;
}
}
// Internal handler
// Internal handler
private
void
handleImmediateStamina
(
GameSession
session
,
@NotNull
MotionState
motionState
)
{
private
void
handleImmediateStamina
(
GameSession
session
,
@NotNull
MotionState
motionState
)
{
switch
(
motionState
)
{
switch
(
motionState
)
{
case
MOTION_CLIMB:
case
MOTION_CLIMB:
if
(
currentState
!=
MotionState
.
MOTION_CLIMB
)
{
if
(
currentState
!=
MotionState
.
MOTION_CLIMB
)
{
updateStaminaRelative
(
session
,
new
Consumption
(
ConsumptionType
.
CLIMB_START
),
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
updateStaminaRelative
(
session
,
new
Consumption
(
ConsumptionType
.
CLIMB_START
),
true
);
}
}
break
;
break
;
case
MOTION_DASH_BEFORE_SHAKE:
case
MOTION_DASH_BEFORE_SHAKE:
if
(
previousState
!=
MotionState
.
MOTION_DASH_BEFORE_SHAKE
)
{
if
(
previousState
!=
MotionState
.
MOTION_DASH_BEFORE_SHAKE
)
{
updateStaminaRelative
(
session
,
new
Consumption
(
ConsumptionType
.
SPRINT
),
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
updateStaminaRelative
(
session
,
new
Consumption
(
ConsumptionType
.
SPRINT
),
true
);
}
}
break
;
break
;
case
MOTION_CLIMB_JUMP:
case
MOTION_CLIMB_JUMP:
if
(
previousState
!=
MotionState
.
MOTION_CLIMB_JUMP
)
{
if
(
previousState
!=
MotionState
.
MOTION_CLIMB_JUMP
)
{
updateStaminaRelative
(
session
,
new
Consumption
(
ConsumptionType
.
CLIMB_JUMP
),
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
updateStaminaRelative
(
session
,
new
Consumption
(
ConsumptionType
.
CLIMB_JUMP
),
true
);
}
}
break
;
break
;
case
MOTION_SWIM_DASH:
case
MOTION_SWIM_DASH:
if
(
previousState
!=
MotionState
.
MOTION_SWIM_DASH
)
{
if
(
previousState
!=
MotionState
.
MOTION_SWIM_DASH
)
{
updateStaminaRelative
(
session
,
new
Consumption
(
ConsumptionType
.
SWIM_DASH_START
),
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
updateStaminaRelative
(
session
,
new
Consumption
(
ConsumptionType
.
SWIM_DASH_START
),
true
);
}
}
break
;
break
;
}
}
...
@@ -422,18 +443,20 @@ public class StaminaManager {
...
@@ -422,18 +443,20 @@ public class StaminaManager {
private
void
handleImmediateStamina
(
GameSession
session
,
int
skillId
)
{
private
void
handleImmediateStamina
(
GameSession
session
,
int
skillId
)
{
Consumption
consumption
=
getFightConsumption
(
skillId
);
Consumption
consumption
=
getFightConsumption
(
skillId
);
updateStaminaRelative
(
session
,
consumption
,
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
updateStaminaRelative
(
session
,
consumption
,
true
);
}
}
private
class
SustainedStaminaHandler
extends
TimerTask
{
private
class
SustainedStaminaHandler
extends
TimerTask
{
public
void
run
()
{
public
void
run
()
{
boolean
moving
=
isPlayerMoving
();
boolean
moving
=
isPlayerMoving
();
int
currentStamina
=
player
.
getProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
int
currentCharacterStamina
=
getCurrentCharacterStamina
();
int
maxStamina
=
player
.
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
);
int
maxCharacterStamina
=
getMaxCharacterStamina
();
if
(
moving
||
(
currentStamina
<
maxStamina
))
{
int
currentVehicleStamina
=
getCurrentVehicleStamina
();
int
maxVehicleStamina
=
getMaxVehicleStamina
();
if
(
moving
||
(
currentCharacterStamina
<
maxCharacterStamina
)
||
(
currentVehicleStamina
<
maxVehicleStamina
))
{
logger
.
trace
(
"Player moving: "
+
moving
+
", stamina full: "
+
logger
.
trace
(
"Player moving: "
+
moving
+
", stamina full: "
+
(
currentStamina
>=
maxStamina
)
+
", recalculate stamina"
);
(
current
Character
Stamina
>=
max
Character
Stamina
)
+
", recalculate stamina"
);
boolean
isCharacterStamina
=
true
;
Consumption
consumption
;
Consumption
consumption
;
if
(
MotionStatesCategorized
.
get
(
"CLIMB"
).
contains
(
currentState
))
{
if
(
MotionStatesCategorized
.
get
(
"CLIMB"
).
contains
(
currentState
))
{
consumption
=
getClimbConsumption
();
consumption
=
getClimbConsumption
();
...
@@ -445,6 +468,7 @@ public class StaminaManager {
...
@@ -445,6 +468,7 @@ public class StaminaManager {
consumption
=
new
Consumption
(
ConsumptionType
.
RUN
);
consumption
=
new
Consumption
(
ConsumptionType
.
RUN
);
}
else
if
(
MotionStatesCategorized
.
get
(
"SKIFF"
).
contains
(
currentState
))
{
}
else
if
(
MotionStatesCategorized
.
get
(
"SKIFF"
).
contains
(
currentState
))
{
consumption
=
getSkiffConsumption
();
consumption
=
getSkiffConsumption
();
isCharacterStamina
=
false
;
}
else
if
(
MotionStatesCategorized
.
get
(
"STANDBY"
).
contains
(
currentState
))
{
}
else
if
(
MotionStatesCategorized
.
get
(
"STANDBY"
).
contains
(
currentState
))
{
consumption
=
new
Consumption
(
ConsumptionType
.
STANDBY
);
consumption
=
new
Consumption
(
ConsumptionType
.
STANDBY
);
}
else
if
(
MotionStatesCategorized
.
get
(
"SWIM"
).
contains
(
currentState
))
{
}
else
if
(
MotionStatesCategorized
.
get
(
"SWIM"
).
contains
(
currentState
))
{
...
@@ -459,16 +483,10 @@ public class StaminaManager {
...
@@ -459,16 +483,10 @@ public class StaminaManager {
return
;
return
;
}
}
if
(
consumption
.
amount
<
0
)
{
if
(
consumption
.
amount
<
0
&&
isCharacterStamina
)
{
/* Do not apply reduction factor when recovering stamina
// Do not apply reduction factor when recovering stamina
TODO: Reductions that apply to all motion types:
Skills
Diona E: -10% while shield lasts - applies to SP+MP
Barbara E: -12% while lasts - applies to SP+MP
*/
// Elemental Resonance - Winds -15%
if
(
player
.
getTeamManager
().
getTeamResonances
().
contains
(
10301
))
{
if
(
player
.
getTeamManager
().
getTeamResonances
().
contains
(
10301
))
{
consumption
.
amount
*=
0.85f
;
consumption
.
amount
*=
0.85f
;
}
}
}
}
// Delay 1 seconds before starts recovering stamina
// Delay 1 seconds before starts recovering stamina
...
@@ -476,8 +494,10 @@ public class StaminaManager {
...
@@ -476,8 +494,10 @@ public class StaminaManager {
if
(
consumption
.
amount
<
0
)
{
if
(
consumption
.
amount
<
0
)
{
staminaRecoverDelay
=
0
;
staminaRecoverDelay
=
0
;
}
}
if
(
consumption
.
amount
>
0
&&
consumption
.
type
!=
ConsumptionType
.
POWERED_FLY
)
{
if
(
consumption
.
amount
>
0
// For POWERED_FLY recover immediately - things like Amber's gliding exam may require this.
&&
consumption
.
type
!=
ConsumptionType
.
POWERED_FLY
&&
consumption
.
type
!=
ConsumptionType
.
POWERED_SKIFF
)
{
// For POWERED_* recover immediately - things like Amber's gliding exam and skiff challenges may require this.
if
(
staminaRecoverDelay
<
5
)
{
if
(
staminaRecoverDelay
<
5
)
{
// For others recover after 1 seconds (5 ticks) - as official server does.
// For others recover after 1 seconds (5 ticks) - as official server does.
staminaRecoverDelay
++;
staminaRecoverDelay
++;
...
@@ -485,7 +505,7 @@ public class StaminaManager {
...
@@ -485,7 +505,7 @@ public class StaminaManager {
logger
.
trace
(
"Delaying recovery: "
+
staminaRecoverDelay
);
logger
.
trace
(
"Delaying recovery: "
+
staminaRecoverDelay
);
}
}
}
}
updateStaminaRelative
(
cachedSession
,
consumption
,
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
updateStaminaRelative
(
cachedSession
,
consumption
,
isCharacterStamina
);
}
}
}
}
previousState
=
currentState
;
previousState
=
currentState
;
...
@@ -499,10 +519,10 @@ public class StaminaManager {
...
@@ -499,10 +519,10 @@ public class StaminaManager {
private
void
handleDrowning
()
{
private
void
handleDrowning
()
{
// TODO: fix drowning waverider entity
// TODO: fix drowning waverider entity
int
stamina
=
player
.
getProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
);
int
stamina
=
getCurrentCharacterStamina
(
);
if
(
stamina
<
10
)
{
if
(
stamina
<
10
)
{
logger
.
trace
(
player
.
getProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
)
+
"/"
+
logger
.
trace
(
getCurrentCharacterStamina
(
)
+
"/"
+
player
.
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
)
+
"\t"
+
currentState
);
getMaxCharacterStamina
(
)
+
"\t"
+
currentState
);
if
(
currentState
!=
MotionState
.
MOTION_SWIM_IDLE
)
{
if
(
currentState
!=
MotionState
.
MOTION_SWIM_IDLE
)
{
killAvatar
(
cachedSession
,
cachedEntity
,
PlayerDieType
.
PLAYER_DIE_DRAWN
);
killAvatar
(
cachedSession
,
cachedEntity
,
PlayerDieType
.
PLAYER_DIE_DRAWN
);
}
}
...
@@ -530,15 +550,15 @@ public class StaminaManager {
...
@@ -530,15 +550,15 @@ public class StaminaManager {
}
}
// Catalyst avatar charged attack
// Catalyst avatar charged attack
if
(
CatalystAvatars
.
contains
(
currentAvatarId
))
{
if
(
CatalystAvatars
.
contains
(
currentAvatarId
))
{
return
getCatalyst
Sustained
Cost
(
skillCasting
);
return
getCatalystCost
(
skillCasting
);
}
}
// Polearm avatar charged attack
// Polearm avatar charged attack
if
(
PolearmAvatars
.
contains
(
currentAvatarId
))
{
if
(
PolearmAvatars
.
contains
(
currentAvatarId
))
{
return
getPolearm
Sustained
Cost
(
skillCasting
);
return
getPolearmCost
(
skillCasting
);
}
}
// Sword avatar charged attack
// Sword avatar charged attack
if
(
SwordAvatars
.
contains
(
skillCasting
))
{
if
(
SwordAvatars
.
contains
(
skillCasting
))
{
return
getSword
Sustained
Cost
(
skillCasting
);
return
getSwordCost
(
skillCasting
);
}
}
return
new
Consumption
();
return
new
Consumption
();
}
}
...
@@ -596,12 +616,13 @@ public class StaminaManager {
...
@@ -596,12 +616,13 @@ public class StaminaManager {
}
}
private
Consumption
getSkiffConsumption
()
{
private
Consumption
getSkiffConsumption
()
{
// POWERED_SKIFF, e.g. wind tunnel
if
(
currentState
==
MotionState
.
MOTION_SKIFF_POWERED_DASH
)
{
return
new
Consumption
(
ConsumptionType
.
POWERED_SKIFF
);
}
// No known reduction for skiffing.
// No known reduction for skiffing.
return
new
Consumption
(
ConsumptionType
.
SKIFF
);
return
switch
(
currentState
)
{
case
MOTION_SKIFF_DASH
->
new
Consumption
(
ConsumptionType
.
SKIFF_DASH
);
case
MOTION_SKIFF_POWERED_DASH
->
new
Consumption
(
ConsumptionType
.
POWERED_SKIFF
);
case
MOTION_SKIFF_NORMAL
->
new
Consumption
(
ConsumptionType
.
SKIFF
);
default
->
new
Consumption
();
};
}
}
private
Consumption
getOtherConsumptions
()
{
private
Consumption
getOtherConsumptions
()
{
...
@@ -662,11 +683,11 @@ public class StaminaManager {
...
@@ -662,11 +683,11 @@ public class StaminaManager {
return
new
Consumption
(
ConsumptionType
.
FIGHT
,
+
500
);
return
new
Consumption
(
ConsumptionType
.
FIGHT
,
+
500
);
}
}
private
Consumption
getCatalyst
Sustained
Cost
(
int
skillId
)
{
private
Consumption
getCatalystCost
(
int
skillId
)
{
Consumption
consumption
=
new
Consumption
(
ConsumptionType
.
FIGHT
,
-
5000
);
Consumption
consumption
=
new
Consumption
(
ConsumptionType
.
FIGHT
,
-
5000
);
// Character specific handling
// Character specific handling
switch
(
skillId
)
{
switch
(
skillId
)
{
// TODO:
Yanfei
// TODO:
}
}
return
consumption
;
return
consumption
;
}
}
...
@@ -675,11 +696,11 @@ public class StaminaManager {
...
@@ -675,11 +696,11 @@ public class StaminaManager {
Consumption
consumption
=
new
Consumption
(
ConsumptionType
.
FIGHT
,
-
1333
);
// 4000 / 3 = 1333
Consumption
consumption
=
new
Consumption
(
ConsumptionType
.
FIGHT
,
-
1333
);
// 4000 / 3 = 1333
// Character specific handling
// Character specific handling
switch
(
skillId
)
{
switch
(
skillId
)
{
case
10571
:
// Arataki Itto, does not consume stamina at all.
case
10571
:
case
10532
:
// Sayu, windwheel does not consume stamina.
case
10532
:
consumption
.
amount
=
0
;
consumption
.
amount
=
0
;
break
;
break
;
case
10160
:
// Diluc, with talent "Relentless" stamina cost is decreased by 50%
case
10160
:
if
(
player
.
getTeamManager
().
getCurrentAvatarEntity
().
getAvatar
().
getProudSkillList
().
contains
(
162101
))
{
if
(
player
.
getTeamManager
().
getCurrentAvatarEntity
().
getAvatar
().
getProudSkillList
().
contains
(
162101
))
{
consumption
.
amount
/=
2
;
consumption
.
amount
/=
2
;
}
}
...
@@ -688,7 +709,7 @@ public class StaminaManager {
...
@@ -688,7 +709,7 @@ public class StaminaManager {
return
consumption
;
return
consumption
;
}
}
private
Consumption
getPolearm
Sustained
Cost
(
int
skillId
)
{
private
Consumption
getPolearmCost
(
int
skillId
)
{
Consumption
consumption
=
new
Consumption
(
ConsumptionType
.
FIGHT
,
-
2500
);
Consumption
consumption
=
new
Consumption
(
ConsumptionType
.
FIGHT
,
-
2500
);
// Character specific handling
// Character specific handling
switch
(
skillId
)
{
switch
(
skillId
)
{
...
@@ -697,11 +718,11 @@ public class StaminaManager {
...
@@ -697,11 +718,11 @@ public class StaminaManager {
return
consumption
;
return
consumption
;
}
}
private
Consumption
getSword
Sustained
Cost
(
int
skillId
)
{
private
Consumption
getSwordCost
(
int
skillId
)
{
Consumption
consumption
=
new
Consumption
(
ConsumptionType
.
FIGHT
,
-
2000
);
Consumption
consumption
=
new
Consumption
(
ConsumptionType
.
FIGHT
,
-
2000
);
// Character specific handling
// Character specific handling
switch
(
skillId
)
{
switch
(
skillId
)
{
case
10421
:
// Keqing, -2500
case
10421
:
consumption
.
amount
=
-
2500
;
consumption
.
amount
=
-
2500
;
break
;
break
;
}
}
...
...
src/main/java/emu/grasscutter/game/player/Player.java
View file @
2531ae36
...
@@ -1237,7 +1237,7 @@ public class Player {
...
@@ -1237,7 +1237,7 @@ public class Player {
}
else
if
(
prop
==
PlayerProperty
.
PROP_IS_TRANSFERABLE
)
{
// 10009
}
else
if
(
prop
==
PlayerProperty
.
PROP_IS_TRANSFERABLE
)
{
// 10009
if
(!(
0
<=
value
&&
value
<=
1
))
{
return
false
;
}
if
(!(
0
<=
value
&&
value
<=
1
))
{
return
false
;
}
}
else
if
(
prop
==
PlayerProperty
.
PROP_MAX_STAMINA
)
{
// 10010
}
else
if
(
prop
==
PlayerProperty
.
PROP_MAX_STAMINA
)
{
// 10010
if
(!(
value
>=
0
&&
value
<=
StaminaManager
.
GlobalMaximumStamina
))
{
return
false
;
}
if
(!(
value
>=
0
&&
value
<=
StaminaManager
.
Global
Character
MaximumStamina
))
{
return
false
;
}
}
else
if
(
prop
==
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
)
{
// 10011
}
else
if
(
prop
==
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
)
{
// 10011
int
playerMaximumStamina
=
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
);
int
playerMaximumStamina
=
getProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
);
if
(!(
value
>=
0
&&
value
<=
playerMaximumStamina
))
{
return
false
;
}
if
(!(
value
>=
0
&&
value
<=
playerMaximumStamina
))
{
return
false
;
}
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerVehicleInteractReq.java
View file @
2531ae36
...
@@ -14,6 +14,7 @@ public class HandlerVehicleInteractReq extends PacketHandler {
...
@@ -14,6 +14,7 @@ public class HandlerVehicleInteractReq extends PacketHandler {
@Override
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
VehicleInteractReqOuterClass
.
VehicleInteractReq
req
=
VehicleInteractReqOuterClass
.
VehicleInteractReq
.
parseFrom
(
payload
);
VehicleInteractReqOuterClass
.
VehicleInteractReq
req
=
VehicleInteractReqOuterClass
.
VehicleInteractReq
.
parseFrom
(
payload
);
session
.
getPlayer
().
getStaminaManager
().
handleVehicleInteractReq
(
session
,
req
.
getEntityId
(),
req
.
getInteractType
());
session
.
send
(
new
PacketVehicleInteractRsp
(
session
.
getPlayer
(),
req
.
getEntityId
(),
req
.
getInteractType
()));
session
.
send
(
new
PacketVehicleInteractRsp
(
session
.
getPlayer
(),
req
.
getEntityId
(),
req
.
getInteractType
()));
}
}
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketVehicleStaminaNotify.java
View file @
2531ae36
package
emu.grasscutter.server.packet.send
;
package
emu.grasscutter.server.packet.send
;
import
emu.grasscutter.game.entity.GameEntity
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.VehicleStaminaNotifyOuterClass.VehicleStaminaNotify
;
import
emu.grasscutter.net.proto.VehicleStaminaNotifyOuterClass.VehicleStaminaNotify
;
public
class
PacketVehicleStaminaNotify
extends
BasePacket
{
public
class
PacketVehicleStaminaNotify
extends
BasePacket
{
public
PacketVehicleStaminaNotify
(
GameEntity
entity
,
in
t
newStamina
)
{
public
PacketVehicleStaminaNotify
(
int
vehicleId
,
floa
t
newStamina
)
{
super
(
PacketOpcodes
.
VehicleStaminaNotify
);
super
(
PacketOpcodes
.
VehicleStaminaNotify
);
VehicleStaminaNotify
.
Builder
proto
=
VehicleStaminaNotify
.
newBuilder
();
VehicleStaminaNotify
.
Builder
proto
=
VehicleStaminaNotify
.
newBuilder
();
proto
.
setEntityId
(
entity
.
getId
()
);
proto
.
setEntityId
(
vehicleId
);
proto
.
setCurStamina
(
newStamina
);
proto
.
setCurStamina
(
newStamina
);
this
.
setData
(
proto
.
build
());
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