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
219a8508
Commit
219a8508
authored
May 08, 2022
by
Akka
Browse files
Merge remote-tracking branch 'origin/development' into tower
parents
4b6842f0
65861c3c
Changes
66
Expand all
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java
View file @
219a8508
...
@@ -10,9 +10,9 @@ import java.util.List;
...
@@ -10,9 +10,9 @@ import java.util.List;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
@Command
(
label
=
"tpall"
,
usage
=
"tpall"
,
@Command
(
label
=
"tpall"
,
usage
=
"tpall"
,
permission
=
"player.tpall"
,
description
=
"commands.teleportAll.description"
)
description
=
"Teleports all players in your world to your position"
,
permission
=
"player.tpall"
)
public
final
class
TeleportAllCommand
implements
CommandHandler
{
public
final
class
TeleportAllCommand
implements
CommandHandler
{
@Override
@Override
public
void
execute
(
Player
sender
,
Player
targetPlayer
,
List
<
String
>
args
)
{
public
void
execute
(
Player
sender
,
Player
targetPlayer
,
List
<
String
>
args
)
{
if
(
targetPlayer
==
null
)
{
if
(
targetPlayer
==
null
)
{
...
...
src/main/java/emu/grasscutter/command/commands/TeleportCommand.java
View file @
219a8508
...
@@ -10,8 +10,7 @@ import java.util.List;
...
@@ -10,8 +10,7 @@ import java.util.List;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
@Command
(
label
=
"teleport"
,
usage
=
"teleport <x> <y> <z> [scene id]"
,
aliases
=
{
"tp"
},
@Command
(
label
=
"teleport"
,
usage
=
"teleport <x> <y> <z> [scene id]"
,
aliases
=
{
"tp"
},
permission
=
"player.teleport"
,
description
=
"commands.teleport.description"
)
description
=
"Change the player's position."
,
permission
=
"player.teleport"
)
public
final
class
TeleportCommand
implements
CommandHandler
{
public
final
class
TeleportCommand
implements
CommandHandler
{
private
float
parseRelative
(
String
input
,
Float
current
)
{
// TODO: Maybe this will be useful elsewhere later
private
float
parseRelative
(
String
input
,
Float
current
)
{
// TODO: Maybe this will be useful elsewhere later
...
...
src/main/java/emu/grasscutter/command/commands/WeatherCommand.java
View file @
219a8508
...
@@ -11,8 +11,7 @@ import java.util.List;
...
@@ -11,8 +11,7 @@ import java.util.List;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
@Command
(
label
=
"weather"
,
usage
=
"weather <weatherId> [climateId]"
,
@Command
(
label
=
"weather"
,
usage
=
"weather <weatherId> [climateId]"
,
aliases
=
{
"w"
},
permission
=
"player.weather"
,
description
=
"commands.weather.description"
)
description
=
"Changes the weather."
,
aliases
=
{
"w"
},
permission
=
"player.weather"
)
public
final
class
WeatherCommand
implements
CommandHandler
{
public
final
class
WeatherCommand
implements
CommandHandler
{
@Override
@Override
...
...
src/main/java/emu/grasscutter/game/gacha/GachaBanner.java
View file @
219a8508
...
@@ -96,7 +96,7 @@ public class GachaBanner {
...
@@ -96,7 +96,7 @@ public class GachaBanner {
return
toProto
(
""
);
return
toProto
(
""
);
}
}
public
GachaInfo
toProto
(
String
sessionKey
)
{
public
GachaInfo
toProto
(
String
sessionKey
)
{
String
record
=
"http
s
://"
String
record
=
"http
"
+
(
Grasscutter
.
getConfig
().
getDispatchOptions
().
FrontHTTPS
?
"s"
:
""
)
+
"
://"
+
(
Grasscutter
.
getConfig
().
getDispatchOptions
().
PublicIp
.
isEmpty
()
?
+
(
Grasscutter
.
getConfig
().
getDispatchOptions
().
PublicIp
.
isEmpty
()
?
Grasscutter
.
getConfig
().
getDispatchOptions
().
Ip
:
Grasscutter
.
getConfig
().
getDispatchOptions
().
Ip
:
Grasscutter
.
getConfig
().
getDispatchOptions
().
PublicIp
)
Grasscutter
.
getConfig
().
getDispatchOptions
().
PublicIp
)
...
...
src/main/java/emu/grasscutter/game/managers/SotSManager
/SotSManager
.java
→
src/main/java/emu/grasscutter/game/managers/SotSManager.java
View file @
219a8508
package
emu.grasscutter.game.managers
.SotSManager
;
package
emu.grasscutter.game.managers
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.avatar.Avatar
;
import
emu.grasscutter.game.avatar.Avatar
;
import
emu.grasscutter.game.entity.EntityAvatar
;
import
emu.grasscutter.game.entity.EntityAvatar
;
import
emu.grasscutter.game.entity.GameEntity
;
import
emu.grasscutter.game.managers.MovementManager.MovementManager
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.game.world.World
;
import
emu.grasscutter.net.proto.ChangeHpReasonOuterClass
;
import
emu.grasscutter.net.proto.ChangeHpReasonOuterClass
;
import
emu.grasscutter.net.proto.PropChangeReasonOuterClass
;
import
emu.grasscutter.net.proto.PropChangeReasonOuterClass
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.game.GameSession
;
...
@@ -29,6 +26,8 @@ public class SotSManager {
...
@@ -29,6 +26,8 @@ public class SotSManager {
private
final
Player
player
;
private
final
Player
player
;
private
Timer
autoRecoverTimer
;
private
Timer
autoRecoverTimer
;
public
final
static
int
GlobalMaximumSpringVolume
=
8500000
;
public
SotSManager
(
Player
player
)
{
public
SotSManager
(
Player
player
)
{
this
.
player
=
player
;
this
.
player
=
player
;
}
}
...
...
src/main/java/emu/grasscutter/game/managers/StaminaManager/AfterUpdateStaminaListener.java
0 → 100644
View file @
219a8508
package
emu.grasscutter.game.managers.StaminaManager
;
public
interface
AfterUpdateStaminaListener
{
/**
* onBeforeUpdateStamina() will be called before StaminaManager attempt to update the player's current stamina.
* This gives listeners a chance to intercept this update.
*
* @param reason Why updating stamina.
* @param newStamina New Stamina value.
*/
void
onAfterUpdateStamina
(
String
reason
,
int
newStamina
);
}
src/main/java/emu/grasscutter/game/managers/StaminaManager/BeforeUpdateStaminaListener.java
0 → 100644
View file @
219a8508
package
emu.grasscutter.game.managers.StaminaManager
;
public
interface
BeforeUpdateStaminaListener
{
/**
* onBeforeUpdateStamina() will be called before StaminaManager attempt to update the player's current stamina.
* This gives listeners a chance to intercept this update.
* @param reason Why updating stamina.
* @param newStamina New ABSOLUTE stamina value.
* @return true if you want to cancel this update, otherwise false.
*/
int
onBeforeUpdateStamina
(
String
reason
,
int
newStamina
);
/**
* onBeforeUpdateStamina() will be called before StaminaManager attempt to update the player's current stamina.
* This gives listeners a chance to intercept this update.
* @param reason Why updating stamina.
* @param consumption ConsumptionType and RELATIVE stamina change amount.
* @return true if you want to cancel this update, otherwise false.
*/
Consumption
onBeforeUpdateStamina
(
String
reason
,
Consumption
consumption
);
}
\ No newline at end of file
src/main/java/emu/grasscutter/game/managers/StaminaManager/Consumption.java
0 → 100644
View file @
219a8508
package
emu.grasscutter.game.managers.StaminaManager
;
public
class
Consumption
{
public
ConsumptionType
consumptionType
;
public
int
amount
;
public
Consumption
(
ConsumptionType
ct
,
int
a
)
{
consumptionType
=
ct
;
amount
=
a
;
}
public
Consumption
(
ConsumptionType
ct
)
{
this
(
ct
,
ct
.
amount
);
}
}
src/main/java/emu/grasscutter/game/managers/StaminaManager/ConsumptionType.java
0 → 100644
View file @
219a8508
package
emu.grasscutter.game.managers.StaminaManager
;
public
enum
ConsumptionType
{
None
(
0
),
// consume
CLIMB_START
(-
500
),
CLIMBING
(-
150
),
CLIMB_JUMP
(-
2500
),
SPRINT
(-
1800
),
DASH
(-
360
),
FLY
(-
60
),
SWIM_DASH_START
(-
20
),
SWIM_DASH
(-
204
),
SWIMMING
(-
80
),
// TODO: Slow swimming is handled per movement, not per second. Movement frequency depends on gender/age/height.
FIGHT
(
0
),
// See StaminaManager.getFightConsumption()
// restore
STANDBY
(
500
),
RUN
(
500
),
WALK
(
500
),
STANDBY_MOVE
(
500
),
POWERED_FLY
(
500
);
public
final
int
amount
;
ConsumptionType
(
int
amount
)
{
this
.
amount
=
amount
;
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/game/managers/StaminaManager/README.md
0 → 100644
View file @
219a8508
# Stamina Manager
---
## UpdateStamina
```
java
// will use consumption.consumptionType as reason
public
int
updateStaminaRelative
(
GameSession
session
,
Consumption
consumption
);
```
```
java
public
int
updateStaminaAbsolute
(
GameSession
session
,
String
reason
,
int
newStamina
)
```
---
## Pause and Resume
```
java
public
void
startSustainedStaminaHandler
()
```
```
java
public
void
stopSustainedStaminaHandler
()
```
---
## Stamina change listeners and intercepting
### BeforeUpdateStaminaListener
```
java
import
emu.grasscutter.game.managers.StaminaManager.BeforeUpdateStaminaListener
;
// Listener sample: plugin disable CLIMB_JUMP stamina cost.
private
class
MyClass
implements
BeforeUpdateStaminaListener
{
// Make your class implement the listener, and pass in your class as a listener.
public
MyClass
()
{
getStaminaManager
().
registerBeforeUpdateStaminaListener
(
"myClass"
,
this
);
}
@Override
public
boolean
onBeforeUpdateStamina
(
String
reason
,
int
newStamina
)
{
// do not intercept this update
return
false
;
}
@Override
public
boolean
onBeforeUpdateStamina
(
String
reason
,
Consumption
consumption
)
{
// Try to intercept if this update is CLIMB_JUMP
if
(
consumption
.
consumptionType
==
ConsumptionType
.
CLIMB_JUMP
)
{
return
true
;
}
// If it is not CLIMB_JUMP, do not intercept.
return
false
;
}
}
```
### AfterUpdateStaminaListener
```
java
import
emu.grasscutter.game.managers.StaminaManager.AfterUpdateStaminaListener
;
// Listener sample: plugin listens for changes already made.
private
class
MyClass
implements
AfterUpdateStaminaListener
{
// Make your class implement the listener, and pass in your class as a listener.
public
MyClass
()
{
registerAfterUpdateStaminaListener
(
"myClass"
,
this
);
}
@Override
public
void
onAfterUpdateStamina
(
String
reason
,
int
newStamina
)
{
// ...
}
}
```
\ No newline at end of file
src/main/java/emu/grasscutter/game/managers/
MovementManager/Movement
Manager.java
→
src/main/java/emu/grasscutter/game/managers/
StaminaManager/Stamina
Manager.java
View file @
219a8508
This diff is collapsed.
Click to expand it.
src/main/java/emu/grasscutter/game/player/Player.java
View file @
219a8508
...
@@ -22,8 +22,8 @@ import emu.grasscutter.game.inventory.GameItem;
...
@@ -22,8 +22,8 @@ import emu.grasscutter.game.inventory.GameItem;
import
emu.grasscutter.game.inventory.Inventory
;
import
emu.grasscutter.game.inventory.Inventory
;
import
emu.grasscutter.game.mail.Mail
;
import
emu.grasscutter.game.mail.Mail
;
import
emu.grasscutter.game.mail.MailHandler
;
import
emu.grasscutter.game.mail.MailHandler
;
import
emu.grasscutter.game.managers.
MovementManager.Movement
Manager
;
import
emu.grasscutter.game.managers.
StaminaManager.Stamina
Manager
;
import
emu.grasscutter.game.managers.SotSManager
.SotSManager
;
import
emu.grasscutter.game.managers.SotSManager
;
import
emu.grasscutter.game.props.ActionReason
;
import
emu.grasscutter.game.props.ActionReason
;
import
emu.grasscutter.game.props.EntityType
;
import
emu.grasscutter.game.props.EntityType
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
...
@@ -62,9 +62,6 @@ import java.util.concurrent.LinkedBlockingQueue;
...
@@ -62,9 +62,6 @@ import java.util.concurrent.LinkedBlockingQueue;
@Entity
(
value
=
"players"
,
useDiscriminator
=
false
)
@Entity
(
value
=
"players"
,
useDiscriminator
=
false
)
public
class
Player
{
public
class
Player
{
@Transient
private
static
int
GlobalMaximumSpringVolume
=
8500000
;
@Transient
private
static
int
GlobalMaximumStamina
=
24000
;
@Id
private
int
id
;
@Id
private
int
id
;
@Indexed
(
options
=
@IndexOptions
(
unique
=
true
))
private
String
accountId
;
@Indexed
(
options
=
@IndexOptions
(
unique
=
true
))
private
String
accountId
;
...
@@ -132,7 +129,7 @@ public class Player {
...
@@ -132,7 +129,7 @@ public class Player {
@Transient
private
final
InvokeHandler
<
AbilityInvokeEntry
>
clientAbilityInitFinishHandler
;
@Transient
private
final
InvokeHandler
<
AbilityInvokeEntry
>
clientAbilityInitFinishHandler
;
private
MapMarksManager
mapMarksManager
;
private
MapMarksManager
mapMarksManager
;
@Transient
private
MovementManager
movement
Manager
;
@Transient
private
StaminaManager
stamina
Manager
;
private
long
springLastUsed
;
private
long
springLastUsed
;
...
@@ -178,7 +175,7 @@ public class Player {
...
@@ -178,7 +175,7 @@ public class Player {
this
.
expeditionInfo
=
new
HashMap
<>();
this
.
expeditionInfo
=
new
HashMap
<>();
this
.
messageHandler
=
null
;
this
.
messageHandler
=
null
;
this
.
mapMarksManager
=
new
MapMarksManager
();
this
.
mapMarksManager
=
new
MapMarksManager
();
this
.
movement
Manager
=
new
Movement
Manager
(
this
);
this
.
stamina
Manager
=
new
Stamina
Manager
(
this
);
this
.
sotsManager
=
new
SotSManager
(
this
);
this
.
sotsManager
=
new
SotSManager
(
this
);
}
}
...
@@ -206,7 +203,7 @@ public class Player {
...
@@ -206,7 +203,7 @@ public class Player {
this
.
getRotation
().
set
(
0
,
307
,
0
);
this
.
getRotation
().
set
(
0
,
307
,
0
);
this
.
messageHandler
=
null
;
this
.
messageHandler
=
null
;
this
.
mapMarksManager
=
new
MapMarksManager
();
this
.
mapMarksManager
=
new
MapMarksManager
();
this
.
movement
Manager
=
new
Movement
Manager
(
this
);
this
.
stamina
Manager
=
new
Stamina
Manager
(
this
);
this
.
sotsManager
=
new
SotSManager
(
this
);
this
.
sotsManager
=
new
SotSManager
(
this
);
}
}
...
@@ -875,11 +872,11 @@ public class Player {
...
@@ -875,11 +872,11 @@ public class Player {
}
}
public
void
onPause
()
{
public
void
onPause
()
{
getStaminaManager
().
stopSustainedStaminaHandler
();
}
}
public
void
onUnpause
()
{
public
void
onUnpause
()
{
getStaminaManager
().
startSustainedStaminaHandler
();
}
}
public
void
sendPacket
(
BasePacket
packet
)
{
public
void
sendPacket
(
BasePacket
packet
)
{
...
@@ -1024,7 +1021,7 @@ public class Player {
...
@@ -1024,7 +1021,7 @@ public class Player {
return
mapMarksManager
;
return
mapMarksManager
;
}
}
public
Movement
Manager
get
Movement
Manager
()
{
return
movement
Manager
;
}
public
Stamina
Manager
get
Stamina
Manager
()
{
return
stamina
Manager
;
}
public
SotSManager
getSotSManager
()
{
return
sotsManager
;
}
public
SotSManager
getSotSManager
()
{
return
sotsManager
;
}
...
@@ -1152,7 +1149,7 @@ public class Player {
...
@@ -1152,7 +1149,7 @@ public class Player {
public
void
onLogout
()
{
public
void
onLogout
()
{
// stop stamina calculation
// stop stamina calculation
get
Movement
Manager
().
resetTim
er
();
get
Stamina
Manager
().
stopSustainedStaminaHandl
er
();
// force to leave the dungeon
// force to leave the dungeon
if
(
getScene
().
getSceneType
()
==
SceneType
.
SCENE_DUNGEON
)
{
if
(
getScene
().
getSceneType
()
==
SceneType
.
SCENE_DUNGEON
)
{
...
@@ -1214,7 +1211,7 @@ public class Player {
...
@@ -1214,7 +1211,7 @@ public class Player {
}
else
if
(
prop
==
PlayerProperty
.
PROP_LAST_CHANGE_AVATAR_TIME
)
{
// 10001
}
else
if
(
prop
==
PlayerProperty
.
PROP_LAST_CHANGE_AVATAR_TIME
)
{
// 10001
// TODO: implement sanity check
// TODO: implement sanity check
}
else
if
(
prop
==
PlayerProperty
.
PROP_MAX_SPRING_VOLUME
)
{
// 10002
}
else
if
(
prop
==
PlayerProperty
.
PROP_MAX_SPRING_VOLUME
)
{
// 10002
if
(!(
value
>=
0
&&
value
<=
GlobalMaximumSpringVolume
))
{
return
false
;
}
if
(!(
value
>=
0
&&
value
<=
getSotSManager
().
GlobalMaximumSpringVolume
))
{
return
false
;
}
}
else
if
(
prop
==
PlayerProperty
.
PROP_CUR_SPRING_VOLUME
)
{
// 10003
}
else
if
(
prop
==
PlayerProperty
.
PROP_CUR_SPRING_VOLUME
)
{
// 10003
int
playerMaximumSpringVolume
=
getProperty
(
PlayerProperty
.
PROP_MAX_SPRING_VOLUME
);
int
playerMaximumSpringVolume
=
getProperty
(
PlayerProperty
.
PROP_MAX_SPRING_VOLUME
);
if
(!(
value
>=
0
&&
value
<=
playerMaximumSpringVolume
))
{
return
false
;
}
if
(!(
value
>=
0
&&
value
<=
playerMaximumSpringVolume
))
{
return
false
;
}
...
@@ -1231,7 +1228,7 @@ public class Player {
...
@@ -1231,7 +1228,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
<=
GlobalMaximumStamina
))
{
return
false
;
}
if
(!(
value
>=
0
&&
value
<=
getStaminaManager
().
GlobalMaximumStamina
))
{
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
;
}
...
@@ -1242,7 +1239,7 @@ public class Player {
...
@@ -1242,7 +1239,7 @@ public class Player {
}
else
if
(
prop
==
PlayerProperty
.
PROP_PLAYER_EXP
)
{
// 10014
}
else
if
(
prop
==
PlayerProperty
.
PROP_PLAYER_EXP
)
{
// 10014
if
(!(
0
<=
value
))
{
return
false
;
}
if
(!(
0
<=
value
))
{
return
false
;
}
}
else
if
(
prop
==
PlayerProperty
.
PROP_PLAYER_HCOIN
)
{
// 10015
}
else
if
(
prop
==
PlayerProperty
.
PROP_PLAYER_HCOIN
)
{
// 10015
// see
10015
// see
PlayerProperty.PROP_PLAYER_HCOIN comments
}
else
if
(
prop
==
PlayerProperty
.
PROP_PLAYER_SCOIN
)
{
// 10016
}
else
if
(
prop
==
PlayerProperty
.
PROP_PLAYER_SCOIN
)
{
// 10016
// See 10015
// See 10015
}
else
if
(
prop
==
PlayerProperty
.
PROP_PLAYER_MP_SETTING_TYPE
)
{
// 10017
}
else
if
(
prop
==
PlayerProperty
.
PROP_PLAYER_MP_SETTING_TYPE
)
{
// 10017
...
...
src/main/java/emu/grasscutter/game/player/TeamManager.java
View file @
219a8508
...
@@ -557,7 +557,7 @@ public class TeamManager {
...
@@ -557,7 +557,7 @@ public class TeamManager {
// return;
// return;
// }
// }
// }
// }
player
.
get
Movement
Manager
().
resetTim
er
();
// prevent drowning immediately after respawn
player
.
get
Stamina
Manager
().
stopSustainedStaminaHandl
er
();
// prevent drowning immediately after respawn
// Revive all team members
// Revive all team members
for
(
EntityAvatar
entity
:
getActiveTeam
())
{
for
(
EntityAvatar
entity
:
getActiveTeam
())
{
...
...
src/main/java/emu/grasscutter/plugin/PluginManager.java
View file @
219a8508
...
@@ -4,12 +4,12 @@ import emu.grasscutter.Grasscutter;
...
@@ -4,12 +4,12 @@ import emu.grasscutter.Grasscutter;
import
emu.grasscutter.server.event.Event
;
import
emu.grasscutter.server.event.Event
;
import
emu.grasscutter.server.event.EventHandler
;
import
emu.grasscutter.server.event.EventHandler
;
import
emu.grasscutter.server.event.HandlerPriority
;
import
emu.grasscutter.server.event.HandlerPriority
;
import
emu.grasscutter.utils.EventConsumer
;
import
emu.grasscutter.utils.Utils
;
import
emu.grasscutter.utils.Utils
;
import
java.io.File
;
import
java.io.File
;
import
java.io.InputStreamReader
;
import
java.io.InputStreamReader
;
import
java.lang.reflect.Method
;
import
java.lang.reflect.Method
;
import
java.net.MalformedURLException
;
import
java.net.URL
;
import
java.net.URL
;
import
java.net.URLClassLoader
;
import
java.net.URLClassLoader
;
import
java.util.*
;
import
java.util.*
;
...
@@ -47,12 +47,23 @@ public final class PluginManager {
...
@@ -47,12 +47,23 @@ public final class PluginManager {
List
<
File
>
plugins
=
Arrays
.
stream
(
files
)
List
<
File
>
plugins
=
Arrays
.
stream
(
files
)
.
filter
(
file
->
file
.
getName
().
endsWith
(
".jar"
))
.
filter
(
file
->
file
.
getName
().
endsWith
(
".jar"
))
.
toList
();
.
toList
();
URL
[]
pluginNames
=
new
URL
[
plugins
.
size
()];
plugins
.
forEach
(
plugin
->
{
try
{
pluginNames
[
plugins
.
indexOf
(
plugin
)]
=
plugin
.
toURI
().
toURL
();
}
catch
(
MalformedURLException
exception
)
{
Grasscutter
.
getLogger
().
warn
(
"Unable to load plugin."
,
exception
);
}
});
URLClassLoader
classLoader
=
new
URLClassLoader
(
pluginNames
);
plugins
.
forEach
(
plugin
->
{
plugins
.
forEach
(
plugin
->
{
try
{
try
{
URL
url
=
plugin
.
toURI
().
toURL
();
URL
url
=
plugin
.
toURI
().
toURL
();
try
(
URLClassLoader
loader
=
new
URLClassLoader
(
new
URL
[]{
url
}))
{
try
(
URLClassLoader
loader
=
new
URLClassLoader
(
new
URL
[]{
url
}))
{
URL
configFile
=
loader
.
findResource
(
"plugin.json"
);
URL
configFile
=
loader
.
findResource
(
"plugin.json"
);
// Find the plugin.json file for each plugin.
InputStreamReader
fileReader
=
new
InputStreamReader
(
configFile
.
openStream
());
InputStreamReader
fileReader
=
new
InputStreamReader
(
configFile
.
openStream
());
PluginConfig
pluginConfig
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
PluginConfig
.
class
);
PluginConfig
pluginConfig
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
PluginConfig
.
class
);
...
@@ -68,10 +79,10 @@ public final class PluginManager {
...
@@ -68,10 +79,10 @@ public final class PluginManager {
JarEntry
entry
=
entries
.
nextElement
();
JarEntry
entry
=
entries
.
nextElement
();
if
(
entry
.
isDirectory
()
||
!
entry
.
getName
().
endsWith
(
".class"
)
||
entry
.
getName
().
contains
(
"module-info"
))
continue
;
if
(
entry
.
isDirectory
()
||
!
entry
.
getName
().
endsWith
(
".class"
)
||
entry
.
getName
().
contains
(
"module-info"
))
continue
;
String
className
=
entry
.
getName
().
replace
(
".class"
,
""
).
replace
(
"/"
,
"."
);
String
className
=
entry
.
getName
().
replace
(
".class"
,
""
).
replace
(
"/"
,
"."
);
l
oader
.
loadClass
(
className
);
classL
oader
.
loadClass
(
className
);
// Use the same class loader for ALL plugins.
}
}
Class
<?>
pluginClass
=
l
oader
.
loadClass
(
pluginConfig
.
mainClass
);
Class
<?>
pluginClass
=
classL
oader
.
loadClass
(
pluginConfig
.
mainClass
);
Plugin
pluginInstance
=
(
Plugin
)
pluginClass
.
getDeclaredConstructor
().
newInstance
();
Plugin
pluginInstance
=
(
Plugin
)
pluginClass
.
getDeclaredConstructor
().
newInstance
();
this
.
loadPlugin
(
pluginInstance
,
PluginIdentifier
.
fromPluginConfig
(
pluginConfig
),
loader
);
this
.
loadPlugin
(
pluginInstance
,
PluginIdentifier
.
fromPluginConfig
(
pluginConfig
),
loader
);
...
@@ -156,6 +167,10 @@ public final class PluginManager {
...
@@ -156,6 +167,10 @@ public final class PluginManager {
.
toList
().
forEach
(
handler
->
this
.
invokeHandler
(
event
,
handler
));
.
toList
().
forEach
(
handler
->
this
.
invokeHandler
(
event
,
handler
));
}
}
public
Plugin
getPlugin
(
String
name
)
{
return
this
.
plugins
.
get
(
name
);
}
/**
/**
* Performs logic checks then invokes the provided event handler.
* Performs logic checks then invokes the provided event handler.
* @param event The event passed through to the handler.
* @param event The event passed through to the handler.
...
@@ -167,4 +182,4 @@ public final class PluginManager {
...
@@ -167,4 +182,4 @@ public final class PluginManager {
(
event
.
isCanceled
()
&&
handler
.
ignoresCanceled
())
(
event
.
isCanceled
()
&&
handler
.
ignoresCanceled
())
)
handler
.
getCallback
().
consume
((
T
)
event
);
)
handler
.
getCallback
().
consume
((
T
)
event
);
}
}
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java
View file @
219a8508
package
emu.grasscutter.server.packet.recv
;
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.entity.GameEntity
;
import
emu.grasscutter.game.entity.GameEntity
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify
;
import
emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify
;
...
@@ -8,11 +10,19 @@ import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
...
@@ -8,11 +10,19 @@ import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
import
emu.grasscutter.net.proto.EntityMoveInfoOuterClass.EntityMoveInfo
;
import
emu.grasscutter.net.proto.EntityMoveInfoOuterClass.EntityMoveInfo
;
import
emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo
;
import
emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo
;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.net.proto.PlayerDieTypeOuterClass
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify
;
@Opcodes
(
PacketOpcodes
.
CombatInvocationsNotify
)
@Opcodes
(
PacketOpcodes
.
CombatInvocationsNotify
)
public
class
HandlerCombatInvocationsNotify
extends
PacketHandler
{
public
class
HandlerCombatInvocationsNotify
extends
PacketHandler
{
private
float
cachedLandingSpeed
=
0
;
private
long
cachedLandingTimeMillisecond
=
0
;
private
boolean
monitorLandingEvent
=
false
;
@Override
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
CombatInvocationsNotify
notif
=
CombatInvocationsNotify
.
parseFrom
(
payload
);
CombatInvocationsNotify
notif
=
CombatInvocationsNotify
.
parseFrom
(
payload
);
...
@@ -28,7 +38,34 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
...
@@ -28,7 +38,34 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
EntityMoveInfo
moveInfo
=
EntityMoveInfo
.
parseFrom
(
entry
.
getCombatData
());
EntityMoveInfo
moveInfo
=
EntityMoveInfo
.
parseFrom
(
entry
.
getCombatData
());
GameEntity
entity
=
session
.
getPlayer
().
getScene
().
getEntityById
(
moveInfo
.
getEntityId
());
GameEntity
entity
=
session
.
getPlayer
().
getScene
().
getEntityById
(
moveInfo
.
getEntityId
());
if
(
entity
!=
null
)
{
if
(
entity
!=
null
)
{
session
.
getPlayer
().
getMovementManager
().
handle
(
session
,
moveInfo
,
entity
);
// Move player
MotionInfo
motionInfo
=
moveInfo
.
getMotionInfo
();
entity
.
getPosition
().
set
(
motionInfo
.
getPos
());
entity
.
getRotation
().
set
(
motionInfo
.
getRot
());
entity
.
setLastMoveSceneTimeMs
(
moveInfo
.
getSceneTime
());
entity
.
setLastMoveReliableSeq
(
moveInfo
.
getReliableSeq
());
MotionState
motionState
=
motionInfo
.
getState
();
entity
.
setMotionState
(
motionState
);
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.
// MOTION_LAND_SPEED and MOTION_FALL_ON_GROUND arrive in different packets.
// Cache land speed for later use.
if
(
motionState
==
MotionState
.
MOTION_LAND_SPEED
)
{
cachedLandingSpeed
=
motionInfo
.
getSpeed
().
getY
();
cachedLandingTimeMillisecond
=
System
.
currentTimeMillis
();
monitorLandingEvent
=
true
;
}
if
(
monitorLandingEvent
)
{
if
(
motionState
==
MotionState
.
MOTION_FALL_ON_GROUND
)
{
monitorLandingEvent
=
false
;
handleFallOnGround
(
session
,
entity
,
motionState
);
}
}
}
}
break
;
break
;
default
:
default
:
...
@@ -47,5 +84,48 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
...
@@ -47,5 +84,48 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
}
}
}
}
private
void
handleFallOnGround
(
GameSession
session
,
GameEntity
entity
,
MotionState
motionState
)
{
// People have reported that after plunge attack (client sends a FIGHT instead of FALL_ON_GROUND) they will die
// if they talk to an NPC (this is when the client sends a FALL_ON_GROUND) without jumping again.
// A dirty patch: if not received immediately after MOTION_LAND_SPEED, discard this packet.
// 200ms seems to be a reasonable delay.
int
maxDelay
=
200
;
long
actualDelay
=
System
.
currentTimeMillis
()
-
cachedLandingTimeMillisecond
;
Grasscutter
.
getLogger
().
trace
(
"MOTION_FALL_ON_GROUND received after "
+
actualDelay
+
"/"
+
maxDelay
+
"ms."
+
(
actualDelay
>
maxDelay
?
" Discard"
:
""
));
if
(
actualDelay
>
maxDelay
)
{
return
;
}
float
currentHP
=
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
);
float
maxHP
=
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
);
float
damageFactor
=
0
;
if
(
cachedLandingSpeed
<
-
23.5
)
{
damageFactor
=
0.33f
;
}
if
(
cachedLandingSpeed
<
-
25
)
{
damageFactor
=
0.5f
;
}
if
(
cachedLandingSpeed
<
-
26.5
)
{
damageFactor
=
0.66f
;
}
if
(
cachedLandingSpeed
<
-
28
)
{
damageFactor
=
1
f
;
}
float
damage
=
maxHP
*
damageFactor
;
float
newHP
=
currentHP
-
damage
;
if
(
newHP
<
0
)
{
newHP
=
0
;
}
if
(
damageFactor
>
0
)
{
Grasscutter
.
getLogger
().
debug
(
currentHP
+
"/"
+
maxHP
+
"\tLandingSpeed: "
+
cachedLandingSpeed
+
"\tDamageFactor: "
+
damageFactor
+
"\tDamage: "
+
damage
+
"\tNewHP: "
+
newHP
);
}
else
{
Grasscutter
.
getLogger
().
trace
(
currentHP
+
"/"
+
maxHP
+
"\tLandingSpeed: 0\tNo damage"
);
}
entity
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
newHP
);
entity
.
getWorld
().
broadcastPacket
(
new
PacketEntityFightPropUpdateNotify
(
entity
,
FightProperty
.
FIGHT_PROP_CUR_HP
));
if
(
newHP
==
0
)
{
session
.
getPlayer
().
getStaminaManager
().
killAvatar
(
session
,
entity
,
PlayerDieTypeOuterClass
.
PlayerDieType
.
PLAYER_DIE_FALL
);
}
cachedLandingSpeed
=
0
;
}
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerEnterTransPointRegionNotify.java
View file @
219a8508
package
emu.grasscutter.server.packet.recv
;
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.game.managers.SotSManager
.SotSManager
;
import
emu.grasscutter.game.managers.SotSManager
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason
;
import
emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason
;
import
emu.grasscutter.server.game.GameSession
;
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
;
@Opcodes
(
PacketOpcodes
.
EnterTransPointRegionNotify
)
@Opcodes
(
PacketOpcodes
.
EnterTransPointRegionNotify
)
public
class
HandlerEnterTransPointRegionNotify
extends
PacketHandler
{
public
class
HandlerEnterTransPointRegionNotify
extends
PacketHandler
{
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtDoSkillSuccNotify.java
View file @
219a8508
package
emu.grasscutter.server.packet.recv
;
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
...
@@ -15,10 +14,7 @@ public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
...
@@ -15,10 +14,7 @@ public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
EvtDoSkillSuccNotify
notify
=
EvtDoSkillSuccNotify
.
parseFrom
(
payload
);
EvtDoSkillSuccNotify
notify
=
EvtDoSkillSuccNotify
.
parseFrom
(
payload
);
// TODO: Will be used for deducting stamina for charged skills.
// TODO: Will be used for deducting stamina for charged skills.
int
caster
=
notify
.
getCasterId
();
session
.
getPlayer
().
getStaminaManager
().
handleEvtDoSkillSuccNotify
(
session
,
notify
);
int
skillId
=
notify
.
getSkillId
();
session
.
getPlayer
().
getMovementManager
().
notifySkill
(
caster
,
skillId
);
}
}
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerExitTransPointRegionNotify.java
View file @
219a8508
package
emu.grasscutter.server.packet.recv
;
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.game.managers.SotSManager
.SotSManager
;
import
emu.grasscutter.game.managers.SotSManager
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketHandler
;
...
...
src/main/java/emu/grasscutter/tools/Tools.java
View file @
219a8508
...
@@ -13,16 +13,16 @@ import java.io.PrintWriter;
...
@@ -13,16 +13,16 @@ import java.io.PrintWriter;
import
java.nio.charset.StandardCharsets
;
import
java.nio.charset.StandardCharsets
;
import
java.time.LocalDateTime
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
import
java.time.format.DateTimeFormatter
;
import
java.util.ArrayList
;
import
java.util.*
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.stream.Collectors
;
import
java.util.stream.Collectors
;
import
com.google.gson.reflect.TypeToken
;
import
com.google.gson.reflect.TypeToken
;
import
emu.grasscutter.GameConstants
;
import
emu.grasscutter.GameConstants
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.command.Command
;
import
emu.grasscutter.command.CommandHandler
;
import
emu.grasscutter.command.CommandMap
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.ResourceLoader
;
import
emu.grasscutter.data.ResourceLoader
;
import
emu.grasscutter.data.def.AvatarData
;
import
emu.grasscutter.data.def.AvatarData
;
...
@@ -31,6 +31,8 @@ import emu.grasscutter.data.def.MonsterData;
...
@@ -31,6 +31,8 @@ import emu.grasscutter.data.def.MonsterData;
import
emu.grasscutter.data.def.SceneData
;
import
emu.grasscutter.data.def.SceneData
;
import
emu.grasscutter.utils.Utils
;
import
emu.grasscutter.utils.Utils
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
public
final
class
Tools
{
public
final
class
Tools
{
public
static
void
createGmHandbook
()
throws
Exception
{
public
static
void
createGmHandbook
()
throws
Exception
{
ToolsWithLanguageOption
.
createGmHandbook
(
getLanguageOption
());
ToolsWithLanguageOption
.
createGmHandbook
(
getLanguageOption
());
...
@@ -111,7 +113,20 @@ final class ToolsWithLanguageOption {
...
@@ -111,7 +113,20 @@ final class ToolsWithLanguageOption {
writer
.
println
(
"// Grasscutter "
+
GameConstants
.
VERSION
+
" GM Handbook"
);
writer
.
println
(
"// Grasscutter "
+
GameConstants
.
VERSION
+
" GM Handbook"
);
writer
.
println
(
"// Created "
+
dtf
.
format
(
now
)
+
System
.
lineSeparator
()
+
System
.
lineSeparator
());
writer
.
println
(
"// Created "
+
dtf
.
format
(
now
)
+
System
.
lineSeparator
()
+
System
.
lineSeparator
());
CommandMap
cmdMap
=
new
CommandMap
(
true
);
List
<
Command
>
cmdList
=
new
ArrayList
<>(
cmdMap
.
getAnnotationsAsList
());
writer
.
println
(
"// Commands"
);
for
(
Command
cmd
:
cmdList
)
{
String
cmdName
=
cmd
.
label
();
while
(
cmdName
.
length
()
<=
15
)
{
cmdName
=
" "
+
cmdName
;
}
writer
.
println
(
cmdName
+
" : "
+
translate
(
cmd
.
description
()));
}
writer
.
println
();
list
=
new
ArrayList
<>(
GameData
.
getAvatarDataMap
().
keySet
());
list
=
new
ArrayList
<>(
GameData
.
getAvatarDataMap
().
keySet
());
Collections
.
sort
(
list
);
Collections
.
sort
(
list
);
...
...
src/main/java/emu/grasscutter/utils/Language.java
View file @
219a8508
...
@@ -19,7 +19,7 @@ public final class Language {
...
@@ -19,7 +19,7 @@ public final class Language {
* @return A language instance.
* @return A language instance.
*/
*/
public
static
Language
getLanguage
(
String
langCode
)
{
public
static
Language
getLanguage
(
String
langCode
)
{
return
new
Language
(
langCode
+
".json"
);
return
new
Language
(
langCode
+
".json"
,
Grasscutter
.
getConfig
().
DefaultLanguage
.
toLanguageTag
()
);
}
}
/**
/**
...
@@ -30,6 +30,7 @@ public final class Language {
...
@@ -30,6 +30,7 @@ public final class Language {
*/
*/
public
static
String
translate
(
String
key
,
Object
...
args
)
{
public
static
String
translate
(
String
key
,
Object
...
args
)
{
String
translated
=
Grasscutter
.
getLanguage
().
get
(
key
);
String
translated
=
Grasscutter
.
getLanguage
().
get
(
key
);
try
{
try
{
return
translated
.
formatted
(
args
);
return
translated
.
formatted
(
args
);
}
catch
(
Exception
exception
)
{
}
catch
(
Exception
exception
)
{
...
@@ -38,48 +39,27 @@ public final class Language {
...
@@ -38,48 +39,27 @@ public final class Language {
}
}
}
}
/**
* creates a language instance.
* @param fileName The name of the language file.
*/
private
Language
(
String
fileName
)
{
@Nullable
JsonObject
languageData
=
null
;
languageData
=
loadLanguage
(
fileName
);
if
(
languageData
==
null
)
{
Grasscutter
.
getLogger
().
info
(
"Now switch to default language"
);
languageData
=
loadDefaultLanguage
();
}
assert
languageData
!=
null
:
"languageData is null"
;
this
.
languageData
=
languageData
;
}
/**
* Load default language file and creates a language instance.
* @return language data
*/
private
JsonObject
loadDefaultLanguage
()
{
var
fileName
=
Grasscutter
.
getConfig
().
DefaultLanguage
.
toLanguageTag
()
+
".json"
;
return
loadLanguage
(
fileName
);
}
/**
/**
* Reads a file and creates a language instance.
* Reads a file and creates a language instance.
* @param fileName The name of the language file.
* @param fileName The name of the language file.
* @return language data
*/
*/
private
JsonObject
load
Language
(
String
fileName
)
{
private
Language
(
String
fileName
,
String
fallback
)
{
@Nullable
JsonObject
languageData
=
null
;
@Nullable
JsonObject
languageData
=
null
;
try
{
try
{
InputStream
file
=
Grasscutter
.
class
.
getResourceAsStream
(
"/languages/"
+
fileName
);
InputStream
file
=
Grasscutter
.
class
.
getResourceAsStream
(
"/languages/"
+
fileName
);
languageData
=
Grasscutter
.
getGsonFactory
().
fromJson
(
Utils
.
readFromInputStream
(
file
),
JsonObject
.
class
);
String
translationContents
=
Utils
.
readFromInputStream
(
file
);
if
(
translationContents
.
equals
(
"empty"
))
{
file
=
Grasscutter
.
class
.
getResourceAsStream
(
"/languages/"
+
fallback
);
translationContents
=
Utils
.
readFromInputStream
(
file
);
}
languageData
=
Grasscutter
.
getGsonFactory
().
fromJson
(
translationContents
,
JsonObject
.
class
);
}
catch
(
Exception
exception
)
{
}
catch
(
Exception
exception
)
{
Grasscutter
.
getLogger
().
warn
(
"Failed to load language file: "
+
fileName
);
Grasscutter
.
getLogger
().
warn
(
"Failed to load language file: "
+
fileName
,
exception
);
}
}
return
languageData
;
this
.
languageData
=
languageData
;
}
}
/**
/**
...
...
Prev
1
2
3
4
Next
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