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
65861c3c
Commit
65861c3c
authored
May 08, 2022
by
Akka
Committed by
GitHub
May 08, 2022
Browse files
Merge pull request #7 from Grasscutters/development
Development
parents
c2d2a37f
176f3e91
Changes
105
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java
View file @
65861c3c
...
...
@@ -14,6 +14,7 @@ import emu.grasscutter.server.game.GameSession.SessionState;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
@SuppressWarnings
(
"unchecked"
)
public
class
GameServerPacketHandler
{
private
final
Int2ObjectMap
<
PacketHandler
>
handlers
;
...
...
src/main/java/emu/grasscutter/server/game/GameSession.java
View file @
65861c3c
...
...
@@ -22,6 +22,8 @@ import io.netty.buffer.ByteBuf;
import
io.netty.buffer.Unpooled
;
import
io.netty.channel.ChannelHandlerContext
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
public
class
GameSession
extends
KcpChannel
{
private
GameServer
server
;
...
...
@@ -113,21 +115,21 @@ public class GameSession extends KcpChannel {
@Override
protected
void
onConnect
()
{
Grasscutter
.
getLogger
().
info
(
G
ra
sscutter
.
getLanguage
().
Client_connect
.
replace
(
"{address}"
,
getAddress
().
getHostString
().
toLowerCase
()));
Grasscutter
.
getLogger
().
info
(
t
ra
nslate
(
"messages.game.connect"
,
this
.
getAddress
().
getHostString
().
toLowerCase
()));
}
@Override
protected
synchronized
void
onDisconnect
()
{
// Synchronize so we dont add character at the same time
Grasscutter
.
getLogger
().
info
(
G
ra
sscutter
.
getLanguage
().
Client_disconnect
.
replace
(
"{address}"
,
getAddress
().
getHostString
().
toLowerCase
()));
protected
synchronized
void
onDisconnect
()
{
// Synchronize so we don
'
t add character at the same time
.
Grasscutter
.
getLogger
().
info
(
t
ra
nslate
(
"messages.game.disconnect"
,
this
.
getAddress
().
getHostString
().
toLowerCase
()));
// Set state so no more packets can be handled
this
.
setState
(
SessionState
.
INACTIVE
);
// Save after disconnecting
if
(
this
.
isLoggedIn
())
{
//
Save
//
Call logout event.
getPlayer
().
onLogout
();
// Remove from
game
server
// Remove from server
.
getServer
().
getPlayers
().
remove
(
getPlayer
().
getUid
());
}
}
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarExpeditionAllDataReq.java
0 → 100644
View file @
65861c3c
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketAvatarExpeditionAllDataRsp
;
@Opcodes
(
PacketOpcodes
.
AvatarExpeditionAllDataReq
)
public
class
HandlerAvatarExpeditionAllDataReq
extends
PacketHandler
{
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
session
.
send
(
new
PacketAvatarExpeditionAllDataRsp
(
session
.
getPlayer
()));
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarExpeditionCallBackReq.java
0 → 100644
View file @
65861c3c
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.AvatarExpeditionCallBackReqOuterClass.AvatarExpeditionCallBackReq
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketAvatarExpeditionCallBackRsp
;
import
emu.grasscutter.server.packet.send.PacketAvatarExpeditionStartRsp
;
import
emu.grasscutter.utils.Utils
;
@Opcodes
(
PacketOpcodes
.
AvatarExpeditionCallBackReq
)
public
class
HandlerAvatarExpeditionCallBackReq
extends
PacketHandler
{
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
AvatarExpeditionCallBackReq
req
=
AvatarExpeditionCallBackReq
.
parseFrom
(
payload
);
for
(
int
i
=
0
;
i
<
req
.
getAvatarGuidCount
();
i
++)
{
session
.
getPlayer
().
removeExpeditionInfo
(
req
.
getAvatarGuid
(
i
));
}
session
.
getPlayer
().
save
();
session
.
send
(
new
PacketAvatarExpeditionCallBackRsp
(
session
.
getPlayer
()));
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarExpeditionGetRewardReq.java
0 → 100644
View file @
65861c3c
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.drop.DropData
;
import
emu.grasscutter.game.expedition.ExpeditionInfo
;
import
emu.grasscutter.game.expedition.ExpeditionRewardData
;
import
emu.grasscutter.game.expedition.ExpeditionRewardDataList
;
import
emu.grasscutter.game.inventory.GameItem
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.ActionReason
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.AvatarExpeditionGetRewardReqOuterClass.AvatarExpeditionGetRewardReq
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketAvatarExpeditionCallBackRsp
;
import
emu.grasscutter.server.packet.send.PacketAvatarExpeditionGetRewardRsp
;
import
emu.grasscutter.server.packet.send.PacketGadgetInteractRsp
;
import
emu.grasscutter.server.packet.send.PacketItemAddHintNotify
;
import
emu.grasscutter.utils.Utils
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.LinkedList
;
import
java.util.List
;
@Opcodes
(
PacketOpcodes
.
AvatarExpeditionGetRewardReq
)
public
class
HandlerAvatarExpeditionGetRewardReq
extends
PacketHandler
{
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
AvatarExpeditionGetRewardReq
req
=
AvatarExpeditionGetRewardReq
.
parseFrom
(
payload
);
ExpeditionInfo
expInfo
=
session
.
getPlayer
().
getExpeditionInfo
(
req
.
getAvatarGuid
());
List
<
GameItem
>
items
=
new
LinkedList
<>();
if
(
session
.
getServer
().
getExpeditionManager
().
getExpeditionRewardDataList
().
containsKey
(
expInfo
.
getExpId
()))
{
for
(
ExpeditionRewardDataList
RewardDataList
:
session
.
getServer
().
getExpeditionManager
().
getExpeditionRewardDataList
().
get
(
expInfo
.
getExpId
()))
{
if
(
RewardDataList
.
getHourTime
()
==
expInfo
.
getHourTime
()){
if
(!
RewardDataList
.
getExpeditionRewardData
().
isEmpty
()){
for
(
ExpeditionRewardData
RewardData
:
RewardDataList
.
getExpeditionRewardData
())
{
int
num
=
RewardData
.
getMinCount
();
if
(
RewardData
.
getMinCount
()
!=
RewardData
.
getMaxCount
()){
num
=
Utils
.
randomRange
(
RewardData
.
getMinCount
(),
RewardData
.
getMaxCount
());
}
items
.
add
(
new
GameItem
(
RewardData
.
getItemId
(),
num
));
}
}
}
}
}
session
.
getPlayer
().
getInventory
().
addItems
(
items
);
session
.
getPlayer
().
sendPacket
(
new
PacketItemAddHintNotify
(
items
,
ActionReason
.
ExpeditionReward
));
session
.
getPlayer
().
removeExpeditionInfo
(
req
.
getAvatarGuid
());
session
.
getPlayer
().
save
();
session
.
send
(
new
PacketAvatarExpeditionGetRewardRsp
(
session
.
getPlayer
(),
items
));
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarExpeditionStartReq.java
0 → 100644
View file @
65861c3c
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.AvatarExpeditionStartReqOuterClass.AvatarExpeditionStartReq
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketAvatarExpeditionStartRsp
;
import
emu.grasscutter.utils.Utils
;
@Opcodes
(
PacketOpcodes
.
AvatarExpeditionStartReq
)
public
class
HandlerAvatarExpeditionStartReq
extends
PacketHandler
{
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
AvatarExpeditionStartReq
req
=
AvatarExpeditionStartReq
.
parseFrom
(
payload
);
int
startTime
=
Utils
.
getCurrentSeconds
();
session
.
getPlayer
().
addExpeditionInfo
(
req
.
getAvatarGuid
(),
req
.
getExpId
(),
req
.
getHourTime
(),
startTime
);
session
.
getPlayer
().
save
();
session
.
send
(
new
PacketAvatarExpeditionStartRsp
(
session
.
getPlayer
()));
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java
View file @
65861c3c
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.entity.GameEntity
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify
;
...
...
@@ -8,11 +10,19 @@ import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry;
import
emu.grasscutter.net.proto.EntityMoveInfoOuterClass.EntityMoveInfo
;
import
emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.proto.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.packet.send.PacketEntityFightPropUpdateNotify
;
@Opcodes
(
PacketOpcodes
.
CombatInvocationsNotify
)
public
class
HandlerCombatInvocationsNotify
extends
PacketHandler
{
private
float
cachedLandingSpeed
=
0
;
private
long
cachedLandingTimeMillisecond
=
0
;
private
boolean
monitorLandingEvent
=
false
;
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
CombatInvocationsNotify
notif
=
CombatInvocationsNotify
.
parseFrom
(
payload
);
...
...
@@ -28,7 +38,34 @@ public class HandlerCombatInvocationsNotify extends PacketHandler {
EntityMoveInfo
moveInfo
=
EntityMoveInfo
.
parseFrom
(
entry
.
getCombatData
());
GameEntity
entity
=
session
.
getPlayer
().
getScene
().
getEntityById
(
moveInfo
.
getEntityId
());
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
;
default
:
...
...
@@ -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 @
65861c3c
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.props.FightProperty
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
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.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
)
public
class
HandlerEnterTransPointRegionNotify
extends
PacketHandler
{
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerEvtDoSkillSuccNotify.java
View file @
65861c3c
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
...
...
@@ -15,12 +14,7 @@ public class HandlerEvtDoSkillSuccNotify extends PacketHandler {
EvtDoSkillSuccNotify
notify
=
EvtDoSkillSuccNotify
.
parseFrom
(
payload
);
// TODO: Will be used for deducting stamina for charged skills.
int
caster
=
notify
.
getCasterId
();
int
skill
=
notify
.
getSkillId
();
// Grasscutter.getLogger().warn(caster + "\t" + skill);
// session.getPlayer().getScene().broadcastPacket(new PacketEvtAvatarStandUpNotify(notify));
session
.
getPlayer
().
getStaminaManager
().
handleEvtDoSkillSuccNotify
(
session
,
notify
);
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerExitTransPointRegionNotify.java
0 → 100644
View file @
65861c3c
package
emu.grasscutter.server.packet.recv
;
import
emu.grasscutter.game.managers.SotSManager
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.packet.Opcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.server.game.GameSession
;
@Opcodes
(
PacketOpcodes
.
ExitTransPointRegionNotify
)
public
class
HandlerExitTransPointRegionNotify
extends
PacketHandler
{
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
Player
player
=
session
.
getPlayer
();
SotSManager
sotsManager
=
player
.
getSotSManager
();
sotsManager
.
cancelAutoRecover
();
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketAvatarExpeditionAllDataRsp.java
0 → 100644
View file @
65861c3c
package
emu.grasscutter.server.packet.send
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.expedition.ExpeditionInfo
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.AvatarExpeditionAllDataRspOuterClass.AvatarExpeditionAllDataRsp
;
import
emu.grasscutter.net.proto.AvatarExpeditionInfoOuterClass.AvatarExpeditionInfo
;
import
java.util.*
;
public
class
PacketAvatarExpeditionAllDataRsp
extends
BasePacket
{
public
PacketAvatarExpeditionAllDataRsp
(
Player
player
)
{
super
(
PacketOpcodes
.
AvatarExpeditionAllDataRsp
);
List
<
Integer
>
openExpeditionList
=
new
ArrayList
<>(
List
.
of
(
306
,
305
,
304
,
303
,
302
,
301
,
206
,
105
,
204
,
104
,
203
,
103
,
202
,
101
,
102
,
201
,
106
,
205
));
Map
<
Long
,
AvatarExpeditionInfo
>
avatarExpeditionInfoList
=
new
HashMap
<
Long
,
AvatarExpeditionInfo
>();
var
expeditionInfo
=
player
.
getExpeditionInfo
();
for
(
Long
key
:
player
.
getExpeditionInfo
().
keySet
())
{
ExpeditionInfo
e
=
expeditionInfo
.
get
(
key
);
avatarExpeditionInfoList
.
put
(
key
,
AvatarExpeditionInfo
.
newBuilder
().
setStateValue
(
e
.
getState
()).
setExpId
(
e
.
getExpId
()).
setHourTime
(
e
.
getHourTime
()).
setStartTime
(
e
.
getStartTime
()).
build
());
};
AvatarExpeditionAllDataRsp
.
Builder
proto
=
AvatarExpeditionAllDataRsp
.
newBuilder
()
.
addAllOpenExpeditionList
(
openExpeditionList
)
.
setExpeditionCountLimit
(
5
)
.
putAllExpeditionInfoMap
(
avatarExpeditionInfoList
);
this
.
setData
(
proto
.
build
());
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketAvatarExpeditionCallBackRsp.java
0 → 100644
View file @
65861c3c
package
emu.grasscutter.server.packet.send
;
import
emu.grasscutter.game.expedition.ExpeditionInfo
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.AvatarExpeditionCallBackRspOuterClass.AvatarExpeditionCallBackRsp
;
import
emu.grasscutter.net.proto.AvatarExpeditionInfoOuterClass.AvatarExpeditionInfo
;
public
class
PacketAvatarExpeditionCallBackRsp
extends
BasePacket
{
public
PacketAvatarExpeditionCallBackRsp
(
Player
player
)
{
super
(
PacketOpcodes
.
AvatarExpeditionCallBackRsp
);
AvatarExpeditionCallBackRsp
.
Builder
proto
=
AvatarExpeditionCallBackRsp
.
newBuilder
();
var
expeditionInfo
=
player
.
getExpeditionInfo
();
for
(
Long
key
:
player
.
getExpeditionInfo
().
keySet
())
{
ExpeditionInfo
e
=
expeditionInfo
.
get
(
key
);
proto
.
putExpeditionInfoMap
(
key
,
AvatarExpeditionInfo
.
newBuilder
().
setStateValue
(
e
.
getState
()).
setExpId
(
e
.
getExpId
()).
setHourTime
(
e
.
getHourTime
()).
setStartTime
(
e
.
getStartTime
()).
build
());
};
this
.
setData
(
proto
.
build
());
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/server/packet/send/PacketAvatarExpeditionDataNotify.java
0 → 100644
View file @
65861c3c
package
emu.grasscutter.server.packet.send
;
import
emu.grasscutter.game.expedition.ExpeditionInfo
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.AvatarExpeditionDataNotifyOuterClass.AvatarExpeditionDataNotify
;
import
emu.grasscutter.net.proto.AvatarExpeditionInfoOuterClass.AvatarExpeditionInfo
;
import
java.util.*
;
public
class
PacketAvatarExpeditionDataNotify
extends
BasePacket
{
public
PacketAvatarExpeditionDataNotify
(
Player
player
)
{
super
(
PacketOpcodes
.
AvatarExpeditionDataNotify
);
Map
<
Long
,
AvatarExpeditionInfo
>
avatarExpeditionInfoList
=
new
HashMap
<
Long
,
AvatarExpeditionInfo
>();
var
expeditionInfo
=
player
.
getExpeditionInfo
();
for
(
Long
key
:
player
.
getExpeditionInfo
().
keySet
())
{
ExpeditionInfo
e
=
expeditionInfo
.
get
(
key
);
avatarExpeditionInfoList
.
put
(
key
,
AvatarExpeditionInfo
.
newBuilder
().
setStateValue
(
e
.
getState
()).
setExpId
(
e
.
getExpId
()).
setHourTime
(
e
.
getHourTime
()).
setStartTime
(
e
.
getStartTime
()).
build
());
};
AvatarExpeditionDataNotify
.
Builder
proto
=
AvatarExpeditionDataNotify
.
newBuilder
()
.
putAllExpeditionInfoMap
(
avatarExpeditionInfoList
);
this
.
setData
(
proto
.
build
());
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketAvatarExpeditionGetRewardRsp.java
0 → 100644
View file @
65861c3c
package
emu.grasscutter.server.packet.send
;
import
emu.grasscutter.game.expedition.ExpeditionInfo
;
import
emu.grasscutter.game.inventory.GameItem
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.AvatarExpeditionGetRewardRspOuterClass.AvatarExpeditionGetRewardRsp
;
import
emu.grasscutter.net.proto.AvatarExpeditionInfoOuterClass.AvatarExpeditionInfo
;
import
java.util.Collection
;
public
class
PacketAvatarExpeditionGetRewardRsp
extends
BasePacket
{
public
PacketAvatarExpeditionGetRewardRsp
(
Player
player
,
Collection
<
GameItem
>
items
)
{
super
(
PacketOpcodes
.
AvatarExpeditionGetRewardRsp
);
AvatarExpeditionGetRewardRsp
.
Builder
proto
=
AvatarExpeditionGetRewardRsp
.
newBuilder
();
var
expeditionInfo
=
player
.
getExpeditionInfo
();
for
(
Long
key
:
player
.
getExpeditionInfo
().
keySet
())
{
ExpeditionInfo
e
=
expeditionInfo
.
get
(
key
);
proto
.
putExpeditionInfoMap
(
key
,
AvatarExpeditionInfo
.
newBuilder
().
setStateValue
(
e
.
getState
()).
setExpId
(
e
.
getExpId
()).
setHourTime
(
e
.
getHourTime
()).
setStartTime
(
e
.
getStartTime
()).
build
());
};
for
(
GameItem
item
:
items
)
{
proto
.
addItemList
(
item
.
toItemParam
());
}
this
.
setData
(
proto
.
build
());
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketAvatarExpeditionStartRsp.java
0 → 100644
View file @
65861c3c
package
emu.grasscutter.server.packet.send
;
import
emu.grasscutter.game.expedition.ExpeditionInfo
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.AvatarExpeditionInfoOuterClass.AvatarExpeditionInfo
;
import
emu.grasscutter.net.proto.AvatarExpeditionStartRspOuterClass.AvatarExpeditionStartRsp
;
public
class
PacketAvatarExpeditionStartRsp
extends
BasePacket
{
public
PacketAvatarExpeditionStartRsp
(
Player
player
)
{
super
(
PacketOpcodes
.
AvatarExpeditionStartRsp
);
AvatarExpeditionStartRsp
.
Builder
proto
=
AvatarExpeditionStartRsp
.
newBuilder
();
var
expeditionInfo
=
player
.
getExpeditionInfo
();
for
(
Long
key
:
player
.
getExpeditionInfo
().
keySet
())
{
ExpeditionInfo
e
=
expeditionInfo
.
get
(
key
);
proto
.
putExpeditionInfoMap
(
key
,
AvatarExpeditionInfo
.
newBuilder
().
setStateValue
(
e
.
getState
()).
setExpId
(
e
.
getExpId
()).
setHourTime
(
e
.
getHourTime
()).
setStartTime
(
e
.
getStartTime
()).
build
());
};
this
.
setData
(
proto
.
build
());
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketCanUseSkillNotify.java
0 → 100644
View file @
65861c3c
package
emu.grasscutter.server.packet.send
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.CanUseSkillNotifyOuterClass
;
public
class
PacketCanUseSkillNotify
extends
BasePacket
{
public
PacketCanUseSkillNotify
(
boolean
canUseSkill
)
{
super
(
PacketOpcodes
.
CanUseSkillNotify
);
CanUseSkillNotifyOuterClass
.
CanUseSkillNotify
proto
=
CanUseSkillNotifyOuterClass
.
CanUseSkillNotify
.
newBuilder
()
.
setIsCanUseSkill
(
canUseSkill
)
.
build
();
this
.
setData
(
proto
);
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java
View file @
65861c3c
package
emu.grasscutter.server.packet.send
;
import
emu.grasscutter.GameConstants
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.friends.Friendship
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.packet.BasePacket
;
...
...
@@ -18,13 +19,13 @@ public class PacketGetPlayerFriendListRsp extends BasePacket {
FriendBrief
serverFriend
=
FriendBrief
.
newBuilder
()
.
setUid
(
GameConstants
.
SERVER_CONSOLE_UID
)
.
setNickname
(
G
ameConstants
.
SERVER_AVATAR_NAME
)
.
setLevel
(
1
)
.
setProfilePicture
(
ProfilePicture
.
newBuilder
().
setAvatarId
(
G
ameConstants
.
SERVER_AVATAR_ID
))
.
setWorldLevel
(
0
)
.
setSignature
(
""
)
.
setNickname
(
G
rasscutter
.
getConfig
().
getGameServerOptions
().
ServerNickname
)
.
setLevel
(
Grasscutter
.
getConfig
().
getGameServerOptions
().
ServerLevel
)
.
setProfilePicture
(
ProfilePicture
.
newBuilder
().
setAvatarId
(
G
rasscutter
.
getConfig
().
getGameServerOptions
().
ServerAvatarId
))
.
setWorldLevel
(
Grasscutter
.
getConfig
().
getGameServerOptions
().
ServerWorldLevel
)
.
setSignature
(
Grasscutter
.
getConfig
().
getGameServerOptions
().
ServerSignature
)
.
setLastActiveTime
((
int
)
(
System
.
currentTimeMillis
()
/
1000
f
))
.
setNameCardId
(
210001
)
.
setNameCardId
(
Grasscutter
.
getConfig
().
getGameServerOptions
().
ServerNameCardId
)
.
setOnlineState
(
FriendOnlineState
.
FRIEND_ONLINE
)
.
setParam
(
1
)
.
setIsGameSource
(
true
)
...
...
src/main/java/emu/grasscutter/tools/Tools.java
View file @
65861c3c
package
emu.grasscutter.tools
;
import
java.io.BufferedReader
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.io.FileReader
;
import
java.io.FileWriter
;
import
java.io.FilenameFilter
;
import
java.io.InputStreamReader
;
import
java.io.OutputStreamWriter
;
import
java.io.PrintWriter
;
import
java.nio.charset.StandardCharsets
;
import
java.time.LocalDateTime
;
import
java.time.format.DateTimeFormatter
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.*
;
import
java.util.stream.Collectors
;
import
com.google.gson.reflect.TypeToken
;
import
emu.grasscutter.GameConstants
;
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.ResourceLoader
;
import
emu.grasscutter.data.def.AvatarData
;
...
...
@@ -29,14 +31,77 @@ import emu.grasscutter.data.def.MonsterData;
import
emu.grasscutter.data.def.SceneData
;
import
emu.grasscutter.utils.Utils
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
public
final
class
Tools
{
public
static
void
createGmHandbook
()
throws
Exception
{
ToolsWithLanguageOption
.
createGmHandbook
(
getLanguageOption
());
}
public
static
void
createGachaMapping
(
String
location
)
throws
Exception
{
ToolsWithLanguageOption
.
createGachaMapping
(
location
,
getLanguageOption
());
}
public
static
List
<
String
>
getAvailableLanguage
()
throws
Exception
{
File
textMapFolder
=
new
File
(
Grasscutter
.
getConfig
().
RESOURCE_FOLDER
+
"TextMap"
);
List
<
String
>
availableLangList
=
new
ArrayList
<
String
>();
for
(
String
textMapFileName
:
textMapFolder
.
list
(
new
FilenameFilter
()
{
@Override
public
boolean
accept
(
File
dir
,
String
name
)
{
if
(
name
.
startsWith
(
"TextMap"
)
&&
name
.
endsWith
(
".json"
)){
return
true
;
}
return
false
;
}
}))
{
availableLangList
.
add
(
textMapFileName
.
replace
(
"TextMap"
,
""
).
replace
(
".json"
,
""
).
toLowerCase
());
}
return
availableLangList
;
}
public
static
String
getLanguageOption
()
throws
Exception
{
List
<
String
>
availableLangList
=
getAvailableLanguage
();
// Use system out for better format
if
(
availableLangList
.
size
()
==
1
)
{
return
availableLangList
.
get
(
0
).
toUpperCase
();
}
String
stagedMessage
=
""
;
stagedMessage
+=
"The following languages mappings are available, please select one: [default: EN]\n"
;
String
groupedLangList
=
">\t"
;
int
groupedLangCount
=
0
;
String
input
=
""
;
for
(
String
availableLanguage:
availableLangList
){
groupedLangCount
++;
groupedLangList
=
groupedLangList
+
""
+
availableLanguage
+
"\t"
;
if
(
groupedLangCount
==
6
)
{
stagedMessage
+=
groupedLangList
+
"\n"
;
groupedLangCount
=
0
;
groupedLangList
=
">\t"
;
}
}
if
(
groupedLangCount
>
0
)
{
stagedMessage
+=
groupedLangList
+
"\n"
;
}
stagedMessage
+=
"\nYour choice:[EN] "
;
input
=
Grasscutter
.
getConsole
().
readLine
(
stagedMessage
);
if
(
availableLangList
.
contains
(
input
.
toLowerCase
()))
{
return
input
.
toUpperCase
();
}
Grasscutter
.
getLogger
().
info
(
"Invalid option. Will use EN(English) as fallback"
);
return
"EN"
;
}
}
final
class
ToolsWithLanguageOption
{
@SuppressWarnings
(
"deprecation"
)
public
static
void
createGmHandbook
()
throws
Exception
{
public
static
void
createGmHandbook
(
String
language
)
throws
Exception
{
ResourceLoader
.
loadResources
();
Map
<
Long
,
String
>
map
;
try
(
InputStreamReader
fileReader
=
new
InputStreamReader
(
new
FileInputStream
(
Utils
.
toFilePath
(
Grasscutter
.
getConfig
().
RESOURCE_FOLDER
+
"TextMap/TextMap
EN
.json"
)),
StandardCharsets
.
UTF_8
))
{
try
(
InputStreamReader
fileReader
=
new
InputStreamReader
(
new
FileInputStream
(
Utils
.
toFilePath
(
Grasscutter
.
getConfig
().
RESOURCE_FOLDER
+
"TextMap/TextMap
"
+
language
+
"
.json"
)),
StandardCharsets
.
UTF_8
))
{
map
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
new
TypeToken
<
Map
<
Long
,
String
>>()
{}.
getType
());
}
...
...
@@ -48,7 +113,20 @@ public final class Tools {
writer
.
println
(
"// Grasscutter "
+
GameConstants
.
VERSION
+
" GM Handbook"
);
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
());
Collections
.
sort
(
list
);
...
...
@@ -96,11 +174,11 @@ public final class Tools {
}
@SuppressWarnings
(
"deprecation"
)
public
static
void
createGachaMapping
(
String
location
)
throws
Exception
{
public
static
void
createGachaMapping
(
String
location
,
String
language
)
throws
Exception
{
ResourceLoader
.
loadResources
();
Map
<
Long
,
String
>
map
;
try
(
InputStreamReader
fileReader
=
new
InputStreamReader
(
new
FileInputStream
(
Utils
.
toFilePath
(
Grasscutter
.
getConfig
().
RESOURCE_FOLDER
+
"TextMap/TextMap
EN
.json"
)),
StandardCharsets
.
UTF_8
))
{
try
(
InputStreamReader
fileReader
=
new
InputStreamReader
(
new
FileInputStream
(
Utils
.
toFilePath
(
Grasscutter
.
getConfig
().
RESOURCE_FOLDER
+
"TextMap/TextMap
"
+
language
+
"
.json"
)),
StandardCharsets
.
UTF_8
))
{
map
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
new
TypeToken
<
Map
<
Long
,
String
>>()
{}.
getType
());
}
...
...
@@ -113,6 +191,9 @@ public final class Tools {
list
=
new
ArrayList
<>(
GameData
.
getAvatarDataMap
().
keySet
());
Collections
.
sort
(
list
);
// if the user made choices for language, I assume it's okay to assign his/her selected language to "en-us"
// since it's the fallback language and there will be no difference in the gacha record page.
// The enduser can still modify the `gacha_mappings.js` directly to enable multilingual for the gacha record system.
writer
.
println
(
"mappings = {\"en-us\": {"
);
// Avatars
...
...
@@ -140,10 +221,10 @@ public final class Tools {
default
:
color
=
"blue"
;
}
// Got the magic number 4233146695 from manually search in the json file
writer
.
println
(
"\""
+
(
avatarID
%
1000
+
1000
)
+
"\" : [\""
+
map
.
get
(
data
.
getNameTextMapHash
())
+
"(
Avatar
)\", \""
+
map
.
get
(
data
.
getNameTextMapHash
())
+
"(
"
+
map
.
get
(
4233146695L
)+
"
)\", \""
+
color
+
"\"]"
);
}
...
...
@@ -173,13 +254,17 @@ public final class Tools {
default
:
continue
;
// skip unnecessary entries
}
// Got the magic number 4231343903 from manually search in the json file
writer
.
println
(
",\""
+
data
.
getId
()
+
"\" : [\""
+
map
.
get
(
data
.
getNameTextMapHash
()).
replaceAll
(
"\""
,
""
)
+
"(
Weapon
)\",\""
+
color
+
"\"]"
);
+
"(
"
+
map
.
get
(
4231343903L
)+
"
)\",\""
+
color
+
"\"]"
);
}
writer
.
println
(
",\"200\": \"
Standard\", \"301\": \"Avatar Event\", \"302\": \"Weapon event
\""
);
writer
.
println
(
",\"200\": \"
"
+
map
.
get
(
332935371L
)+
"\", \"301\": \""
+
map
.
get
(
2272170627L
)
+
"\", \"302\": \""
+
map
.
get
(
2864268523L
)+
"
\""
);
writer
.
println
(
"}\n}"
);
}
Grasscutter
.
getLogger
().
info
(
"Mappings generated!"
);
Grasscutter
.
getLogger
().
info
(
"Mappings generated to "
+
location
+
" !"
);
}
}
src/main/java/emu/grasscutter/utils/Language.java
0 → 100644
View file @
65861c3c
package
emu.grasscutter.utils
;
import
com.google.gson.JsonElement
;
import
com.google.gson.JsonObject
;
import
emu.grasscutter.Grasscutter
;
import
javax.annotation.Nullable
;
import
java.io.InputStream
;
import
java.util.HashMap
;
import
java.util.Map
;
public
final
class
Language
{
private
final
JsonObject
languageData
;
private
final
Map
<
String
,
String
>
cachedTranslations
=
new
HashMap
<>();
/**
* Creates a language instance from a code.
* @param langCode The language code.
* @return A language instance.
*/
public
static
Language
getLanguage
(
String
langCode
)
{
return
new
Language
(
langCode
+
".json"
,
Grasscutter
.
getConfig
().
DefaultLanguage
.
toLanguageTag
());
}
/**
* Returns the translated value from the key while substituting arguments.
* @param key The key of the translated value to return.
* @param args The arguments to substitute.
* @return A translated value with arguments substituted.
*/
public
static
String
translate
(
String
key
,
Object
...
args
)
{
String
translated
=
Grasscutter
.
getLanguage
().
get
(
key
);
try
{
return
translated
.
formatted
(
args
);
}
catch
(
Exception
exception
)
{
Grasscutter
.
getLogger
().
error
(
"Failed to format string: "
+
key
,
exception
);
return
translated
;
}
}
/**
* Reads a file and creates a language instance.
* @param fileName The name of the language file.
*/
private
Language
(
String
fileName
,
String
fallback
)
{
@Nullable
JsonObject
languageData
=
null
;
try
{
InputStream
file
=
Grasscutter
.
class
.
getResourceAsStream
(
"/languages/"
+
fileName
);
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
)
{
Grasscutter
.
getLogger
().
warn
(
"Failed to load language file: "
+
fileName
,
exception
);
}
this
.
languageData
=
languageData
;
}
/**
* Returns the value (as a string) from a nested key.
* @param key The key to look for.
* @return The value (as a string) from a nested key.
*/
public
String
get
(
String
key
)
{
if
(
this
.
cachedTranslations
.
containsKey
(
key
))
{
return
this
.
cachedTranslations
.
get
(
key
);
}
String
[]
keys
=
key
.
split
(
"\\."
);
JsonObject
object
=
this
.
languageData
;
int
index
=
0
;
String
result
=
"This value does not exist. Please report this to the Discord: "
+
key
;
while
(
true
)
{
if
(
index
==
keys
.
length
)
break
;
String
currentKey
=
keys
[
index
++];
if
(
object
.
has
(
currentKey
))
{
JsonElement
element
=
object
.
get
(
currentKey
);
if
(
element
.
isJsonObject
())
object
=
element
.
getAsJsonObject
();
else
{
result
=
element
.
getAsString
();
break
;
}
}
else
break
;
}
this
.
cachedTranslations
.
put
(
key
,
result
);
return
result
;
}
}
src/main/java/emu/grasscutter/utils/Utils.java
View file @
65861c3c
package
emu.grasscutter.utils
;
import
java.io.*
;
import
java.nio.charset.StandardCharsets
;
import
java.nio.file.Files
;
import
java.nio.file.StandardCopyOption
;
import
java.time.*
;
import
java.time.temporal.TemporalAdjusters
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Random
;
import
emu.grasscutter.Config
;
...
...
@@ -15,6 +18,10 @@ import io.netty.buffer.Unpooled;
import
org.slf4j.Logger
;
import
javax.annotation.Nullable
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
@SuppressWarnings
({
"UnusedReturnValue"
,
"BooleanMethodIsAlwaysInverted"
})
public
final
class
Utils
{
public
static
final
Random
random
=
new
Random
();
...
...
@@ -176,15 +183,15 @@ public final class Utils {
// Check for resources folder.
if
(!
fileExists
(
resourcesFolder
))
{
logger
.
info
(
G
ra
sscutter
.
getLanguage
().
C
reate_resources
_folder
);
logger
.
info
(
G
ra
sscutter
.
getLanguage
().
Place_copy
);
logger
.
info
(
t
ra
nslate
(
"messages.status.c
reate_resources
"
)
);
logger
.
info
(
t
ra
nslate
(
"messages.status.resources_error"
)
);
createFolder
(
resourcesFolder
);
exit
=
true
;
}
// Check for BinOutput + ExcelBinOuput.
// Check for BinOutput + ExcelBinOu
t
put.
if
(!
fileExists
(
resourcesFolder
+
"BinOutput"
)
||
!
fileExists
(
resourcesFolder
+
"ExcelBinOutput"
))
{
logger
.
info
(
G
ra
sscutter
.
getLanguage
().
Place_copy
);
logger
.
info
(
t
ra
nslate
(
"messages.status.resources_error"
)
);
exit
=
true
;
}
...
...
@@ -195,7 +202,11 @@ public final class Utils {
if
(
exit
)
System
.
exit
(
1
);
}
public
static
int
GetNextTimestampOfThisHour
(
int
hour
,
String
timeZone
,
int
param
)
{
/**
* Gets the timestamp of the next hour.
* @return The timestamp in UNIX seconds.
*/
public
static
int
getNextTimestampOfThisHour
(
int
hour
,
String
timeZone
,
int
param
)
{
ZonedDateTime
zonedDateTime
=
ZonedDateTime
.
now
(
ZoneId
.
of
(
timeZone
));
for
(
int
i
=
0
;
i
<
param
;
i
++){
if
(
zonedDateTime
.
getHour
()
<
hour
)
{
...
...
@@ -204,10 +215,14 @@ public final class Utils {
zonedDateTime
=
zonedDateTime
.
plusDays
(
1
).
withHour
(
hour
).
withMinute
(
0
).
withSecond
(
0
);
}
}
return
(
int
)
zonedDateTime
.
toInstant
().
atZone
(
ZoneOffset
.
UTC
).
toEpochSecond
();
return
(
int
)
zonedDateTime
.
toInstant
().
atZone
(
ZoneOffset
.
UTC
).
toEpochSecond
();
}
public
static
int
GetNextTimestampOfThisHourInNextWeek
(
int
hour
,
String
timeZone
,
int
param
)
{
/**
* Gets the timestamp of the next hour in a week.
* @return The timestamp in UNIX seconds.
*/
public
static
int
getNextTimestampOfThisHourInNextWeek
(
int
hour
,
String
timeZone
,
int
param
)
{
ZonedDateTime
zonedDateTime
=
ZonedDateTime
.
now
(
ZoneId
.
of
(
timeZone
));
for
(
int
i
=
0
;
i
<
param
;
i
++)
{
if
(
zonedDateTime
.
getDayOfWeek
()
==
DayOfWeek
.
MONDAY
&&
zonedDateTime
.
getHour
()
<
hour
)
{
...
...
@@ -216,10 +231,14 @@ public final class Utils {
zonedDateTime
=
zonedDateTime
.
with
(
TemporalAdjusters
.
next
(
DayOfWeek
.
MONDAY
)).
withHour
(
hour
).
withMinute
(
0
).
withSecond
(
0
);
}
}
return
(
int
)
zonedDateTime
.
toInstant
().
atZone
(
ZoneOffset
.
UTC
).
toEpochSecond
();
return
(
int
)
zonedDateTime
.
toInstant
().
atZone
(
ZoneOffset
.
UTC
).
toEpochSecond
();
}
public
static
int
GetNextTimestampOfThisHourInNextMonth
(
int
hour
,
String
timeZone
,
int
param
)
{
/**
* Gets the timestamp of the next hour in a month.
* @return The timestamp in UNIX seconds.
*/
public
static
int
getNextTimestampOfThisHourInNextMonth
(
int
hour
,
String
timeZone
,
int
param
)
{
ZonedDateTime
zonedDateTime
=
ZonedDateTime
.
now
(
ZoneId
.
of
(
timeZone
));
for
(
int
i
=
0
;
i
<
param
;
i
++)
{
if
(
zonedDateTime
.
getDayOfMonth
()
==
1
&&
zonedDateTime
.
getHour
()
<
hour
)
{
...
...
@@ -228,6 +247,63 @@ public final class Utils {
zonedDateTime
=
zonedDateTime
.
with
(
TemporalAdjusters
.
firstDayOfNextMonth
()).
withHour
(
hour
).
withMinute
(
0
).
withSecond
(
0
);
}
}
return
(
int
)
zonedDateTime
.
toInstant
().
atZone
(
ZoneOffset
.
UTC
).
toEpochSecond
();
return
(
int
)
zonedDateTime
.
toInstant
().
atZone
(
ZoneOffset
.
UTC
).
toEpochSecond
();
}
/**
* Retrieves a string from an input stream.
* @param stream The input stream.
* @return The string.
*/
public
static
String
readFromInputStream
(
@Nullable
InputStream
stream
)
{
if
(
stream
==
null
)
return
"empty"
;
StringBuilder
stringBuilder
=
new
StringBuilder
();
try
(
BufferedReader
reader
=
new
BufferedReader
(
new
InputStreamReader
(
stream
,
StandardCharsets
.
UTF_8
)))
{
String
line
;
while
((
line
=
reader
.
readLine
())
!=
null
)
{
stringBuilder
.
append
(
line
);
}
stream
.
close
();
}
catch
(
IOException
e
)
{
Grasscutter
.
getLogger
().
warn
(
"Failed to read from input stream."
);
}
catch
(
NullPointerException
ignored
)
{
return
"empty"
;
}
return
stringBuilder
.
toString
();
}
/**
* Switch properties from upper case to lower case?
*/
public
static
Map
<
String
,
Object
>
switchPropertiesUpperLowerCase
(
Map
<
String
,
Object
>
objMap
,
Class
<?>
cls
)
{
Map
<
String
,
Object
>
map
=
new
HashMap
<>(
objMap
.
size
());
for
(
String
key
:
objMap
.
keySet
())
{
try
{
char
c
=
key
.
charAt
(
0
);
if
(
c
>=
'a'
&&
c
<=
'z'
)
{
try
{
cls
.
getDeclaredField
(
key
);
map
.
put
(
key
,
objMap
.
get
(
key
));
}
catch
(
NoSuchFieldException
e
)
{
String
s1
=
String
.
valueOf
(
c
).
toUpperCase
();
String
after
=
key
.
length
()
>
1
?
s1
+
key
.
substring
(
1
)
:
s1
;
cls
.
getDeclaredField
(
after
);
map
.
put
(
after
,
objMap
.
get
(
key
));
}
}
else
if
(
c
>=
'A'
&&
c
<=
'Z'
)
{
try
{
cls
.
getDeclaredField
(
key
);
map
.
put
(
key
,
objMap
.
get
(
key
));
}
catch
(
NoSuchFieldException
e
)
{
String
s1
=
String
.
valueOf
(
c
).
toLowerCase
();
String
after
=
key
.
length
()
>
1
?
s1
+
key
.
substring
(
1
)
:
s1
;
cls
.
getDeclaredField
(
after
);
map
.
put
(
after
,
objMap
.
get
(
key
));
}
}
}
catch
(
NoSuchFieldException
e
)
{
map
.
put
(
key
,
objMap
.
get
(
key
));
}
}
return
map
;
}
}
Prev
1
2
3
4
5
6
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