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
812f4b37
Commit
812f4b37
authored
May 11, 2022
by
KingRainbow44
Browse files
Fix `ClassDefNotFound` & `NullPointerException` errors
parent
0b3e2b30
Changes
5
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/Configuration.java
View file @
812f4b37
package
emu.grasscutter
;
package
emu.grasscutter
;
import
com.google.gson.JsonObject
;
import
emu.grasscutter.utils.ConfigContainer
;
import
emu.grasscutter.Grasscutter.*
;
import
emu.grasscutter.game.mail.Mail.*
;
import
java.io.FileReader
;
import
java.lang.reflect.Field
;
import
java.util.Arrays
;
import
java.util.Locale
;
import
java.util.Locale
;
import
static
emu
.
grasscutter
.
Grasscutter
.
config
;
import
static
emu
.
grasscutter
.
Grasscutter
.
config
;
...
@@ -17,56 +12,14 @@ import static emu.grasscutter.Grasscutter.config;
...
@@ -17,56 +12,14 @@ import static emu.grasscutter.Grasscutter.config;
* Use `import static emu.grasscutter.Configuration.*;`
* Use `import static emu.grasscutter.Configuration.*;`
* to import all configuration constants.
* to import all configuration constants.
*/
*/
public
final
class
Configuration
{
public
final
class
Configuration
extends
ConfigContainer
{
private
static
int
version
()
{
return
1
;
}
/**
* Attempts to update the server's existing configuration to the latest configuration.
*/
public
static
void
updateConfig
()
{
try
{
// Check if the server is using a legacy config.
JsonObject
configObject
=
Grasscutter
.
getGsonFactory
()
.
fromJson
(
new
FileReader
(
Grasscutter
.
configFile
),
JsonObject
.
class
);
if
(!
configObject
.
has
(
"version"
))
{
Grasscutter
.
getLogger
().
info
(
"Updating legacy configuration..."
);
Grasscutter
.
saveConfig
(
null
);
}
}
catch
(
Exception
ignored
)
{
}
var
existing
=
config
.
version
;
var
latest
=
version
();
if
(
existing
==
latest
)
return
;
// Create a new configuration instance.
Configuration
updated
=
new
Configuration
();
// Update all configuration fields.
Field
[]
fields
=
Configuration
.
class
.
getDeclaredFields
();
Arrays
.
stream
(
fields
).
forEach
(
field
->
{
try
{
field
.
set
(
updated
,
field
.
get
(
config
));
}
catch
(
Exception
exception
)
{
Grasscutter
.
getLogger
().
error
(
"Failed to update a configuration field."
,
exception
);
}
});
try
{
// Save configuration & reload.
Grasscutter
.
saveConfig
(
updated
);
Grasscutter
.
reloadConfig
();
}
catch
(
Exception
exception
)
{
Grasscutter
.
getLogger
().
warn
(
"Failed to inject the updated configuration."
,
exception
);
}
}
/*
/*
* Constants
* Constants
*/
*/
// 'c' is short for 'config' and makes code look 'cleaner'.
// 'c' is short for 'config' and makes code look 'cleaner'.
public
static
final
Config
uration
c
=
config
;
public
static
final
Config
Container
c
=
config
;
public
static
final
Locale
LANGUAGE
=
config
.
language
.
language
;
public
static
final
Locale
LANGUAGE
=
config
.
language
.
language
;
public
static
final
Locale
FALLBACK_LANGUAGE
=
config
.
language
.
fallback
;
public
static
final
Locale
FALLBACK_LANGUAGE
=
config
.
language
.
fallback
;
...
@@ -135,178 +88,4 @@ public final class Configuration {
...
@@ -135,178 +88,4 @@ public final class Configuration {
public
static
int
lr
(
int
left
,
int
right
)
{
public
static
int
lr
(
int
left
,
int
right
)
{
return
left
==
0
?
right
:
left
;
return
left
==
0
?
right
:
left
;
}
}
/*
* Configuration data.
*/
public
Structure
folderStructure
;
public
Database
databaseInfo
;
public
Language
language
;
public
Account
account
;
public
Server
server
;
// DO NOT. TOUCH. THE VERSION NUMBER.
public
int
version
=
version
();
/* Option containers. */
public
static
class
Database
{
public
String
connectionUri
=
"mongodb://localhost:27017"
;
public
String
collection
=
"grasscutter"
;
}
public
static
class
Structure
{
public
String
resources
=
"./resources/"
;
public
String
data
=
"./data/"
;
public
String
packets
=
"./packets/"
;
public
String
keys
=
"./keys/"
;
public
String
scripts
=
"./resources/scripts/"
;
public
String
plugins
=
"./plugins/"
;
// UNUSED (potentially added later?)
// public String dumps = "./dumps/";
}
public
static
class
Server
{
public
ServerDebugMode
debugLevel
=
ServerDebugMode
.
NONE
;
public
ServerRunMode
runMode
=
ServerRunMode
.
HYBRID
;
public
Dispatch
dispatch
=
new
Dispatch
();
public
Game
game
=
new
Game
();
}
public
static
class
Language
{
public
Locale
language
=
Locale
.
getDefault
();
public
Locale
fallback
=
Locale
.
US
;
}
public
static
class
Account
{
public
boolean
autoCreate
=
false
;
public
String
[]
defaultPermissions
=
{};
}
/* Server options. */
public
static
class
Dispatch
{
public
String
bindAddress
=
"0.0.0.0"
;
/* This is the address used in URLs. */
public
String
accessAddress
=
"127.0.0.1"
;
public
int
bindPort
=
443
;
/* This is the port used in URLs. */
public
int
accessPort
=
443
;
public
Encryption
encryption
=
new
Encryption
();
public
Policies
policies
=
new
Policies
();
public
Region
[]
regions
=
{};
public
String
defaultName
=
"Grasscutter"
;
}
public
static
class
Game
{
public
String
bindAddress
=
"0.0.0.0"
;
/* This is the address used in the default region. */
public
String
accessAddress
=
"127.0.0.1"
;
public
int
bindPort
=
443
;
/* This is the port used in the default region. */
public
int
accessPort
=
443
;
public
GameOptions
gameOptions
=
new
GameOptions
();
public
JoinOptions
joinOptions
=
new
JoinOptions
();
public
ConsoleAccount
serverAccount
=
new
ConsoleAccount
();
}
/* Data containers. */
public
static
class
Encryption
{
public
boolean
useEncryption
=
true
;
/* Should 'https' be appended to URLs? */
public
boolean
useInRouting
=
true
;
public
String
keystore
=
"./keystore.p12"
;
public
String
keystorePassword
=
"123456"
;
}
public
static
class
Policies
{
public
CORS
cors
=
new
CORS
();
public
static
class
CORS
{
public
boolean
enabled
=
false
;
public
String
[]
allowedOrigins
=
new
String
[]{
"*"
};
}
}
public
static
class
GameOptions
{
public
InventoryLimits
inventoryLimits
=
new
InventoryLimits
();
public
AvatarLimits
avatarLimits
=
new
AvatarLimits
();
public
int
worldEntityLimit
=
1000
;
// Unenforced. TODO: Implement.
public
boolean
watchGachaConfig
=
false
;
public
boolean
enableShopItems
=
true
;
public
boolean
staminaUsage
=
true
;
public
Rates
rates
=
new
Rates
();
public
Database
databaseInfo
=
new
Database
();
public
static
class
InventoryLimits
{
public
int
weapons
=
2000
;
public
int
relics
=
2000
;
public
int
materials
=
2000
;
public
int
furniture
=
2000
;
public
int
all
=
30000
;
}
public
static
class
AvatarLimits
{
public
int
singlePlayerTeam
=
4
;
public
int
multiplayerTeam
=
4
;
}
public
static
class
Rates
{
public
float
adventureExp
=
1.0f
;
public
float
mora
=
1.0f
;
public
float
leyLines
=
1.0f
;
}
}
public
static
class
JoinOptions
{
public
int
[]
welcomeEmotes
=
{
2007
,
1002
,
4010
};
public
String
welcomeMessage
=
"Welcome to a Grasscutter server."
;
public
Mail
welcomeMail
=
new
Mail
();
public
static
class
Mail
{
public
String
title
=
"Welcome to Grasscutter!"
;
public
String
content
=
"""
Hi there!\r
First of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r
\r
Check out our:\r
<type="
browser
" text="
Discord
" href="
https:
//discord.gg/T5vZU6UyeG"/>
""";
public String sender = "
Lawnmower
";
public MailItem[] items = {
new MailItem(13509, 1, 1),
new MailItem(201, 99999, 1)
};
}
}
public static class ConsoleAccount {
public int avatarId = 10000007;
public int nameCardId = 210001;
public int adventureRank = 1;
public int worldLevel = 0;
public String nickName = "
Server
";
public String signature = "
Welcome
to
Grasscutter
!
";
}
/* Objects. */
public static class Region {
public String Name = "
os_usa
";
public String Title = "
Grasscutter
";
public String Ip = "
127.0
.
0.1
"
;
public
int
Port
=
22102
;
}
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/Grasscutter.java
View file @
812f4b37
package
emu.grasscutter
;
package
emu.grasscutter
;
import
java.io.*
;
import
java.io.*
;
import
java.lang.reflect.Field
;
import
java.util.Arrays
;
import
java.util.Calendar
;
import
java.util.Calendar
;
import
emu.grasscutter.command.CommandMap
;
import
emu.grasscutter.command.CommandMap
;
import
emu.grasscutter.plugin.PluginManager
;
import
emu.grasscutter.plugin.PluginManager
;
import
emu.grasscutter.plugin.api.ServerHook
;
import
emu.grasscutter.plugin.api.ServerHook
;
import
emu.grasscutter.scripts.ScriptLoader
;
import
emu.grasscutter.scripts.ScriptLoader
;
import
emu.grasscutter.utils.ConfigContainer
;
import
emu.grasscutter.utils.Utils
;
import
emu.grasscutter.utils.Utils
;
import
org.jline.reader.EndOfFileException
;
import
org.jline.reader.EndOfFileException
;
import
org.jline.reader.LineReader
;
import
org.jline.reader.LineReader
;
...
@@ -52,16 +51,16 @@ public final class Grasscutter {
...
@@ -52,16 +51,16 @@ public final class Grasscutter {
private
static
PluginManager
pluginManager
;
private
static
PluginManager
pluginManager
;
public
static
final
Reflections
reflector
=
new
Reflections
(
"emu.grasscutter"
);
public
static
final
Reflections
reflector
=
new
Reflections
(
"emu.grasscutter"
);
public
static
final
Configuration
config
;
public
static
ConfigContainer
config
;
static
{
static
{
// Declare logback configuration.
// Declare logback configuration.
System
.
setProperty
(
"logback.configurationFile"
,
"src/main/resources/logback.xml"
);
System
.
setProperty
(
"logback.configurationFile"
,
"src/main/resources/logback.xml"
);
// Load server configuration.
// Load server configuration.
config
=
Grasscutter
.
loadConfig
();
Grasscutter
.
loadConfig
();
// Attempt to update configuration.
// Attempt to update configuration.
Config
uration
.
updateConfig
();
Config
Container
.
updateConfig
();
// Load translation files.
// Load translation files.
Grasscutter
.
loadLanguage
();
Grasscutter
.
loadLanguage
();
...
@@ -144,34 +143,20 @@ public final class Grasscutter {
...
@@ -144,34 +143,20 @@ public final class Grasscutter {
/**
/**
* Attempts to load the configuration from a file.
* Attempts to load the configuration from a file.
* @return The config from the file, or a new instance.
*/
*/
public
static
Configuration
loadConfig
()
{
public
static
void
loadConfig
()
{
try
(
FileReader
file
=
new
FileReader
(
configFile
))
{
try
(
FileReader
file
=
new
FileReader
(
configFile
))
{
return
gson
.
fromJson
(
file
,
Configuration
.
class
);
config
=
gson
.
fromJson
(
file
,
ConfigContainer
.
class
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
exception
)
{
Grasscutter
.
saveConfig
(
null
);
config
=
new
ConfigContainer
();
}
catch
(
Error
error
)
{
// Occurred probably from an outdated config file.
Grasscutter
.
saveConfig
(
null
);
Grasscutter
.
saveConfig
(
null
);
return
new
Config
uration
();
config
=
new
Config
Container
();
}
}
}
}
/**
* Attempts to reload the configuration from the file.
* Uses reflection to **replace** the fields in the config.
*/
public
static
void
reloadConfig
()
{
Configuration
fileConfig
=
Grasscutter
.
loadConfig
();
Field
[]
fields
=
Configuration
.
class
.
getDeclaredFields
();
Arrays
.
stream
(
fields
).
forEach
(
field
->
{
try
{
field
.
set
(
config
,
field
.
get
(
fileConfig
));
}
catch
(
Exception
exception
)
{
Grasscutter
.
getLogger
().
error
(
"Failed to update a configuration field."
,
exception
);
}
});
}
public
static
void
loadLanguage
()
{
public
static
void
loadLanguage
()
{
var
locale
=
config
.
language
.
language
;
var
locale
=
config
.
language
.
language
;
language
=
Language
.
getLanguage
(
Utils
.
getLanguageCode
(
locale
));
language
=
Language
.
getLanguage
(
Utils
.
getLanguageCode
(
locale
));
...
@@ -181,8 +166,8 @@ public final class Grasscutter {
...
@@ -181,8 +166,8 @@ public final class Grasscutter {
* Saves the provided server configuration.
* Saves the provided server configuration.
* @param config The configuration to save, or null for a new one.
* @param config The configuration to save, or null for a new one.
*/
*/
public
static
void
saveConfig
(
@Nullable
Config
uration
config
)
{
public
static
void
saveConfig
(
@Nullable
Config
Container
config
)
{
if
(
config
==
null
)
config
=
new
Config
uration
();
if
(
config
==
null
)
config
=
new
Config
Container
();
try
(
FileWriter
file
=
new
FileWriter
(
configFile
))
{
try
(
FileWriter
file
=
new
FileWriter
(
configFile
))
{
file
.
write
(
gson
.
toJson
(
config
));
file
.
write
(
gson
.
toJson
(
config
));
...
@@ -231,7 +216,7 @@ public final class Grasscutter {
...
@@ -231,7 +216,7 @@ public final class Grasscutter {
}
}
}
}
public
static
Config
uration
getConfig
()
{
public
static
Config
Container
getConfig
()
{
return
config
;
return
config
;
}
}
...
...
src/main/java/emu/grasscutter/command/commands/ReloadCommand.java
View file @
812f4b37
...
@@ -16,7 +16,7 @@ public final class ReloadCommand implements CommandHandler {
...
@@ -16,7 +16,7 @@ public final class ReloadCommand implements CommandHandler {
public
void
execute
(
Player
sender
,
Player
targetPlayer
,
List
<
String
>
args
)
{
public
void
execute
(
Player
sender
,
Player
targetPlayer
,
List
<
String
>
args
)
{
CommandHandler
.
sendMessage
(
sender
,
translate
(
sender
,
"commands.reload.reload_start"
));
CommandHandler
.
sendMessage
(
sender
,
translate
(
sender
,
"commands.reload.reload_start"
));
Grasscutter
.
re
loadConfig
();
Grasscutter
.
loadConfig
();
Grasscutter
.
loadLanguage
();
Grasscutter
.
loadLanguage
();
Grasscutter
.
getGameServer
().
getGachaManager
().
load
();
Grasscutter
.
getGameServer
().
getGachaManager
().
load
();
Grasscutter
.
getGameServer
().
getDropManager
().
load
();
Grasscutter
.
getGameServer
().
getDropManager
().
load
();
...
...
src/main/java/emu/grasscutter/utils/ConfigContainer.java
0 → 100644
View file @
812f4b37
package
emu.grasscutter.utils
;
import
com.google.gson.JsonObject
;
import
emu.grasscutter.Grasscutter
;
import
java.io.FileReader
;
import
java.lang.reflect.Field
;
import
java.util.Arrays
;
import
java.util.Locale
;
import
static
emu
.
grasscutter
.
Grasscutter
.
config
;
/**
* *when your JVM fails*
*/
public
class
ConfigContainer
{
private
static
int
version
()
{
return
1
;
}
/**
* Attempts to update the server's existing configuration to the latest
*/
public
static
void
updateConfig
()
{
try
{
// Check if the server is using a legacy config.
JsonObject
configObject
=
Grasscutter
.
getGsonFactory
()
.
fromJson
(
new
FileReader
(
Grasscutter
.
configFile
),
JsonObject
.
class
);
if
(!
configObject
.
has
(
"version"
))
{
Grasscutter
.
getLogger
().
info
(
"Updating legacy .."
);
Grasscutter
.
saveConfig
(
null
);
}
}
catch
(
Exception
ignored
)
{
}
var
existing
=
config
.
version
;
var
latest
=
version
();
if
(
existing
==
latest
)
return
;
// Create a new configuration instance.
ConfigContainer
updated
=
new
ConfigContainer
();
// Update all configuration fields.
Field
[]
fields
=
ConfigContainer
.
class
.
getDeclaredFields
();
Arrays
.
stream
(
fields
).
forEach
(
field
->
{
try
{
field
.
set
(
updated
,
field
.
get
(
config
));
}
catch
(
Exception
exception
)
{
Grasscutter
.
getLogger
().
error
(
"Failed to update a configuration field."
,
exception
);
}
});
updated
.
version
=
version
();
try
{
// Save configuration & reload.
Grasscutter
.
saveConfig
(
updated
);
Grasscutter
.
loadConfig
();
}
catch
(
Exception
exception
)
{
Grasscutter
.
getLogger
().
warn
(
"Failed to inject the updated "
,
exception
);
}
}
public
Structure
folderStructure
=
new
Structure
();
public
Database
databaseInfo
=
new
Database
();
public
Language
language
=
new
Language
();
public
Account
account
=
new
Account
();
public
Server
server
=
new
Server
();
// DO NOT. TOUCH. THE VERSION NUMBER.
public
int
version
=
version
();
/* Option containers. */
public
static
class
Database
{
public
String
connectionUri
=
"mongodb://localhost:27017"
;
public
String
collection
=
"grasscutter"
;
}
public
static
class
Structure
{
public
String
resources
=
"./resources/"
;
public
String
data
=
"./data/"
;
public
String
packets
=
"./packets/"
;
public
String
keys
=
"./keys/"
;
public
String
scripts
=
"./resources/scripts/"
;
public
String
plugins
=
"./plugins/"
;
// UNUSED (potentially added later?)
// public String dumps = "./dumps/";
}
public
static
class
Server
{
public
Grasscutter
.
ServerDebugMode
debugLevel
=
Grasscutter
.
ServerDebugMode
.
NONE
;
public
Grasscutter
.
ServerRunMode
runMode
=
Grasscutter
.
ServerRunMode
.
HYBRID
;
public
Dispatch
dispatch
=
new
Dispatch
();
public
Game
game
=
new
Game
();
}
public
static
class
Language
{
public
Locale
language
=
Locale
.
getDefault
();
public
Locale
fallback
=
Locale
.
US
;
}
public
static
class
Account
{
public
boolean
autoCreate
=
false
;
public
String
[]
defaultPermissions
=
{};
}
/* Server options. */
public
static
class
Dispatch
{
public
String
bindAddress
=
"0.0.0.0"
;
/* This is the address used in URLs. */
public
String
accessAddress
=
"127.0.0.1"
;
public
int
bindPort
=
443
;
/* This is the port used in URLs. */
public
int
accessPort
=
443
;
public
Encryption
encryption
=
new
Encryption
();
public
Policies
policies
=
new
Policies
();
public
Region
[]
regions
=
{};
public
String
defaultName
=
"Grasscutter"
;
}
public
static
class
Game
{
public
String
bindAddress
=
"0.0.0.0"
;
/* This is the address used in the default region. */
public
String
accessAddress
=
"127.0.0.1"
;
public
int
bindPort
=
443
;
/* This is the port used in the default region. */
public
int
accessPort
=
443
;
public
GameOptions
gameOptions
=
new
GameOptions
();
public
JoinOptions
joinOptions
=
new
JoinOptions
();
public
ConsoleAccount
serverAccount
=
new
ConsoleAccount
();
}
/* Data containers. */
public
static
class
Encryption
{
public
boolean
useEncryption
=
true
;
/* Should 'https' be appended to URLs? */
public
boolean
useInRouting
=
true
;
public
String
keystore
=
"./keystore.p12"
;
public
String
keystorePassword
=
"123456"
;
}
public
static
class
Policies
{
public
Policies
.
CORS
cors
=
new
Policies
.
CORS
();
public
static
class
CORS
{
public
boolean
enabled
=
false
;
public
String
[]
allowedOrigins
=
new
String
[]{
"*"
};
}
}
public
static
class
GameOptions
{
public
GameOptions
.
InventoryLimits
inventoryLimits
=
new
GameOptions
.
InventoryLimits
();
public
GameOptions
.
AvatarLimits
avatarLimits
=
new
GameOptions
.
AvatarLimits
();
public
int
worldEntityLimit
=
1000
;
// Unenforced. TODO: Implement.
public
boolean
watchGachaConfig
=
false
;
public
boolean
enableShopItems
=
true
;
public
boolean
staminaUsage
=
true
;
public
GameOptions
.
Rates
rates
=
new
GameOptions
.
Rates
();
public
Database
databaseInfo
=
new
Database
();
public
static
class
InventoryLimits
{
public
int
weapons
=
2000
;
public
int
relics
=
2000
;
public
int
materials
=
2000
;
public
int
furniture
=
2000
;
public
int
all
=
30000
;
}
public
static
class
AvatarLimits
{
public
int
singlePlayerTeam
=
4
;
public
int
multiplayerTeam
=
4
;
}
public
static
class
Rates
{
public
float
adventureExp
=
1.0f
;
public
float
mora
=
1.0f
;
public
float
leyLines
=
1.0f
;
}
}
public
static
class
JoinOptions
{
public
int
[]
welcomeEmotes
=
{
2007
,
1002
,
4010
};
public
String
welcomeMessage
=
"Welcome to a Grasscutter server."
;
public
JoinOptions
.
Mail
welcomeMail
=
new
JoinOptions
.
Mail
();
public
static
class
Mail
{
public
String
title
=
"Welcome to Grasscutter!"
;
public
String
content
=
"""
Hi there!\r
First of all, welcome to Grasscutter. If you have any issues, please let us know so that Lawnmower can help you! \r
\r
Check out our:\r
<type="
browser
" text="
Discord
" href="
https:
//discord.gg/T5vZU6UyeG"/>
""";
public String sender = "
Lawnmower
";
public emu.grasscutter.game.mail.Mail.MailItem[] items = {
new emu.grasscutter.game.mail.Mail.MailItem(13509, 1, 1),
new emu.grasscutter.game.mail.Mail.MailItem(201, 99999, 1)
};
}
}
public static class ConsoleAccount {
public int avatarId = 10000007;
public int nameCardId = 210001;
public int adventureRank = 1;
public int worldLevel = 0;
public String nickName = "
Server
";
public String signature = "
Welcome
to
Grasscutter
!
";
}
/* Objects. */
public static class Region {
public String Name = "
os_usa
";
public String Title = "
Grasscutter
";
public String Ip = "
127.0
.
0.1
"
;
public
int
Port
=
22102
;
}
}
src/main/java/emu/grasscutter/utils/Utils.java
View file @
812f4b37
...
@@ -11,7 +11,6 @@ import java.util.Map;
...
@@ -11,7 +11,6 @@ import java.util.Map;
import
java.util.Random
;
import
java.util.Random
;
import
java.util.Locale
;
import
java.util.Locale
;
import
emu.grasscutter.Configuration
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
io.netty.buffer.ByteBuf
;
import
io.netty.buffer.ByteBuf
;
import
io.netty.buffer.ByteBufUtil
;
import
io.netty.buffer.ByteBufUtil
;
...
@@ -175,7 +174,7 @@ public final class Utils {
...
@@ -175,7 +174,7 @@ public final class Utils {
* Checks for required files and folders before startup.
* Checks for required files and folders before startup.
*/
*/
public
static
void
startupCheck
()
{
public
static
void
startupCheck
()
{
Config
uration
config
=
Grasscutter
.
getConfig
();
Config
Container
config
=
Grasscutter
.
getConfig
();
Logger
logger
=
Grasscutter
.
getLogger
();
Logger
logger
=
Grasscutter
.
getLogger
();
boolean
exit
=
false
;
boolean
exit
=
false
;
...
...
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