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
584aec58
Commit
584aec58
authored
Jun 15, 2022
by
loulou310
Committed by
GitHub
Jun 15, 2022
Browse files
Merge branch 'Grasscutters:development' into development
parents
8c8f3887
c056ad5c
Changes
19
Expand all
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
584aec58
...
...
@@ -28,7 +28,7 @@ EN | [中文](README_zh-CN.md) | [FR](README_fr-FR.md)
**Note:**
If you just want to
**run it**
, then
**jre**
only is fine.
*
MongoDB (recommended 4.0+)
*
[
MongoDB
](
https://www.mongodb.com/try/download/community
)
(
recommended
4.0+)
*
Proxy daemon: mitmproxy (mitmdump, recommended), Fiddler Classic, etc.
...
...
README_zh-CN.md
View file @
584aec58
...
...
@@ -28,7 +28,7 @@
**注:**
如果您仅仅想要简单地
**运行服务端**
, 那么使用
**jre**
便足够了
*
MongoDB (推荐 4.0+)
*
[
MongoDB
](
https://fastdl.mongodb.org/windows/mongodb-windows-x86_64-5.0.9-signed.msi
)
(
推荐
4.0+)
*
Proxy daemon: mitmproxy (推荐使用mitmdump), Fiddler Classic, 等
...
...
lib/kcp-netty-1.5.0.jar
deleted
100644 → 0
View file @
8c8f3887
File deleted
lib/kcp.jar
0 → 100644
View file @
584aec58
File added
src/main/java/emu/grasscutter/database/DatabaseHelper.java
View file @
584aec58
...
...
@@ -83,33 +83,33 @@ public final class DatabaseHelper {
}
public
static
Account
getAccountByName
(
String
username
)
{
return
DatabaseManager
.
get
Game
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"username"
,
username
)).
first
();
return
DatabaseManager
.
get
Account
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"username"
,
username
)).
first
();
}
public
static
Account
getAccountByToken
(
String
token
)
{
if
(
token
==
null
)
return
null
;
return
DatabaseManager
.
get
Game
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"token"
,
token
)).
first
();
return
DatabaseManager
.
get
Account
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"token"
,
token
)).
first
();
}
public
static
Account
getAccountBySessionKey
(
String
sessionKey
)
{
if
(
sessionKey
==
null
)
return
null
;
return
DatabaseManager
.
get
Game
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"sessionKey"
,
sessionKey
)).
first
();
return
DatabaseManager
.
get
Account
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"sessionKey"
,
sessionKey
)).
first
();
}
public
static
Account
getAccountById
(
String
uid
)
{
return
DatabaseManager
.
get
Game
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"_id"
,
uid
)).
first
();
return
DatabaseManager
.
get
Account
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"_id"
,
uid
)).
first
();
}
public
static
Account
getAccountByPlayerId
(
int
playerId
)
{
return
DatabaseManager
.
get
Game
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"reservedPlayerId"
,
playerId
)).
first
();
return
DatabaseManager
.
get
Account
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"reservedPlayerId"
,
playerId
)).
first
();
}
public
static
boolean
checkIfAccountExists
(
String
name
)
{
return
DatabaseManager
.
get
Game
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"username"
,
name
)).
count
()
>
0
;
return
DatabaseManager
.
get
Account
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"username"
,
name
)).
count
()
>
0
;
}
public
static
boolean
checkIfAccountExists
(
int
reservedUid
)
{
return
DatabaseManager
.
get
Game
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"reservedPlayerId"
,
reservedUid
)).
count
()
>
0
;
return
DatabaseManager
.
get
Account
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"reservedPlayerId"
,
reservedUid
)).
count
()
>
0
;
}
public
static
void
deleteAccount
(
Account
target
)
{
...
...
@@ -141,7 +141,7 @@ public final class DatabaseHelper {
}
// Finally, delete the account itself.
DatabaseManager
.
get
Game
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"id"
,
target
.
getId
())).
delete
();
DatabaseManager
.
get
Account
Datastore
().
find
(
Account
.
class
).
filter
(
Filters
.
eq
(
"id"
,
target
.
getId
())).
delete
();
}
public
static
List
<
Player
>
getAllPlayers
()
{
...
...
src/main/java/emu/grasscutter/game/entity/EntityAvatar.java
View file @
584aec58
...
...
@@ -16,6 +16,7 @@ import emu.grasscutter.net.proto.AbilityControlBlockOuterClass.AbilityControlBlo
import
emu.grasscutter.net.proto.AbilityEmbryoOuterClass.AbilityEmbryo
;
import
emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo
;
import
emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair
;
import
emu.grasscutter.net.proto.ChangeEnergyReasonOuterClass.ChangeEnergyReason
;
import
emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason
;
import
emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo
;
import
emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData
;
...
...
@@ -31,6 +32,7 @@ import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify
;
import
emu.grasscutter.utils.Position
;
import
emu.grasscutter.utils.ProtoHelper
;
import
emu.grasscutter.utils.Utils
;
...
...
@@ -108,13 +110,13 @@ public class EntityAvatar extends GameEntity {
public
void
onDeath
(
int
killerId
)
{
this
.
killedType
=
PlayerDieType
.
PLAYER_DIE_TYPE_KILL_BY_MONSTER
;
this
.
killedBy
=
killerId
;
clearEnergy
(
Prop
ChangeReason
.
PROP_
CHANGE_
REASON_STATUE_RECOVER
);
clearEnergy
(
Change
Energy
Reason
.
CHANGE_
ENERGY_REASON_NONE
);
}
public
void
onDeath
(
PlayerDieType
dieType
,
int
killerId
)
{
this
.
killedType
=
dieType
;
this
.
killedBy
=
killerId
;
clearEnergy
(
Prop
ChangeReason
.
PROP_
CHANGE_
REASON_STATUE_RECOVER
);
clearEnergy
(
Change
Energy
Reason
.
CHANGE_
ENERGY_REASON_NONE
);
}
@Override
...
...
@@ -130,14 +132,25 @@ public class EntityAvatar extends GameEntity {
return
healed
;
}
public
void
clearEnergy
(
PropChangeReason
reason
)
{
public
void
clearEnergy
(
ChangeEnergyReason
reason
)
{
// Fight props.
FightProperty
curEnergyProp
=
this
.
getAvatar
().
getSkillDepot
().
getElementType
().
getCurEnergyProp
();
FightProperty
maxEnergyProp
=
this
.
getAvatar
().
getSkillDepot
().
getElementType
().
getMaxEnergyProp
();
// Get max energy.
float
maxEnergy
=
this
.
avatar
.
getFightProperty
(
maxEnergyProp
);
// Set energy to zero.
this
.
avatar
.
setCurrentEnergy
(
curEnergyProp
,
0
);
this
.
getScene
().
broadcastPacket
(
new
PacketAvatarFightPropUpdateNotify
(
this
.
getAvatar
(),
curEnergyProp
));
this
.
getScene
().
broadcastPacket
(
new
PacketEntityFightPropChangeReasonNotify
(
this
,
curEnergyProp
,
0
f
,
reason
));
}
// Send packets.
this
.
getScene
().
broadcastPacket
(
new
PacketEntityFightPropUpdateNotify
(
this
,
curEnergyProp
));
if
(
reason
==
ChangeEnergyReason
.
CHANGE_ENERGY_REASON_SKILL_START
)
{
this
.
getScene
().
broadcastPacket
(
new
PacketEntityFightPropChangeReasonNotify
(
this
,
curEnergyProp
,
-
maxEnergy
,
reason
));
}
}
public
void
addEnergy
(
float
amount
,
PropChangeReason
reason
)
{
this
.
addEnergy
(
amount
,
reason
,
false
);
}
...
...
src/main/java/emu/grasscutter/game/gacha/GachaManager.java
View file @
584aec58
...
...
@@ -31,6 +31,7 @@ import emu.grasscutter.net.proto.GachaItemOuterClass.GachaItem;
import
emu.grasscutter.net.proto.GachaTransferItemOuterClass.GachaTransferItem
;
import
emu.grasscutter.net.proto.GetGachaInfoRspOuterClass.GetGachaInfoRsp
;
import
emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam
;
import
emu.grasscutter.net.proto.RetcodeOuterClass.Retcode
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.game.GameServerTickEvent
;
import
emu.grasscutter.server.packet.send.PacketDoGachaRsp
;
...
...
@@ -244,7 +245,7 @@ public class GachaManager {
}
Inventory
inventory
=
player
.
getInventory
();
if
(
inventory
.
getInventoryTab
(
ItemType
.
ITEM_WEAPON
).
getSize
()
+
times
>
inventory
.
getInventoryTab
(
ItemType
.
ITEM_WEAPON
).
getMaxCapacity
())
{
player
.
sendPacket
(
new
PacketDoGachaRsp
());
player
.
sendPacket
(
new
PacketDoGachaRsp
(
Retcode
.
RET_ITEM_EXCEED_LIMIT
));
return
;
}
...
...
src/main/java/emu/grasscutter/game/managers/EnergyManager/EnergyManager.java
View file @
584aec58
...
...
@@ -22,6 +22,7 @@ import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.Ability
import
emu.grasscutter.net.proto.AbilityIdentifierOuterClass.AbilityIdentifier
;
import
emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry
;
import
emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult
;
import
emu.grasscutter.net.proto.ChangeEnergyReasonOuterClass.ChangeEnergyReason
;
import
emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo
;
import
emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason
;
import
emu.grasscutter.server.game.GameSession
;
...
...
@@ -334,7 +335,7 @@ public class EnergyManager {
// If the cast skill was a burst, consume energy.
if
(
avatar
.
getSkillDepot
()
!=
null
&&
skillId
==
avatar
.
getSkillDepot
().
getEnergySkill
())
{
avatar
.
getAsEntity
().
clearEnergy
(
Prop
ChangeReason
.
PROP_
CHANGE_
REASON_ABILITY
);
avatar
.
getAsEntity
().
clearEnergy
(
Change
Energy
Reason
.
CHANGE_
ENERGY_REASON_SKILL_START
);
}
}
...
...
src/main/java/emu/grasscutter/netty/KcpChannel.java
deleted
100644 → 0
View file @
8c8f3887
package
emu.grasscutter.netty
;
import
emu.grasscutter.Grasscutter
;
import
io.jpower.kcp.netty.UkcpChannel
;
import
io.netty.buffer.ByteBuf
;
import
io.netty.buffer.ByteBufUtil
;
import
io.netty.buffer.Unpooled
;
import
io.netty.channel.ChannelHandlerContext
;
import
io.netty.channel.ChannelInboundHandlerAdapter
;
public
abstract
class
KcpChannel
extends
ChannelInboundHandlerAdapter
{
private
UkcpChannel
kcpChannel
;
private
ChannelHandlerContext
ctx
;
private
boolean
isActive
;
public
UkcpChannel
getChannel
()
{
return
kcpChannel
;
}
public
boolean
isActive
()
{
return
this
.
isActive
;
}
@Override
public
void
channelActive
(
ChannelHandlerContext
ctx
)
throws
Exception
{
this
.
kcpChannel
=
(
UkcpChannel
)
ctx
.
channel
();
this
.
ctx
=
ctx
;
this
.
isActive
=
true
;
this
.
onConnect
();
}
@Override
public
void
channelInactive
(
ChannelHandlerContext
ctx
)
throws
Exception
{
this
.
isActive
=
false
;
this
.
onDisconnect
();
}
@Override
public
void
channelRead
(
ChannelHandlerContext
ctx
,
Object
msg
)
{
ByteBuf
data
=
(
ByteBuf
)
msg
;
onMessage
(
ctx
,
data
);
}
@Override
public
void
channelReadComplete
(
ChannelHandlerContext
ctx
)
{
ctx
.
flush
();
}
@Override
public
void
exceptionCaught
(
ChannelHandlerContext
ctx
,
Throwable
cause
)
{
cause
.
printStackTrace
();
close
();
}
protected
void
send
(
byte
[]
data
)
{
if
(!
isActive
())
{
return
;
}
ByteBuf
packet
=
Unpooled
.
wrappedBuffer
(
data
);
kcpChannel
.
writeAndFlush
(
packet
);
}
public
void
close
()
{
if
(
getChannel
()
!=
null
)
{
getChannel
().
close
();
}
}
/*
protected void logPacket(ByteBuffer buf) {
ByteBuf b = Unpooled.wrappedBuffer(buf.array());
logPacket(b);
}
*/
protected
void
logPacket
(
ByteBuf
buf
)
{
Grasscutter
.
getLogger
().
info
(
"Received: \n"
+
ByteBufUtil
.
prettyHexDump
(
buf
));
}
// Events
protected
abstract
void
onConnect
();
protected
abstract
void
onDisconnect
();
public
abstract
void
onMessage
(
ChannelHandlerContext
ctx
,
ByteBuf
data
);
}
src/main/java/emu/grasscutter/netty/KcpHandshaker.java
deleted
100644 → 0
View file @
8c8f3887
package
emu.grasscutter.netty
;
import
java.net.SocketAddress
;
import
java.nio.channels.SelectableChannel
;
import
java.util.List
;
import
io.netty.channel.Channel
;
import
io.netty.channel.ChannelConfig
;
import
io.netty.channel.ChannelMetadata
;
import
io.netty.channel.ChannelOutboundBuffer
;
import
io.netty.channel.nio.AbstractNioMessageChannel
;
public
class
KcpHandshaker
extends
AbstractNioMessageChannel
{
protected
KcpHandshaker
(
Channel
parent
,
SelectableChannel
ch
,
int
readInterestOp
)
{
super
(
parent
,
ch
,
readInterestOp
);
}
@Override
public
ChannelConfig
config
()
{
// TODO Auto-generated method stub
return
null
;
}
@Override
public
boolean
isActive
()
{
// TODO Auto-generated method stub
return
false
;
}
@Override
public
ChannelMetadata
metadata
()
{
// TODO Auto-generated method stub
return
null
;
}
@Override
protected
int
doReadMessages
(
List
<
Object
>
buf
)
throws
Exception
{
// TODO Auto-generated method stub
return
0
;
}
@Override
protected
boolean
doWriteMessage
(
Object
msg
,
ChannelOutboundBuffer
in
)
throws
Exception
{
// TODO Auto-generated method stub
return
false
;
}
@Override
protected
boolean
doConnect
(
SocketAddress
remoteAddress
,
SocketAddress
localAddress
)
throws
Exception
{
// TODO Auto-generated method stub
return
false
;
}
@Override
protected
void
doFinishConnect
()
throws
Exception
{
// TODO Auto-generated method stub
}
@Override
protected
SocketAddress
localAddress0
()
{
// TODO Auto-generated method stub
return
null
;
}
@Override
protected
SocketAddress
remoteAddress0
()
{
// TODO Auto-generated method stub
return
null
;
}
@Override
protected
void
doBind
(
SocketAddress
localAddress
)
throws
Exception
{
// TODO Auto-generated method stub
}
@Override
protected
void
doDisconnect
()
throws
Exception
{
// TODO Auto-generated method stub
}
}
src/main/java/emu/grasscutter/netty/KcpServer.java
deleted
100644 → 0
View file @
8c8f3887
package
emu.grasscutter.netty
;
import
java.net.InetSocketAddress
;
import
emu.grasscutter.Grasscutter
;
import
io.jpower.kcp.netty.ChannelOptionHelper
;
import
io.jpower.kcp.netty.UkcpChannelOption
;
import
io.jpower.kcp.netty.UkcpServerChannel
;
import
io.netty.bootstrap.UkcpServerBootstrap
;
import
io.netty.channel.ChannelFuture
;
import
io.netty.channel.ChannelInitializer
;
import
io.netty.channel.EventLoopGroup
;
import
io.netty.channel.nio.NioEventLoopGroup
;
@SuppressWarnings
(
"rawtypes"
)
public
class
KcpServer
extends
Thread
{
private
EventLoopGroup
group
;
private
UkcpServerBootstrap
bootstrap
;
private
ChannelInitializer
serverInitializer
;
private
InetSocketAddress
address
;
public
KcpServer
(
InetSocketAddress
address
)
{
this
.
address
=
address
;
this
.
setName
(
"Netty Server Thread"
);
}
public
InetSocketAddress
getAddress
()
{
return
this
.
address
;
}
public
ChannelInitializer
getServerInitializer
()
{
return
serverInitializer
;
}
public
void
setServerInitializer
(
ChannelInitializer
serverInitializer
)
{
this
.
serverInitializer
=
serverInitializer
;
}
@Override
public
void
run
()
{
if
(
getServerInitializer
()
==
null
)
{
this
.
setServerInitializer
(
new
KcpServerInitializer
());
}
try
{
group
=
new
NioEventLoopGroup
();
bootstrap
=
new
UkcpServerBootstrap
();
bootstrap
.
group
(
group
)
.
channel
(
UkcpServerChannel
.
class
)
.
childHandler
(
this
.
getServerInitializer
());
ChannelOptionHelper
.
nodelay
(
bootstrap
,
true
,
20
,
2
,
true
)
.
childOption
(
UkcpChannelOption
.
UKCP_MTU
,
1200
);
// Start handler
this
.
onStart
();
// Start the server.
ChannelFuture
f
=
bootstrap
.
bind
(
getAddress
()).
sync
();
// Start finish handler
this
.
onStartFinish
();
// Wait until the server socket is closed.
f
.
channel
().
closeFuture
().
sync
();
}
catch
(
Exception
exception
)
{
Grasscutter
.
getLogger
().
error
(
"Unable to start game server."
,
exception
);
}
finally
{
// Close
finish
();
}
}
public
void
onStart
()
{
}
public
void
onStartFinish
()
{
}
private
void
finish
()
{
try
{
group
.
shutdownGracefully
();
}
catch
(
Exception
e
)
{
}
Grasscutter
.
getLogger
().
info
(
"Game Server closed"
);
}
}
src/main/java/emu/grasscutter/netty/KcpServerInitializer.java
deleted
100644 → 0
View file @
8c8f3887
package
emu.grasscutter.netty
;
import
io.jpower.kcp.netty.UkcpChannel
;
import
io.netty.channel.ChannelInitializer
;
import
io.netty.channel.ChannelPipeline
;
@SuppressWarnings
(
"unused"
)
public
class
KcpServerInitializer
extends
ChannelInitializer
<
UkcpChannel
>
{
@Override
protected
void
initChannel
(
UkcpChannel
ch
)
throws
Exception
{
ChannelPipeline
pipeline
=
ch
.
pipeline
();
}
}
src/main/java/emu/grasscutter/server/game/GameServer.java
View file @
584aec58
...
...
@@ -21,13 +21,13 @@ import emu.grasscutter.game.tower.TowerScheduleManager;
import
emu.grasscutter.game.world.World
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail
;
import
emu.grasscutter.netty.KcpServer
;
import
emu.grasscutter.server.event.types.ServerEvent
;
import
emu.grasscutter.server.event.game.ServerTickEvent
;
import
emu.grasscutter.server.event.internal.ServerStartEvent
;
import
emu.grasscutter.server.event.internal.ServerStopEvent
;
import
emu.grasscutter.task.TaskMap
;
import
emu.grasscutter.BuildConfig
;
import
kcp.highway.ChannelConfig
;
import
kcp.highway.KcpServer
;
import
java.net.InetSocketAddress
;
import
java.time.OffsetDateTime
;
...
...
@@ -60,7 +60,7 @@ public final class GameServer extends KcpServer {
private
final
TowerScheduleManager
towerScheduleManager
;
private
static
InetSocketAddress
getAdapterInetSocketAddress
(){
InetSocketAddress
inetSocketAddress
=
null
;
InetSocketAddress
inetSocketAddress
;
if
(
GAME_INFO
.
bindAddress
.
equals
(
""
)){
inetSocketAddress
=
new
InetSocketAddress
(
GAME_INFO
.
bindPort
);
}
else
{
...
...
@@ -75,9 +75,17 @@ public final class GameServer extends KcpServer {
this
(
getAdapterInetSocketAddress
());
}
public
GameServer
(
InetSocketAddress
address
)
{
super
(
address
);
ChannelConfig
channelConfig
=
new
ChannelConfig
();
channelConfig
.
nodelay
(
true
,
40
,
2
,
true
);
channelConfig
.
setMtu
(
1400
);
channelConfig
.
setSndwnd
(
256
);
channelConfig
.
setRcvwnd
(
256
);
channelConfig
.
setTimeoutMillis
(
30
*
1000
);
//30s
channelConfig
.
setUseConvChannel
(
true
);
channelConfig
.
setAckNoDelay
(
false
);
this
.
init
(
GameSessionManager
.
getListener
(),
channelConfig
,
address
);
this
.
setServerInitializer
(
new
GameServerInitializer
(
this
));
this
.
address
=
address
;
this
.
packetHandler
=
new
GameServerPacketHandler
(
PacketHandler
.
class
);
this
.
questHandler
=
new
ServerQuestHandler
();
...
...
@@ -96,6 +104,7 @@ public final class GameServer extends KcpServer {
this
.
expeditionManager
=
new
ExpeditionManager
(
this
);
this
.
combineManger
=
new
CombineManger
(
this
);
this
.
towerScheduleManager
=
new
TowerScheduleManager
(
this
);
// Hook into shutdown event.
Runtime
.
getRuntime
().
addShutdownHook
(
new
Thread
(
this
::
onServerShutdown
));
}
...
...
@@ -164,6 +173,7 @@ public final class GameServer extends KcpServer {
return
towerScheduleManager
;
}
public
TaskMap
getTaskMap
()
{
return
this
.
taskMap
;
}
...
...
@@ -220,23 +230,23 @@ public final class GameServer extends KcpServer {
}
return
DatabaseHelper
.
getAccountByName
(
username
);
}
public
void
onTick
()
throws
Exception
{
public
synchronized
void
onTick
(){
Iterator
<
World
>
it
=
this
.
getWorlds
().
iterator
();
while
(
it
.
hasNext
())
{
World
world
=
it
.
next
();
if
(
world
.
getPlayerCount
()
==
0
)
{
it
.
remove
();
}
world
.
onTick
();
}
for
(
Player
player
:
this
.
getPlayers
().
values
())
{
player
.
onTick
();
}
ServerTickEvent
event
=
new
ServerTickEvent
();
event
.
call
();
}
...
...
@@ -249,8 +259,7 @@ public final class GameServer extends KcpServer {
}
@Override
public
synchronized
void
start
()
{
public
void
start
()
{
// Schedule game loop.
Timer
gameLoop
=
new
Timer
();
gameLoop
.
scheduleAtFixedRate
(
new
TimerTask
()
{
...
...
@@ -263,24 +272,19 @@ public final class GameServer extends KcpServer {
}
}
},
new
Date
(),
1000L
);
super
.
start
();
}
@Override
public
void
onStartFinish
()
{
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.status.free_software"
));
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.game.port_bind"
,
Integer
.
toString
(
address
.
getPort
())));
ServerStartEvent
event
=
new
ServerStartEvent
(
ServerEvent
.
Type
.
GAME
,
OffsetDateTime
.
now
());
event
.
call
();
ServerStartEvent
event
=
new
ServerStartEvent
(
ServerEvent
.
Type
.
GAME
,
OffsetDateTime
.
now
());
event
.
call
();
}
public
void
onServerShutdown
()
{
ServerStopEvent
event
=
new
ServerStopEvent
(
ServerEvent
.
Type
.
GAME
,
OffsetDateTime
.
now
());
event
.
call
();
// Kick and save all players
List
<
Player
>
list
=
new
ArrayList
<>(
this
.
getPlayers
().
size
());
list
.
addAll
(
this
.
getPlayers
().
values
());
for
(
Player
player
:
list
)
{
player
.
getSession
().
close
();
}
...
...
src/main/java/emu/grasscutter/server/game/GameServerInitializer.java
deleted
100644 → 0
View file @
8c8f3887
package
emu.grasscutter.server.game
;
import
emu.grasscutter.netty.KcpServerInitializer
;
import
io.jpower.kcp.netty.UkcpChannel
;
import
io.netty.channel.ChannelPipeline
;
public
class
GameServerInitializer
extends
KcpServerInitializer
{
private
GameServer
server
;
public
GameServerInitializer
(
GameServer
server
)
{
this
.
server
=
server
;
}
@Override
protected
void
initChannel
(
UkcpChannel
ch
)
throws
Exception
{
ChannelPipeline
pipeline
=
null
;
if
(
ch
!=
null
){
pipeline
=
ch
.
pipeline
();
}
new
GameSession
(
server
,
pipeline
);
}
}
src/main/java/emu/grasscutter/server/game/GameSession.java
View file @
584aec58
...
...
@@ -2,9 +2,6 @@ package emu.grasscutter.server.game;
import
java.io.File
;
import
java.net.InetSocketAddress
;
import
java.nio.ByteBuffer
;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.Set
;
import
emu.grasscutter.Grasscutter
;
...
...
@@ -14,23 +11,19 @@ import emu.grasscutter.game.player.Player;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.packet.PacketOpcodesUtil
;
import
emu.grasscutter.netty.KcpChannel
;
import
emu.grasscutter.server.event.game.SendPacketEvent
;
import
emu.grasscutter.utils.Crypto
;
import
emu.grasscutter.utils.FileUtils
;
import
emu.grasscutter.utils.Utils
;
import
io.jpower.kcp.netty.UkcpChannel
;
import
io.netty.buffer.ByteBuf
;
import
io.netty.buffer.Unpooled
;
import
io.netty.channel.ChannelHandlerContext
;
import
io.netty.channel.ChannelPipeline
;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
import
static
emu
.
grasscutter
.
Configuration
.*;
import
static
emu
.
grasscutter
.
utils
.
Language
.
translate
;
public
class
GameSession
ext
en
d
s
KcpChannel
{
public
class
GameSession
implem
en
t
s
GameSessionManager
.
KcpChannel
{
private
final
GameServer
server
;
private
GameSessionManager
.
KcpTunnel
tunnel
;
private
Account
account
;
private
Player
player
;
...
...
@@ -41,29 +34,10 @@ public class GameSession extends KcpChannel {
private
long
lastPingTime
;
private
int
lastClientSeq
=
10
;
private
final
ChannelPipeline
pipeline
;
@Override
public
void
close
()
{
setState
(
SessionState
.
INACTIVE
);
//send disconnection pack in case of reconnection
try
{
send
(
new
BasePacket
(
PacketOpcodes
.
ServerDisconnectClientNotify
));
}
catch
(
Throwable
ignore
){
}
super
.
close
();
}
public
GameSession
(
GameServer
server
)
{
this
(
server
,
null
);
}
public
GameSession
(
GameServer
server
,
ChannelPipeline
pipeline
)
{
this
.
server
=
server
;
this
.
state
=
SessionState
.
WAITING_FOR_TOKEN
;
this
.
lastPingTime
=
System
.
currentTimeMillis
();
this
.
pipeline
=
pipeline
;
if
(
pipeline
!=
null
)
{
pipeline
.
addLast
(
this
);
}
}
public
GameServer
getServer
()
{
...
...
@@ -71,10 +45,11 @@ public class GameSession extends KcpChannel {
}
public
InetSocketAddress
getAddress
()
{
if
(
this
.
getChannel
()
==
null
)
{
try
{
return
tunnel
.
getAddress
();
}
catch
(
Throwable
ignore
){
return
null
;
}
return
this
.
getChannel
().
remoteAddress
();
}
public
boolean
useSecretKey
()
{
...
...
@@ -135,37 +110,7 @@ public class GameSession extends KcpChannel {
public
int
getNextClientSequence
()
{
return
++
lastClientSeq
;
}
@Override
protected
void
onConnect
()
{
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.game.connect"
,
this
.
getAddress
().
getHostString
().
toLowerCase
()));
}
@Override
protected
synchronized
void
onDisconnect
()
{
// Synchronize so we don't add character at the same time.
Grasscutter
.
getLogger
().
info
(
translate
(
"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
())
{
Player
player
=
getPlayer
();
// Call logout event.
player
.
onLogout
();
}
try
{
pipeline
.
remove
(
this
);
}
catch
(
Throwable
ignore
)
{
}
}
protected
void
logPacket
(
ByteBuffer
buf
)
{
ByteBuf
b
=
Unpooled
.
wrappedBuffer
(
buf
.
array
());
logPacket
(
b
);
}
public
void
replayPacket
(
int
opcode
,
String
name
)
{
String
filePath
=
PACKET
(
name
);
File
p
=
new
File
(
filePath
);
...
...
@@ -200,13 +145,16 @@ public class GameSession extends KcpChannel {
// Log
if
(
SERVER
.
debugLevel
==
ServerDebugMode
.
ALL
)
{
logPacket
(
packet
);
if
(!
loopPacket
.
contains
(
packet
.
getOpcode
()))
{
Grasscutter
.
getLogger
().
info
(
"SEND: "
+
PacketOpcodesUtil
.
getOpcodeName
(
packet
.
getOpcode
())
+
" ("
+
packet
.
getOpcode
()
+
")"
);
System
.
out
.
println
(
Utils
.
bytesToHex
(
packet
.
getData
()));
}
}
// Invoke event.
SendPacketEvent
event
=
new
SendPacketEvent
(
this
,
packet
);
event
.
call
();
if
(!
event
.
isCanceled
())
// If event is not cancelled, continue.
this
.
send
(
event
.
getPacket
().
build
());
if
(!
event
.
isCanceled
())
{
// If event is not cancelled, continue.
tunnel
.
writeData
(
event
.
getPacket
().
build
());
}
}
private
static
final
Set
<
Integer
>
loopPacket
=
Set
.
of
(
...
...
@@ -217,78 +165,104 @@ public class GameSession extends KcpChannel {
PacketOpcodes
.
QueryPathReq
);
private
void
logPacket
(
BasePacket
packet
)
{
if
(!
loopPacket
.
contains
(
packet
.
getOpcode
())
)
{
Grasscutter
.
getLogger
().
info
(
"SEND: "
+
PacketOpcodesUtil
.
getOpcodeName
(
packet
.
getOpcode
())
+
" ("
+
packet
.
getOpcode
()
+
")"
)
;
System
.
out
.
println
(
Utils
.
bytesToHex
(
packet
.
getData
()));
}
}
@Override
public
void
onConnected
(
GameSessionManager
.
KcpTunnel
tunnel
)
{
this
.
tunnel
=
tunnel
;
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.game.connect"
,
this
.
getAddress
().
toString
()));
}
@Override
public
void
onMessage
(
ChannelHandlerContext
ctx
,
ByteBuf
data
)
{
public
void
handleReceive
(
byte
[]
bytes
)
{
// Decrypt and turn back into a packet
byte
[]
byteData
=
Utils
.
byteBufToArray
(
data
);
Crypto
.
xor
(
byteData
,
useSecretKey
()
?
Crypto
.
ENCRYPT_KEY
:
Crypto
.
DISPATCH_KEY
);
ByteBuf
packet
=
Unpooled
.
wrappedBuffer
(
byteData
);
Crypto
.
xor
(
bytes
,
useSecretKey
()
?
Crypto
.
ENCRYPT_KEY
:
Crypto
.
DISPATCH_KEY
);
ByteBuf
packet
=
Unpooled
.
wrappedBuffer
(
bytes
);
// Log
//logPacket(packet);
// Handle
try
{
boolean
allDebug
=
SERVER
.
debugLevel
==
ServerDebugMode
.
ALL
;
while
(
packet
.
readableBytes
()
>
0
)
{
// Length
if
(
packet
.
readableBytes
()
<
12
)
{
return
;
}
// Packet sanity check
int
const1
=
packet
.
readShort
();
if
(
const1
!=
17767
)
{
if
(
allDebug
){
Grasscutter
.
getLogger
().
error
(
"Bad Data Package Received: got {} ,expect 17767"
,
const1
);
}
return
;
// Bad packet
}
// Data
int
opcode
=
packet
.
readShort
();
int
headerLength
=
packet
.
readShort
();
int
payloadLength
=
packet
.
readInt
();
byte
[]
header
=
new
byte
[
headerLength
];
byte
[]
payload
=
new
byte
[
payloadLength
];
packet
.
readBytes
(
header
);
packet
.
readBytes
(
payload
);
// Sanity check #2
int
const2
=
packet
.
readShort
();
if
(
const2
!=
-
30293
)
{
if
(
allDebug
){
Grasscutter
.
getLogger
().
error
(
"Bad Data Package Received: got {} ,expect -30293"
,
const2
);
}
return
;
// Bad packet
}
// Log packet
if
(
SERVER
.
debugLevel
==
ServerDebugMode
.
ALL
)
{
if
(
allDebug
)
{
if
(!
loopPacket
.
contains
(
opcode
))
{
Grasscutter
.
getLogger
().
info
(
"RECV: "
+
PacketOpcodesUtil
.
getOpcodeName
(
opcode
)
+
" ("
+
opcode
+
")"
);
System
.
out
.
println
(
Utils
.
bytesToHex
(
payload
));
}
}
// Handle
getServer
().
getPacketHandler
().
handle
(
this
,
opcode
,
header
,
payload
);
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
finally
{
data
.
release
();
//byteBuf
.release();
//Needn't
packet
.
release
();
}
}
@Override
public
void
handleClose
()
{
setState
(
SessionState
.
INACTIVE
);
//send disconnection pack in case of reconnection
Grasscutter
.
getLogger
().
info
(
translate
(
"messages.game.disconnect"
,
this
.
getAddress
().
toString
()));
// Save after disconnecting
if
(
this
.
isLoggedIn
())
{
Player
player
=
getPlayer
();
// Call logout event.
player
.
onLogout
();
}
try
{
send
(
new
BasePacket
(
PacketOpcodes
.
ServerDisconnectClientNotify
));
}
catch
(
Throwable
ignore
){
Grasscutter
.
getLogger
().
warn
(
"closing {} error"
,
getAddress
().
getAddress
().
getHostAddress
());
}
tunnel
=
null
;
}
public
void
close
()
{
tunnel
.
close
();
}
public
boolean
isActive
()
{
return
getState
()
==
SessionState
.
ACTIVE
;
}
public
enum
SessionState
{
INACTIVE
,
WAITING_FOR_TOKEN
,
WAITING_FOR_LOGIN
,
PICKING_CHARACTER
,
ACTIVE
;
ACTIVE
}
}
src/main/java/emu/grasscutter/server/game/GameSessionManager.java
0 → 100644
View file @
584aec58
package
emu.grasscutter.server.game
;
import
java.net.InetSocketAddress
;
import
java.util.concurrent.ConcurrentHashMap
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.utils.Crypto
;
import
emu.grasscutter.utils.Utils
;
import
io.netty.buffer.ByteBuf
;
import
io.netty.buffer.Unpooled
;
import
io.netty.channel.DefaultEventLoop
;
import
kcp.highway.KcpListener
;
import
kcp.highway.Ukcp
;
public
class
GameSessionManager
{
private
static
final
DefaultEventLoop
logicThread
=
new
DefaultEventLoop
();
private
static
final
ConcurrentHashMap
<
Ukcp
,
GameSession
>
sessions
=
new
ConcurrentHashMap
<>();
private
static
final
KcpListener
listener
=
new
KcpListener
(){
@Override
public
void
onConnected
(
Ukcp
ukcp
)
{
int
times
=
0
;
GameServer
server
=
Grasscutter
.
getGameServer
();
while
(
server
==
null
){
//Waiting server to establish
try
{
Thread
.
sleep
(
1000
);
}
catch
(
InterruptedException
e
)
{
e
.
printStackTrace
();
ukcp
.
close
();
return
;
}
if
(
times
++>
5
){
Grasscutter
.
getLogger
().
error
(
"Service is not available!"
);
ukcp
.
close
();
return
;
}
server
=
Grasscutter
.
getGameServer
();
}
GameSession
conversation
=
new
GameSession
(
server
);
conversation
.
onConnected
(
new
KcpTunnel
(){
@Override
public
InetSocketAddress
getAddress
()
{
return
ukcp
.
user
().
getRemoteAddress
();
}
@Override
public
void
writeData
(
byte
[]
bytes
)
{
ByteBuf
buf
=
Unpooled
.
wrappedBuffer
(
bytes
);
ukcp
.
write
(
buf
);
buf
.
release
();
}
@Override
public
void
close
()
{
ukcp
.
close
();
}
@Override
public
int
getSrtt
()
{
return
ukcp
.
srtt
();
}
});
sessions
.
put
(
ukcp
,
conversation
);
}
@Override
public
void
handleReceive
(
ByteBuf
buf
,
Ukcp
kcp
)
{
byte
[]
byteData
=
Utils
.
byteBufToArray
(
buf
);
logicThread
.
execute
(()
->
{
try
{
GameSession
conversation
=
sessions
.
get
(
kcp
);
if
(
conversation
!=
null
)
{
conversation
.
handleReceive
(
byteData
);
}
}
catch
(
Exception
e
){
e
.
printStackTrace
();
}
});
}
@Override
public
void
handleException
(
Throwable
ex
,
Ukcp
ukcp
)
{
}
@Override
public
void
handleClose
(
Ukcp
ukcp
)
{
GameSession
conversation
=
sessions
.
get
(
ukcp
);
if
(
conversation
!=
null
)
{
conversation
.
handleClose
();
sessions
.
remove
(
ukcp
);
}
}
};
public
static
KcpListener
getListener
()
{
return
listener
;
}
interface
KcpTunnel
{
InetSocketAddress
getAddress
();
void
writeData
(
byte
[]
bytes
);
void
close
();
int
getSrtt
();
}
interface
KcpChannel
{
void
onConnected
(
KcpTunnel
tunnel
);
void
handleClose
();
void
handleReceive
(
byte
[]
bytes
);
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketDoGachaRsp.java
View file @
584aec58
...
...
@@ -8,6 +8,7 @@ import emu.grasscutter.net.packet.BasePacket;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.DoGachaRspOuterClass.DoGachaRsp
;
import
emu.grasscutter.net.proto.GachaItemOuterClass.GachaItem
;
import
emu.grasscutter.net.proto.RetcodeOuterClass.Retcode
;
import
emu.grasscutter.net.proto.RetcodeOuterClass
;
public
class
PacketDoGachaRsp
extends
BasePacket
{
...
...
@@ -42,4 +43,14 @@ public class PacketDoGachaRsp extends BasePacket {
this
.
setData
(
p
);
}
public
PacketDoGachaRsp
(
Retcode
retcode
)
{
super
(
PacketOpcodes
.
DoGachaRsp
);
DoGachaRsp
p
=
DoGachaRsp
.
newBuilder
()
.
setRetcode
(
retcode
.
getNumber
())
.
build
();
this
.
setData
(
p
);
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketEntityFightPropChangeReasonNotify.java
View file @
584aec58
...
...
@@ -4,6 +4,7 @@ import emu.grasscutter.game.entity.GameEntity;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.ChangeEnergyReasonOuterClass.ChangeEnergyReason
;
import
emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason
;
import
emu.grasscutter.net.proto.EntityFightPropChangeReasonNotifyOuterClass.EntityFightPropChangeReasonNotify
;
import
emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason
;
...
...
@@ -55,4 +56,17 @@ public class PacketEntityFightPropChangeReasonNotify extends BasePacket {
this
.
setData
(
proto
);
}
public
PacketEntityFightPropChangeReasonNotify
(
GameEntity
entity
,
FightProperty
prop
,
Float
value
,
ChangeEnergyReason
reason
)
{
super
(
PacketOpcodes
.
EntityFightPropChangeReasonNotify
);
EntityFightPropChangeReasonNotify
proto
=
EntityFightPropChangeReasonNotify
.
newBuilder
()
.
setEntityId
(
entity
.
getId
())
.
setPropType
(
prop
.
getId
())
.
setPropDelta
(
value
)
.
setChangeEnergyReson
(
reason
)
.
build
();
this
.
setData
(
proto
);
}
}
src/main/resources/defaults/data/Spawns.json
View file @
584aec58
This diff is collapsed.
Click to expand it.
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