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
c442039f
Commit
c442039f
authored
Apr 30, 2022
by
Magix
Committed by
GitHub
Apr 30, 2022
Browse files
Implement a plugin API for developers
Add a developer-friendly API to Grasscutter
parents
d133e556
a82ec3e3
Changes
32
Show whitespace changes
Inline
Side-by-side
build.gradle
View file @
c442039f
...
@@ -37,7 +37,7 @@ sourceCompatibility = JavaVersion.VERSION_17
...
@@ -37,7 +37,7 @@ sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility
=
JavaVersion
.
VERSION_17
targetCompatibility
=
JavaVersion
.
VERSION_17
group
=
'tech.xigam'
group
=
'tech.xigam'
version
=
'1.0.
0
-dev'
version
=
'1.0.
2
-dev'
sourceCompatibility
=
17
sourceCompatibility
=
17
targetCompatibility
=
17
targetCompatibility
=
17
...
...
src/main/java/emu/grasscutter/command/commands/CoopCommand.java
View file @
c442039f
...
@@ -8,13 +8,14 @@ import java.util.List;
...
@@ -8,13 +8,14 @@ import java.util.List;
@Command
(
label
=
"coop"
,
usage
=
"coop"
,
@Command
(
label
=
"coop"
,
usage
=
"coop"
,
description
=
"Forces someone to join the world of others"
,
permission
=
"server.coop"
)
description
=
"Forces someone to join the world of others"
,
permission
=
"server.coop"
)
public
class
CoopCommand
implements
CommandHandler
{
public
final
class
CoopCommand
implements
CommandHandler
{
@Override
@Override
public
void
execute
(
Player
sender
,
List
<
String
>
args
)
{
public
void
execute
(
Player
sender
,
List
<
String
>
args
)
{
if
(
args
.
size
()
<
2
)
{
if
(
args
.
size
()
<
2
)
{
CommandHandler
.
sendMessage
(
sender
,
"Usage: coop <playerId> <target playerId>"
);
CommandHandler
.
sendMessage
(
sender
,
"Usage: coop <playerId> <target playerId>"
);
return
;
return
;
}
}
try
{
try
{
int
tid
=
Integer
.
parseInt
(
args
.
get
(
0
));
int
tid
=
Integer
.
parseInt
(
args
.
get
(
0
));
int
hostId
=
Integer
.
parseInt
(
args
.
get
(
1
));
int
hostId
=
Integer
.
parseInt
(
args
.
get
(
1
));
...
...
src/main/java/emu/grasscutter/command/commands/GiveAllCommand.java
View file @
c442039f
...
@@ -15,7 +15,7 @@ import java.util.*;
...
@@ -15,7 +15,7 @@ import java.util.*;
@Command
(
label
=
"giveall"
,
usage
=
"giveall [player] [amount]"
,
@Command
(
label
=
"giveall"
,
usage
=
"giveall [player] [amount]"
,
description
=
"Gives all items"
,
aliases
=
{
"givea"
},
permission
=
"player.giveall"
,
threading
=
true
)
description
=
"Gives all items"
,
aliases
=
{
"givea"
},
permission
=
"player.giveall"
,
threading
=
true
)
public
class
GiveAllCommand
implements
CommandHandler
{
public
final
class
GiveAllCommand
implements
CommandHandler
{
@Override
@Override
public
void
execute
(
Player
sender
,
List
<
String
>
args
)
{
public
void
execute
(
Player
sender
,
List
<
String
>
args
)
{
...
@@ -142,16 +142,11 @@ public class GiveAllCommand implements CommandHandler {
...
@@ -142,16 +142,11 @@ public class GiveAllCommand implements CommandHandler {
}
}
}
}
if
(
testItemsList
.
contains
(
itemId
))
{
return
testItemsList
.
contains
(
itemId
);
return
true
;
}
return
false
;
}
}
static
class
Range
{
static
class
Range
{
private
int
min
;
private
final
int
min
,
max
;
private
int
max
;
public
Range
(
int
min
,
int
max
)
{
public
Range
(
int
min
,
int
max
)
{
if
(
min
>
max
){
if
(
min
>
max
){
...
@@ -159,6 +154,7 @@ public class GiveAllCommand implements CommandHandler {
...
@@ -159,6 +154,7 @@ public class GiveAllCommand implements CommandHandler {
max
^=
min
;
max
^=
min
;
min
^=
max
;
min
^=
max
;
}
}
this
.
min
=
min
;
this
.
min
=
min
;
this
.
max
=
max
;
this
.
max
=
max
;
}
}
...
...
src/main/java/emu/grasscutter/command/commands/SendMailCommand.java
View file @
c442039f
...
@@ -6,24 +6,20 @@ import emu.grasscutter.command.CommandHandler;
...
@@ -6,24 +6,20 @@ import emu.grasscutter.command.CommandHandler;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.mail.Mail
;
import
emu.grasscutter.game.mail.Mail
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.server.packet.send.PacketMailChangeNotify
;
import
java.time.Instant
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Locale
;
@Command
(
label
=
"sendmail"
,
usage
=
"sendmail <userId|all|help> [templateId]"
,
@Command
(
label
=
"sendmail"
,
usage
=
"sendmail <userId|all|help> [templateId]"
,
description
=
"Sends mail to the specified user. The usage of this command changes based on it's composition state."
,
permission
=
"server.sendmail"
)
description
=
"Sends mail to the specified user. The usage of this command changes based on it's composition state."
,
permission
=
"server.sendmail"
)
public
class
SendMailCommand
implements
CommandHandler
{
public
final
class
SendMailCommand
implements
CommandHandler
{
// TODO: You should be able to do /sendmail and then just send subsequent messages until you finish
// TODO: You should be able to do /sendmail and then just send subsequent messages until you finish
// However, due to the current nature of the command system, I don't think this is possible without rewriting
// However, due to the current nature of the command system, I don't think this is possible without rewriting
// the command system (again). For now this will do
// the command system (again). For now this will do
// Key = User that is constructing the mail.
// Key = User that is constructing the mail.
private
static
HashMap
<
Integer
,
MailBuilder
>
mailBeingConstructed
=
new
HashMap
<
Integer
,
MailBuilder
>();
private
static
final
HashMap
<
Integer
,
MailBuilder
>
mailBeingConstructed
=
new
HashMap
<
Integer
,
MailBuilder
>();
// Yes this is awful and I hate it.
// Yes this is awful and I hate it.
@Override
@Override
...
@@ -48,7 +44,6 @@ public class SendMailCommand implements CommandHandler {
...
@@ -48,7 +44,6 @@ public class SendMailCommand implements CommandHandler {
default
->
{
default
->
{
if
(
DatabaseHelper
.
getPlayerById
(
Integer
.
parseInt
(
args
.
get
(
0
)))
!=
null
)
{
if
(
DatabaseHelper
.
getPlayerById
(
Integer
.
parseInt
(
args
.
get
(
0
)))
!=
null
)
{
mailBuilder
=
new
MailBuilder
(
Integer
.
parseInt
(
args
.
get
(
0
)),
new
Mail
());
mailBuilder
=
new
MailBuilder
(
Integer
.
parseInt
(
args
.
get
(
0
)),
new
Mail
());
break
;
}
else
{
}
else
{
CommandHandler
.
sendMessage
(
sender
,
"The user with an id of '"
+
args
.
get
(
0
)
+
"' does not exist"
);
CommandHandler
.
sendMessage
(
sender
,
"The user with an id of '"
+
args
.
get
(
0
)
+
"' does not exist"
);
return
;
return
;
...
@@ -73,7 +68,7 @@ public class SendMailCommand implements CommandHandler {
...
@@ -73,7 +68,7 @@ public class SendMailCommand implements CommandHandler {
}
}
case
"finish"
->
{
case
"finish"
->
{
if
(
mailBuilder
.
constructionStage
==
3
)
{
if
(
mailBuilder
.
constructionStage
==
3
)
{
if
(
mailBuilder
.
sendToAll
==
false
)
{
if
(
!
mailBuilder
.
sendToAll
)
{
Grasscutter
.
getGameServer
().
getPlayerByUid
(
mailBuilder
.
recipient
,
true
).
sendMail
(
mailBuilder
.
mail
);
Grasscutter
.
getGameServer
().
getPlayerByUid
(
mailBuilder
.
recipient
,
true
).
sendMail
(
mailBuilder
.
mail
);
CommandHandler
.
sendMessage
(
sender
,
"Message sent to user "
+
mailBuilder
.
recipient
+
"!"
);
CommandHandler
.
sendMessage
(
sender
,
"Message sent to user "
+
mailBuilder
.
recipient
+
"!"
);
}
else
{
}
else
{
...
...
src/main/java/emu/grasscutter/command/commands/T
pa
llCommand.java
→
src/main/java/emu/grasscutter/command/commands/T
eleportA
llCommand.java
View file @
c442039f
...
@@ -9,23 +9,25 @@ import java.util.List;
...
@@ -9,23 +9,25 @@ import java.util.List;
@Command
(
label
=
"tpall"
,
usage
=
"tpall"
,
@Command
(
label
=
"tpall"
,
usage
=
"tpall"
,
description
=
"Teleports all players in your world to your position"
,
permission
=
"player.tpall"
)
description
=
"Teleports all players in your world to your position"
,
permission
=
"player.tpall"
)
public
class
T
pa
llCommand
implements
CommandHandler
{
public
final
class
T
eleportA
llCommand
implements
CommandHandler
{
@Override
@Override
public
void
execute
(
Player
sender
,
List
<
String
>
args
)
{
public
void
execute
(
Player
sender
,
List
<
String
>
args
)
{
if
(
sender
==
null
)
{
if
(
sender
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Run this command in-game."
);
CommandHandler
.
sendMessage
(
null
,
"Run this command in-game."
);
return
;
return
;
}
}
if
(!
sender
.
getWorld
().
isMultiplayer
())
{
if
(!
sender
.
getWorld
().
isMultiplayer
())
{
CommandHandler
.
sendMessage
(
sender
,
"You only can use this command in MP mode."
);
CommandHandler
.
sendMessage
(
sender
,
"You only can use this command in MP mode."
);
return
;
return
;
}
}
for
(
Player
gp
:
sender
.
getWorld
().
getPlayers
())
{
if
(
gp
.
equals
(
sender
))
for
(
Player
player
:
sender
.
getWorld
().
getPlayers
())
{
if
(
player
.
equals
(
sender
))
continue
;
continue
;
Position
pos
=
sender
.
getPos
();
Position
pos
=
sender
.
getPos
();
g
p
.
getWorld
().
transferPlayerToScene
(
g
p
,
sender
.
getSceneId
(),
pos
);
p
layer
.
getWorld
().
transferPlayerToScene
(
p
layer
,
sender
.
getSceneId
(),
pos
);
}
}
}
}
}
}
src/main/java/emu/grasscutter/game/player/Player.java
View file @
c442039f
...
@@ -37,6 +37,9 @@ import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass;
...
@@ -37,6 +37,9 @@ import emu.grasscutter.net.proto.ShowAvatarInfoOuterClass;
import
emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture
;
import
emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture
;
import
emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail
;
import
emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail
;
import
emu.grasscutter.net.proto.SocialShowAvatarInfoOuterClass
;
import
emu.grasscutter.net.proto.SocialShowAvatarInfoOuterClass
;
import
emu.grasscutter.server.event.player.PlayerJoinEvent
;
import
emu.grasscutter.server.event.player.PlayerQuitEvent
;
import
emu.grasscutter.server.event.player.PlayerReceiveMailEvent
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.*
;
import
emu.grasscutter.server.packet.send.*
;
...
@@ -725,9 +728,13 @@ public class Player {
...
@@ -725,9 +728,13 @@ public class Player {
public
List
<
Mail
>
getAllMail
()
{
return
this
.
mail
;
}
public
List
<
Mail
>
getAllMail
()
{
return
this
.
mail
;
}
public
void
sendMail
(
Mail
message
)
{
public
void
sendMail
(
Mail
message
)
{
// Call mail receive event.
PlayerReceiveMailEvent
event
=
new
PlayerReceiveMailEvent
(
this
,
message
);
event
.
call
();
if
(
event
.
isCanceled
())
return
;
message
=
event
.
getMessage
();
this
.
mail
.
add
(
message
);
this
.
mail
.
add
(
message
);
this
.
save
();
this
.
save
();
Grasscutter
.
getLogger
().
info
(
"Mail sent to user ["
+
this
.
getUid
()
+
":"
+
this
.
getNickname
()
+
"]!"
);
Grasscutter
.
getLogger
().
debug
(
"Mail sent to user ["
+
this
.
getUid
()
+
":"
+
this
.
getNickname
()
+
"]!"
);
if
(
this
.
isOnline
())
{
if
(
this
.
isOnline
())
{
this
.
sendPacket
(
new
PacketMailChangeNotify
(
this
,
message
));
this
.
sendPacket
(
new
PacketMailChangeNotify
(
this
,
message
));
}
// TODO: setup a way for the mail notification to show up when someone receives mail when they were offline
}
// TODO: setup a way for the mail notification to show up when someone receives mail when they were offline
...
@@ -1037,6 +1044,11 @@ public class Player {
...
@@ -1037,6 +1044,11 @@ public class Player {
// First notify packets sent
// First notify packets sent
this
.
setHasSentAvatarDataNotify
(
true
);
this
.
setHasSentAvatarDataNotify
(
true
);
// Call join event.
PlayerJoinEvent
event
=
new
PlayerJoinEvent
(
this
);
event
.
call
();
if
(
event
.
isCanceled
())
// If event is not cancelled, continue.
session
.
close
();
}
}
public
void
onLogout
()
{
public
void
onLogout
()
{
...
@@ -1055,6 +1067,9 @@ public class Player {
...
@@ -1055,6 +1067,9 @@ public class Player {
this
.
save
();
this
.
save
();
this
.
getTeamManager
().
saveAvatars
();
this
.
getTeamManager
().
saveAvatars
();
this
.
getFriendsList
().
save
();
this
.
getFriendsList
().
save
();
// Call quit event.
PlayerQuitEvent
event
=
new
PlayerQuitEvent
(
this
);
event
.
call
();
}
}
public
enum
SceneLoadState
{
public
enum
SceneLoadState
{
...
...
src/main/java/emu/grasscutter/plugin/Plugin.java
View file @
c442039f
package
emu.grasscutter.plugin
;
package
emu.grasscutter.plugin
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.plugin.api.ServerHook
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.game.GameServer
;
import
java.io.File
;
import
java.io.InputStream
;
import
java.net.URLClassLoader
;
/**
/**
* The base class for all plugins to extend.
* The base class for all plugins to extend.
*/
*/
public
abstract
class
Plugin
{
public
abstract
class
Plugin
{
private
final
ServerHook
server
=
ServerHook
.
getInstance
();
private
PluginIdentifier
identifier
;
private
PluginIdentifier
identifier
;
private
URLClassLoader
classLoader
;
private
File
dataFolder
;
/**
/**
* This method is reflected into.
* This method is reflected into.
...
@@ -15,10 +24,20 @@ public abstract class Plugin {
...
@@ -15,10 +24,20 @@ public abstract class Plugin {
* Set plugin variables.
* Set plugin variables.
* @param identifier The plugin's identifier.
* @param identifier The plugin's identifier.
*/
*/
private
void
initializePlugin
(
PluginIdentifier
identifier
)
{
private
void
initializePlugin
(
PluginIdentifier
identifier
,
URLClassLoader
classLoader
)
{
if
(
this
.
identifier
==
null
)
if
(
this
.
identifier
!=
null
)
{
Grasscutter
.
getLogger
().
warn
(
this
.
identifier
.
name
+
" had a reinitialization attempt."
);
return
;
}
this
.
identifier
=
identifier
;
this
.
identifier
=
identifier
;
else
Grasscutter
.
getLogger
().
warn
(
this
.
identifier
.
name
+
" had a reinitialization attempt."
);
this
.
classLoader
=
classLoader
;
this
.
dataFolder
=
new
File
(
Grasscutter
.
getConfig
().
PLUGINS_FOLDER
,
identifier
.
name
);
if
(!
this
.
dataFolder
.
exists
()
&&
!
this
.
dataFolder
.
mkdirs
())
{
Grasscutter
.
getLogger
().
warn
(
"Failed to create plugin data folder for "
+
this
.
identifier
.
name
);
return
;
}
}
}
/**
/**
...
@@ -55,7 +74,32 @@ public abstract class Plugin {
...
@@ -55,7 +74,32 @@ public abstract class Plugin {
* @return A server instance.
* @return A server instance.
*/
*/
public
final
GameServer
getServer
()
{
public
final
GameServer
getServer
()
{
return
Grasscutter
.
getGameServer
();
return
this
.
server
.
getGameServer
();
}
/**
* Returns an input stream for a resource in the JAR file.
* @param resourceName The name of the resource.
* @return An input stream.
*/
public
final
InputStream
getResource
(
String
resourceName
)
{
return
this
.
classLoader
.
getResourceAsStream
(
resourceName
);
}
/**
* Returns a directory where plugins can store data files.
* @return A directory on the file system.
*/
public
final
File
getDataFolder
()
{
return
this
.
dataFolder
;
}
/**
* Returns the server hook.
* @return A server hook singleton.
*/
public
final
ServerHook
getHandle
()
{
return
this
.
server
;
}
}
/* Called when the plugin is first loaded. */
/* Called when the plugin is first loaded. */
...
...
src/main/java/emu/grasscutter/plugin/PluginManager.java
View file @
c442039f
...
@@ -3,9 +3,9 @@ package emu.grasscutter.plugin;
...
@@ -3,9 +3,9 @@ package emu.grasscutter.plugin;
import
emu.grasscutter.Grasscutter
;
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.Listener
;
import
emu.grasscutter.server.event.HandlerPriority
;
import
emu.grasscutter.utils.EventConsumer
;
import
emu.grasscutter.utils.Utils
;
import
emu.grasscutter.utils.Utils
;
import
org.reflections.Reflections
;
import
java.io.File
;
import
java.io.File
;
import
java.io.InputStreamReader
;
import
java.io.InputStreamReader
;
...
@@ -21,7 +21,7 @@ import java.util.jar.JarFile;
...
@@ -21,7 +21,7 @@ import java.util.jar.JarFile;
*/
*/
public
final
class
PluginManager
{
public
final
class
PluginManager
{
private
final
Map
<
String
,
Plugin
>
plugins
=
new
HashMap
<>();
private
final
Map
<
String
,
Plugin
>
plugins
=
new
HashMap
<>();
private
final
Map
<
Plugin
,
List
<
Listener
>>
listeners
=
new
HashMap
<>();
private
final
List
<
EventHandler
<?
extends
Event
>>
listeners
=
new
LinkedList
<>();
public
PluginManager
()
{
public
PluginManager
()
{
this
.
loadPlugins
();
// Load all plugins from the plugins directory.
this
.
loadPlugins
();
// Load all plugins from the plugins directory.
...
@@ -68,12 +68,12 @@ public final class PluginManager {
...
@@ -68,12 +68,12 @@ 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
(
"/"
,
"."
);
Class
<?>
clazz
=
loader
.
loadClass
(
className
);
loader
.
loadClass
(
className
);
}
}
Class
<?>
pluginClass
=
loader
.
loadClass
(
pluginConfig
.
mainClass
);
Class
<?>
pluginClass
=
loader
.
loadClass
(
pluginConfig
.
mainClass
);
Plugin
pluginInstance
=
(
Plugin
)
pluginClass
.
getDeclaredConstructor
().
newInstance
();
Plugin
pluginInstance
=
(
Plugin
)
pluginClass
.
getDeclaredConstructor
().
newInstance
();
this
.
loadPlugin
(
pluginInstance
,
PluginIdentifier
.
fromPluginConfig
(
pluginConfig
));
this
.
loadPlugin
(
pluginInstance
,
PluginIdentifier
.
fromPluginConfig
(
pluginConfig
)
,
loader
);
fileReader
.
close
();
// Close the file reader.
fileReader
.
close
();
// Close the file reader.
}
catch
(
ClassNotFoundException
ignored
)
{
}
catch
(
ClassNotFoundException
ignored
)
{
...
@@ -89,14 +89,14 @@ public final class PluginManager {
...
@@ -89,14 +89,14 @@ public final class PluginManager {
* Load the specified plugin.
* Load the specified plugin.
* @param plugin The plugin instance.
* @param plugin The plugin instance.
*/
*/
private
void
loadPlugin
(
Plugin
plugin
,
PluginIdentifier
identifier
)
{
private
void
loadPlugin
(
Plugin
plugin
,
PluginIdentifier
identifier
,
URLClassLoader
classLoader
)
{
Grasscutter
.
getLogger
().
info
(
"Loading plugin: "
+
identifier
.
name
);
Grasscutter
.
getLogger
().
info
(
"Loading plugin: "
+
identifier
.
name
);
// Add the plugin's identifier.
// Add the plugin's identifier.
try
{
try
{
Class
<
Plugin
>
pluginClass
=
Plugin
.
class
;
Class
<
Plugin
>
pluginClass
=
Plugin
.
class
;
Method
method
=
pluginClass
.
getDeclaredMethod
(
"initializePlugin"
,
PluginIdentifier
.
class
);
Method
method
=
pluginClass
.
getDeclaredMethod
(
"initializePlugin"
,
PluginIdentifier
.
class
,
URLClassLoader
.
class
);
method
.
setAccessible
(
true
);
method
.
invoke
(
plugin
,
identifier
);
method
.
setAccessible
(
false
);
method
.
setAccessible
(
true
);
method
.
invoke
(
plugin
,
identifier
,
classLoader
);
method
.
setAccessible
(
false
);
}
catch
(
Exception
ignored
)
{
}
catch
(
Exception
ignored
)
{
Grasscutter
.
getLogger
().
warn
(
"Failed to add plugin identifier: "
+
identifier
.
name
);
Grasscutter
.
getLogger
().
warn
(
"Failed to add plugin identifier: "
+
identifier
.
name
);
}
}
...
@@ -129,11 +129,10 @@ public final class PluginManager {
...
@@ -129,11 +129,10 @@ public final class PluginManager {
/**
/**
* Registers a plugin's event listener.
* Registers a plugin's event listener.
* @param plugin The plugin instance.
* @param listener The event listener.
* @param listener The event listener.
*/
*/
public
void
registerListener
(
Plugin
plugin
,
Listener
listener
)
{
public
void
registerListener
(
EventHandler
<?
extends
Event
>
listener
)
{
this
.
listeners
.
computeIfAbsent
(
plugin
,
k
->
new
ArrayList
<>()).
add
(
listener
);
this
.
listeners
.
add
(
listener
);
}
}
/**
/**
...
@@ -141,23 +140,31 @@ public final class PluginManager {
...
@@ -141,23 +140,31 @@ public final class PluginManager {
* @param event The event to invoke.
* @param event The event to invoke.
*/
*/
public
void
invokeEvent
(
Event
event
)
{
public
void
invokeEvent
(
Event
event
)
{
this
.
listeners
.
values
().
stream
()
EnumSet
.
allOf
(
HandlerPriority
.
class
)
.
flatMap
(
Collection:
:
stream
)
.
forEach
(
priority
->
this
.
checkAndFilter
(
event
,
priority
));
.
forEach
(
listener
->
this
.
invokeOnListener
(
listener
,
event
));
}
}
/**
/**
* Attempts to invoke the event on the provided listener.
* Check an event to handlers for the priority.
* @param event The event being called.
* @param priority The priority to call for.
*/
*/
private
void
invokeOnListener
(
Listener
listener
,
Event
event
)
{
private
void
checkAndFilter
(
Event
event
,
HandlerPriority
priority
)
{
try
{
this
.
listeners
.
stream
()
Class
<?>
listenerClass
=
listener
.
getClass
();
.
filter
(
handler
->
handler
.
handles
().
isInstance
(
event
))
Method
[]
methods
=
listenerClass
.
getMethods
();
.
filter
(
handler
->
handler
.
getPriority
()
==
priority
)
for
(
Method
method
:
methods
)
{
.
toList
().
forEach
(
handler
->
this
.
invokeHandler
(
event
,
handler
));
if
(!
method
.
isAnnotationPresent
(
EventHandler
.
class
))
return
;
}
if
(!
method
.
getParameterTypes
()[
0
].
isAssignableFrom
(
event
.
getClass
()))
return
;
method
.
invoke
(
listener
,
event
);
/**
}
* Performs logic checks then invokes the provided event handler.
}
catch
(
Exception
ignored
)
{
}
* @param event The event passed through to the handler.
* @param handler The handler to invoke.
*/
@SuppressWarnings
(
"unchecked"
)
private
<
T
extends
Event
>
void
invokeHandler
(
Event
event
,
EventHandler
<
T
>
handler
)
{
if
(!
event
.
isCanceled
()
||
(
event
.
isCanceled
()
&&
handler
.
ignoresCanceled
())
)
handler
.
getCallback
().
consume
((
T
)
event
);
}
}
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/plugin/api/ServerHook.java
View file @
c442039f
package
emu.grasscutter.plugin.api
;
package
emu.grasscutter.plugin.api
;
import
emu.grasscutter.command.Command
;
import
emu.grasscutter.command.CommandHandler
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.server.dispatch.DispatchServer
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.game.GameServer
;
import
java.util.LinkedList
;
import
java.util.LinkedList
;
...
@@ -11,7 +14,8 @@ import java.util.List;
...
@@ -11,7 +14,8 @@ import java.util.List;
*/
*/
public
final
class
ServerHook
{
public
final
class
ServerHook
{
private
static
ServerHook
instance
;
private
static
ServerHook
instance
;
private
final
GameServer
server
;
private
final
GameServer
gameServer
;
private
final
DispatchServer
dispatchServer
;
/**
/**
* Gets the server hook instance.
* Gets the server hook instance.
...
@@ -23,19 +27,47 @@ public final class ServerHook {
...
@@ -23,19 +27,47 @@ public final class ServerHook {
/**
/**
* Hooks into a server.
* Hooks into a server.
* @param server The server to hook into.
* @param gameServer The game server to hook into.
* @param dispatchServer The dispatch server to hook into.
*/
*/
public
ServerHook
(
GameServer
server
)
{
public
ServerHook
(
GameServer
gameServer
,
DispatchServer
dispatchServer
)
{
this
.
server
=
server
;
this
.
gameServer
=
gameServer
;
this
.
dispatchServer
=
dispatchServer
;
instance
=
this
;
instance
=
this
;
}
}
/**
* @return The game server.
*/
public
GameServer
getGameServer
()
{
return
this
.
gameServer
;
}
/**
* @return The dispatch server.
*/
public
DispatchServer
getDispatchServer
()
{
return
this
.
dispatchServer
;
}
/**
/**
* Gets all online players.
* Gets all online players.
* @return Players connected to the server.
* @return Players connected to the server.
*/
*/
public
List
<
Player
>
getOnlinePlayers
()
{
public
List
<
Player
>
getOnlinePlayers
()
{
return
new
LinkedList
<>(
this
.
server
.
getPlayers
().
values
());
return
new
LinkedList
<>(
this
.
gameServer
.
getPlayers
().
values
());
}
/**
* Registers a command to the {@link emu.grasscutter.command.CommandMap}.
* @param handler The command handler.
*/
public
void
registerCommand
(
CommandHandler
handler
)
{
Class
<?
extends
CommandHandler
>
clazz
=
handler
.
getClass
();
if
(!
clazz
.
isAnnotationPresent
(
Command
.
class
))
throw
new
IllegalArgumentException
(
"Command handler must be annotated with @Command."
);
Command
commandData
=
clazz
.
getAnnotation
(
Command
.
class
);
this
.
gameServer
.
getCommandMap
().
registerCommand
(
commandData
.
label
(),
handler
);
}
}
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java
View file @
c442039f
...
@@ -30,6 +30,7 @@ import java.net.BindException;
...
@@ -30,6 +30,7 @@ import java.net.BindException;
import
java.net.InetSocketAddress
;
import
java.net.InetSocketAddress
;
import
java.net.URI
;
import
java.net.URI
;
import
java.net.URLDecoder
;
import
java.net.URLDecoder
;
import
java.nio.charset.StandardCharsets
;
import
java.security.KeyStore
;
import
java.security.KeyStore
;
import
java.util.*
;
import
java.util.*
;
...
@@ -209,7 +210,7 @@ public final class DispatchServer {
...
@@ -209,7 +210,7 @@ public final class DispatchServer {
return
null
;
return
null
;
}
}
private
KeyManagerFactory
createKeyManagerFactory
(
File
keystore
,
String
password
)
throws
Exception
{
private
KeyManagerFactory
createKeyManagerFactory
(
File
keystore
,
String
password
)
{
char
[]
pass
=
password
.
toCharArray
();
char
[]
pass
=
password
.
toCharArray
();
KeyManagerFactory
kmf
=
null
;
KeyManagerFactory
kmf
=
null
;
...
@@ -220,8 +221,8 @@ public final class DispatchServer {
...
@@ -220,8 +221,8 @@ public final class DispatchServer {
kmf
=
KeyManagerFactory
.
getInstance
(
"SunX509"
);
kmf
=
KeyManagerFactory
.
getInstance
(
"SunX509"
);
kmf
.
init
(
ks
,
pass
);
kmf
.
init
(
ks
,
pass
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
xception
)
{
throw
e
;
Grasscutter
.
getLogger
().
error
(
"Unable to load keystore."
,
exception
)
;
}
}
return
kmf
;
return
kmf
;
...
@@ -243,10 +244,9 @@ public final class DispatchServer {
...
@@ -243,10 +244,9 @@ public final class DispatchServer {
try
{
try
{
kmf
=
createKeyManagerFactory
(
keystoreFile
,
"123456"
);
kmf
=
createKeyManagerFactory
(
keystoreFile
,
"123456"
);
Grasscutter
.
getLogger
().
warn
(
Grasscutter
.
getLogger
().
warn
(
"[Dispatch] The default keystore password was loaded successfully. Please consider setting the password to 123456 in config.json."
);
"[Dispatch] The default keystore password was loaded successfully. Please consider setting the password to
'
123456
'
in config.json."
);
}
catch
(
Exception
e2
)
{
}
catch
(
Exception
e2
)
{
Grasscutter
.
getLogger
().
warn
(
"[Dispatch] Error while loading keystore!"
);
Grasscutter
.
getLogger
().
warn
(
"[Dispatch] Error while loading keystore!"
,
e2
);
e2
.
printStackTrace
();
}
}
}
}
}
}
...
@@ -257,7 +257,7 @@ public final class DispatchServer {
...
@@ -257,7 +257,7 @@ public final class DispatchServer {
server
=
this
.
safelyCreateServer
(
this
.
getAddress
());
server
=
this
.
safelyCreateServer
(
this
.
getAddress
());
}
}
HttpsServer
httpsServer
=
null
;
HttpsServer
httpsServer
;
try
{
try
{
httpsServer
=
HttpsServer
.
create
(
getAddress
(),
0
);
httpsServer
=
HttpsServer
.
create
(
getAddress
(),
0
);
...
@@ -339,10 +339,6 @@ public final class DispatchServer {
...
@@ -339,10 +339,6 @@ public final class DispatchServer {
// added.
// added.
account
=
DatabaseHelper
.
createAccountWithId
(
requestData
.
account
,
0
);
account
=
DatabaseHelper
.
createAccountWithId
(
requestData
.
account
,
0
);
for
(
String
permission
:
Grasscutter
.
getConfig
().
getDispatchOptions
().
defaultPermissions
)
{
account
.
addPermission
(
permission
);
}
if
(
account
!=
null
)
{
if
(
account
!=
null
)
{
responseData
.
message
=
"OK"
;
responseData
.
message
=
"OK"
;
responseData
.
data
.
account
.
uid
=
account
.
getId
();
responseData
.
data
.
account
.
uid
=
account
.
getId
();
...
@@ -352,6 +348,9 @@ public final class DispatchServer {
...
@@ -352,6 +348,9 @@ public final class DispatchServer {
Grasscutter
.
getLogger
()
Grasscutter
.
getLogger
()
.
info
(
String
.
format
(
"[Dispatch] Client %s failed to log in: Account %s created"
,
.
info
(
String
.
format
(
"[Dispatch] Client %s failed to log in: Account %s created"
,
t
.
getRemoteAddress
(),
responseData
.
data
.
account
.
uid
));
t
.
getRemoteAddress
(),
responseData
.
data
.
account
.
uid
));
for
(
String
permission
:
Grasscutter
.
getConfig
().
getDispatchOptions
().
defaultPermissions
)
{
account
.
addPermission
(
permission
);
}
}
else
{
}
else
{
responseData
.
retcode
=
-
201
;
responseData
.
retcode
=
-
201
;
responseData
.
message
=
"Username not found, create failed."
;
responseData
.
message
=
"Username not found, create failed."
;
...
@@ -575,15 +574,11 @@ public final class DispatchServer {
...
@@ -575,15 +574,11 @@ public final class DispatchServer {
if
(
next
>
last
)
{
if
(
next
>
last
)
{
int
eqPos
=
qs
.
indexOf
(
'='
,
last
);
int
eqPos
=
qs
.
indexOf
(
'='
,
last
);
try
{
if
(
eqPos
<
0
||
eqPos
>
next
)
{
if
(
eqPos
<
0
||
eqPos
>
next
)
{
result
.
put
(
URLDecoder
.
decode
(
qs
.
substring
(
last
,
next
),
"utf-8"
),
""
);
result
.
put
(
URLDecoder
.
decode
(
qs
.
substring
(
last
,
next
),
StandardCharsets
.
UTF_8
),
""
);
}
else
{
}
else
{
result
.
put
(
URLDecoder
.
decode
(
qs
.
substring
(
last
,
eqPos
),
"utf-8"
),
result
.
put
(
URLDecoder
.
decode
(
qs
.
substring
(
last
,
eqPos
),
StandardCharsets
.
UTF_8
),
URLDecoder
.
decode
(
qs
.
substring
(
eqPos
+
1
,
next
),
"utf-8"
));
URLDecoder
.
decode
(
qs
.
substring
(
eqPos
+
1
,
next
),
StandardCharsets
.
UTF_8
));
}
}
catch
(
UnsupportedEncodingException
e
)
{
throw
new
RuntimeException
(
e
);
// will never happen, utf-8 support is mandatory for java
}
}
}
}
last
=
next
+
1
;
last
=
next
+
1
;
...
...
src/main/java/emu/grasscutter/server/event/EventHandler.java
View file @
c442039f
package
emu.grasscutter.server.event
;
package
emu.grasscutter.server.event
;
import
java.lang.annotation.Retention
;
import
emu.grasscutter.Grasscutter
;
import
java.lang.annotation.Ret
ent
i
on
Policy
;
import
emu.grasscutter.utils.Ev
ent
C
on
sumer
;
/**
public
final
class
EventHandler
<
T
extends
Event
>
{
* Declares a class as an event listener/handler.
private
final
Class
<
T
>
eventClass
;
private
EventConsumer
<
T
>
listener
;
private
HandlerPriority
priority
;
private
boolean
handleCanceled
;
public
EventHandler
(
Class
<
T
>
eventClass
)
{
this
.
eventClass
=
eventClass
;
}
/**
* Gets which event this handler is handling.
* @return An event class.
*/
public
Class
<
T
>
handles
()
{
return
this
.
eventClass
;
}
/**
* Returns the callback for the handler.
* @return A consumer callback.
*/
public
EventConsumer
<
T
>
getCallback
()
{
return
this
.
listener
;
}
/**
* Returns the handler's priority.
* @return The priority of the handler.
*/
public
HandlerPriority
getPriority
()
{
return
this
.
priority
;
}
/**
* Returns if the handler will ignore cancelled events.
* @return The ignore cancelled state.
*/
public
boolean
ignoresCanceled
()
{
return
this
.
handleCanceled
;
}
/**
* Sets the callback method for when the event is invoked.
* @param listener An event handler method.
* @return Method chaining.
*/
public
EventHandler
<
T
>
listener
(
EventConsumer
<
T
>
listener
)
{
this
.
listener
=
listener
;
return
this
;
}
/**
* Changes the handler's priority in handling events.
* @param priority The priority of the handler.
* @return Method chaining.
*/
public
EventHandler
<
T
>
priority
(
HandlerPriority
priority
)
{
this
.
priority
=
priority
;
return
this
;
}
/**
* Sets if the handler will ignore cancelled events.
* @param ignore If the handler should ignore cancelled events.
* @return Method chaining.
*/
public
EventHandler
<
T
>
ignore
(
boolean
ignore
)
{
this
.
handleCanceled
=
ignore
;
return
this
;
}
/**
* Registers the handler into the PluginManager.
*/
*/
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
void
register
()
{
public
@interface
EventHandler
{
Grasscutter
.
getPluginManager
().
registerListener
(
this
);
}
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/server/event/HandlerPriority.java
0 → 100644
View file @
c442039f
package
emu.grasscutter.server.event
;
public
enum
HandlerPriority
{
/**
* The handler will be called before every other handler.
*/
HIGH
,
/**
* The handler will be called the same time as other handlers.
*/
NORMAL
,
/**
* The handler will be called after every other handler.
*/
LOW
}
src/main/java/emu/grasscutter/server/event/Listener.java
deleted
100644 → 0
View file @
d133e556
package
emu.grasscutter.server.event
;
/**
* Implementing this interface declares a class as an event listener.
*/
public
interface
Listener
{
}
src/main/java/emu/grasscutter/server/event/dispatch/QueryAllRegionsEvent.java
View file @
c442039f
package
emu.grasscutter.server.event.dispatch
;
package
emu.grasscutter.server.event.dispatch
;
import
emu.grasscutter.server.event.ServerEvent
;
import
emu.grasscutter.server.event.
types.
ServerEvent
;
public
final
class
QueryAllRegionsEvent
extends
ServerEvent
{
public
final
class
QueryAllRegionsEvent
extends
ServerEvent
{
private
String
regionList
;
private
String
regionList
;
...
...
src/main/java/emu/grasscutter/server/event/dispatch/QueryCurrentRegionEvent.java
View file @
c442039f
package
emu.grasscutter.server.event.dispatch
;
package
emu.grasscutter.server.event.dispatch
;
import
emu.grasscutter.server.event.ServerEvent
;
import
emu.grasscutter.server.event.
types.
ServerEvent
;
public
final
class
QueryCurrentRegionEvent
extends
ServerEvent
{
public
final
class
QueryCurrentRegionEvent
extends
ServerEvent
{
private
String
regionInfo
;
private
String
regionInfo
;
...
...
src/main/java/emu/grasscutter/server/event/game/PlayerCreationEvent.java
0 → 100644
View file @
c442039f
package
emu.grasscutter.server.event.game
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.server.event.types.GameEvent
;
import
emu.grasscutter.server.game.GameSession
;
public
final
class
PlayerCreationEvent
extends
GameEvent
{
private
final
GameSession
session
;
private
Class
<?
extends
Player
>
playerClass
;
public
PlayerCreationEvent
(
GameSession
session
,
Class
<?
extends
Player
>
playerClass
)
{
this
.
session
=
session
;
this
.
playerClass
=
playerClass
;
}
public
GameSession
getSession
()
{
return
this
.
session
;
}
public
void
setPlayerClass
(
Class
<?
extends
Player
>
playerClass
)
{
this
.
playerClass
=
playerClass
;
}
public
Class
<?
extends
Player
>
getPlayerClass
()
{
return
this
.
playerClass
;
}
}
src/main/java/emu/grasscutter/server/event/game/ReceivePacketEvent.java
View file @
c442039f
package
emu.grasscutter.server.event.game
;
package
emu.grasscutter.server.event.game
;
import
emu.grasscutter.server.event.Cancellable
;
import
emu.grasscutter.server.event.Cancellable
;
import
emu.grasscutter.server.event.ServerEvent
;
import
emu.grasscutter.server.event.
types.
ServerEvent
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.game.GameSession
;
public
final
class
ReceivePacketEvent
extends
ServerEvent
implements
Cancellable
{
public
final
class
ReceivePacketEvent
extends
ServerEvent
implements
Cancellable
{
...
...
src/main/java/emu/grasscutter/server/event/game/SendPacketEvent.java
View file @
c442039f
...
@@ -2,7 +2,7 @@ package emu.grasscutter.server.event.game;
...
@@ -2,7 +2,7 @@ package emu.grasscutter.server.event.game;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.server.event.Cancellable
;
import
emu.grasscutter.server.event.Cancellable
;
import
emu.grasscutter.server.event.ServerEvent
;
import
emu.grasscutter.server.event.
types.
ServerEvent
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.game.GameSession
;
public
final
class
SendPacketEvent
extends
ServerEvent
implements
Cancellable
{
public
final
class
SendPacketEvent
extends
ServerEvent
implements
Cancellable
{
...
...
src/main/java/emu/grasscutter/server/event/game/ServerTickEvent.java
View file @
c442039f
package
emu.grasscutter.server.event.game
;
package
emu.grasscutter.server.event.game
;
import
emu.grasscutter.server.event.ServerEvent
;
import
emu.grasscutter.server.event.
types.
ServerEvent
;
public
final
class
ServerTickEvent
extends
ServerEvent
{
public
final
class
ServerTickEvent
extends
ServerEvent
{
public
ServerTickEvent
()
{
public
ServerTickEvent
()
{
...
...
src/main/java/emu/grasscutter/server/event/internal/ServerStartEvent.java
View file @
c442039f
package
emu.grasscutter.server.event.internal
;
package
emu.grasscutter.server.event.internal
;
import
emu.grasscutter.server.event.ServerEvent
;
import
emu.grasscutter.server.event.
types.
ServerEvent
;
import
java.time.OffsetDateTime
;
import
java.time.OffsetDateTime
;
...
...
Prev
1
2
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