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
eac3745f
Commit
eac3745f
authored
Apr 19, 2022
by
Jaida Wu
Committed by
GitHub
Apr 19, 2022
Browse files
Merge branch 'Melledy:main' into main
parents
49f640cb
3e7dc503
Changes
21
Expand all
Show whitespace changes
Inline
Side-by-side
src/deprecated/java/emu/grasscutter/commands/PlayerCommands.java
0 → 100644
View file @
eac3745f
package
emu.grasscutter.commands
;
import
java.lang.reflect.Modifier
;
import
java.util.HashMap
;
import
java.util.LinkedList
;
import
java.util.List
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.def.ItemData
;
import
emu.grasscutter.data.def.MonsterData
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.avatar.GenshinAvatar
;
import
emu.grasscutter.game.entity.EntityAvatar
;
import
emu.grasscutter.game.entity.EntityItem
;
import
emu.grasscutter.game.entity.EntityMonster
;
import
emu.grasscutter.game.entity.GenshinEntity
;
import
emu.grasscutter.game.inventory.GenshinItem
;
import
emu.grasscutter.game.inventory.ItemType
;
import
emu.grasscutter.game.props.ActionReason
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketItemAddHintNotify
;
import
emu.grasscutter.utils.Position
;
public
class
PlayerCommands
{
private
static
HashMap
<
String
,
PlayerCommand
>
list
=
new
HashMap
<>();
static
{
try
{
// Look for classes
for
(
Class
<?>
cls
:
PlayerCommands
.
class
.
getDeclaredClasses
())
{
// Get non abstract classes
if
(!
Modifier
.
isAbstract
(
cls
.
getModifiers
()))
{
Command
commandAnnotation
=
cls
.
getAnnotation
(
Command
.
class
);
PlayerCommand
command
=
(
PlayerCommand
)
cls
.
newInstance
();
if
(
commandAnnotation
!=
null
)
{
command
.
setLevel
(
commandAnnotation
.
gmLevel
());
for
(
String
alias
:
commandAnnotation
.
aliases
())
{
if
(
alias
.
length
()
==
0
)
{
continue
;
}
String
commandName
=
"!"
+
alias
;
list
.
put
(
commandName
,
command
);
commandName
=
"/"
+
alias
;
list
.
put
(
commandName
,
command
);
}
}
String
commandName
=
"!"
+
cls
.
getSimpleName
().
toLowerCase
();
list
.
put
(
commandName
,
command
);
commandName
=
"/"
+
cls
.
getSimpleName
().
toLowerCase
();
list
.
put
(
commandName
,
command
);
}
}
}
catch
(
Exception
e
)
{
}
}
public
static
void
handle
(
GenshinPlayer
player
,
String
msg
)
{
String
[]
split
=
msg
.
split
(
" "
);
// End if invalid
if
(
split
.
length
==
0
)
{
return
;
}
//
String
first
=
split
[
0
].
toLowerCase
();
PlayerCommand
c
=
PlayerCommands
.
list
.
get
(
first
);
if
(
c
!=
null
)
{
// Level check
if
(
player
.
getGmLevel
()
<
c
.
getLevel
())
{
return
;
}
// Execute
int
len
=
Math
.
min
(
first
.
length
()
+
1
,
msg
.
length
());
c
.
execute
(
player
,
msg
.
substring
(
len
));
}
}
public
static
abstract
class
PlayerCommand
{
// GM level required to use this command
private
int
level
;
protected
int
getLevel
()
{
return
this
.
level
;
}
protected
void
setLevel
(
int
minLevel
)
{
this
.
level
=
minLevel
;
}
// Main
public
abstract
void
execute
(
GenshinPlayer
player
,
String
raw
);
}
// ================ Commands ================
@Command
(
aliases
=
{
"g"
,
"item"
,
"additem"
},
helpText
=
"/give [item id] [count] - Gives {count} amount of {item id}"
)
public
static
class
Give
extends
PlayerCommand
{
@Override
public
void
execute
(
GenshinPlayer
player
,
String
raw
)
{
String
[]
split
=
raw
.
split
(
" "
);
int
itemId
=
0
,
count
=
1
;
try
{
itemId
=
Integer
.
parseInt
(
split
[
0
]);
}
catch
(
Exception
e
)
{
itemId
=
0
;
}
try
{
count
=
Math
.
max
(
Math
.
min
(
Integer
.
parseInt
(
split
[
1
]),
Integer
.
MAX_VALUE
),
1
);
}
catch
(
Exception
e
)
{
count
=
1
;
}
// Give
ItemData
itemData
=
GenshinData
.
getItemDataMap
().
get
(
itemId
);
GenshinItem
item
;
if
(
itemData
==
null
)
{
player
.
dropMessage
(
"Error: Item data not found"
);
return
;
}
if
(
itemData
.
isEquip
())
{
List
<
GenshinItem
>
items
=
new
LinkedList
<>();
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
item
=
new
GenshinItem
(
itemData
);
items
.
add
(
item
);
}
player
.
getInventory
().
addItems
(
items
);
player
.
sendPacket
(
new
PacketItemAddHintNotify
(
items
,
ActionReason
.
SubfieldDrop
));
}
else
{
item
=
new
GenshinItem
(
itemData
,
count
);
player
.
getInventory
().
addItem
(
item
);
player
.
sendPacket
(
new
PacketItemAddHintNotify
(
item
,
ActionReason
.
SubfieldDrop
));
}
}
}
@Command
(
aliases
=
{
"d"
},
helpText
=
"/drop [item id] [count] - Drops {count} amount of {item id}"
)
public
static
class
Drop
extends
PlayerCommand
{
@Override
public
void
execute
(
GenshinPlayer
player
,
String
raw
)
{
String
[]
split
=
raw
.
split
(
" "
);
int
itemId
=
0
,
count
=
1
;
try
{
itemId
=
Integer
.
parseInt
(
split
[
0
]);
}
catch
(
Exception
e
)
{
itemId
=
0
;
}
try
{
count
=
Math
.
max
(
Math
.
min
(
Integer
.
parseInt
(
split
[
1
]),
Integer
.
MAX_VALUE
),
1
);
}
catch
(
Exception
e
)
{
count
=
1
;
}
// Give
ItemData
itemData
=
GenshinData
.
getItemDataMap
().
get
(
itemId
);
if
(
itemData
==
null
)
{
player
.
dropMessage
(
"Error: Item data not found"
);
return
;
}
if
(
itemData
.
isEquip
())
{
float
range
=
(
5
f
+
(.
1
f
*
count
));
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
Position
pos
=
player
.
getPos
().
clone
().
addX
((
float
)
(
Math
.
random
()
*
range
)
-
(
range
/
2
)).
addY
(
3
f
).
addZ
((
float
)
(
Math
.
random
()
*
range
)
-
(
range
/
2
));
EntityItem
entity
=
new
EntityItem
(
player
.
getWorld
(),
player
,
itemData
,
pos
,
1
);
player
.
getWorld
().
addEntity
(
entity
);
}
}
else
{
EntityItem
entity
=
new
EntityItem
(
player
.
getWorld
(),
player
,
itemData
,
player
.
getPos
().
clone
().
addY
(
3
f
),
count
);
player
.
getWorld
().
addEntity
(
entity
);
}
}
}
@Command
(
helpText
=
"/spawn [monster id] [count] - Creates {count} amount of {item id}"
)
public
static
class
Spawn
extends
PlayerCommand
{
@Override
public
void
execute
(
GenshinPlayer
player
,
String
raw
)
{
String
[]
split
=
raw
.
split
(
" "
);
int
monsterId
=
0
,
count
=
1
,
level
=
1
;
try
{
monsterId
=
Integer
.
parseInt
(
split
[
0
]);
}
catch
(
Exception
e
)
{
monsterId
=
0
;
}
try
{
level
=
Math
.
max
(
Math
.
min
(
Integer
.
parseInt
(
split
[
1
]),
200
),
1
);
}
catch
(
Exception
e
)
{
level
=
1
;
}
try
{
count
=
Math
.
max
(
Math
.
min
(
Integer
.
parseInt
(
split
[
2
]),
1000
),
1
);
}
catch
(
Exception
e
)
{
count
=
1
;
}
// Give
MonsterData
monsterData
=
GenshinData
.
getMonsterDataMap
().
get
(
monsterId
);
if
(
monsterData
==
null
)
{
player
.
dropMessage
(
"Error: Monster data not found"
);
return
;
}
float
range
=
(
5
f
+
(.
1
f
*
count
));
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
Position
pos
=
player
.
getPos
().
clone
().
addX
((
float
)
(
Math
.
random
()
*
range
)
-
(
range
/
2
)).
addY
(
3
f
).
addZ
((
float
)
(
Math
.
random
()
*
range
)
-
(
range
/
2
));
EntityMonster
entity
=
new
EntityMonster
(
player
.
getWorld
(),
monsterData
,
pos
,
level
);
player
.
getWorld
().
addEntity
(
entity
);
}
}
}
@Command
(
helpText
=
"/killall"
)
public
static
class
KillAll
extends
PlayerCommand
{
@Override
public
void
execute
(
GenshinPlayer
player
,
String
raw
)
{
List
<
GenshinEntity
>
toRemove
=
new
LinkedList
<>();
for
(
GenshinEntity
entity
:
player
.
getWorld
().
getEntities
().
values
())
{
if
(
entity
instanceof
EntityMonster
)
{
toRemove
.
add
(
entity
);
}
}
toRemove
.
forEach
(
e
->
player
.
getWorld
().
killEntity
(
e
,
0
));
}
}
@Command
(
helpText
=
"/resetconst - Resets all constellations for the currently active character"
)
public
static
class
ResetConst
extends
PlayerCommand
{
@Override
public
void
execute
(
GenshinPlayer
player
,
String
raw
)
{
EntityAvatar
entity
=
player
.
getTeamManager
().
getCurrentAvatarEntity
();
if
(
entity
==
null
)
{
return
;
}
GenshinAvatar
avatar
=
entity
.
getAvatar
();
avatar
.
getTalentIdList
().
clear
();
avatar
.
setCoreProudSkillLevel
(
0
);
avatar
.
recalcStats
();
avatar
.
save
();
player
.
dropMessage
(
"Constellations for "
+
entity
.
getAvatar
().
getAvatarData
().
getName
()
+
" have been reset. Please relogin to see changes."
);
}
}
@Command
(
helpText
=
"/godmode - Prevents you from taking damage"
)
public
static
class
Godmode
extends
PlayerCommand
{
@Override
public
void
execute
(
GenshinPlayer
player
,
String
raw
)
{
player
.
setGodmode
(!
player
.
hasGodmode
());
player
.
dropMessage
(
"Godmode is now "
+
(
player
.
hasGodmode
()
?
"ON"
:
"OFF"
));
}
}
@Command
(
helpText
=
"/sethp [hp]"
)
public
static
class
Sethp
extends
PlayerCommand
{
@Override
public
void
execute
(
GenshinPlayer
player
,
String
raw
)
{
String
[]
split
=
raw
.
split
(
" "
);
int
hp
=
0
;
try
{
hp
=
Math
.
max
(
Integer
.
parseInt
(
split
[
0
]),
1
);
}
catch
(
Exception
e
)
{
hp
=
1
;
}
EntityAvatar
entity
=
player
.
getTeamManager
().
getCurrentAvatarEntity
();
if
(
entity
==
null
)
{
return
;
}
entity
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
hp
);
entity
.
getWorld
().
broadcastPacket
(
new
PacketEntityFightPropUpdateNotify
(
entity
,
FightProperty
.
FIGHT_PROP_CUR_HP
));
}
}
@Command
(
aliases
=
{
"clearart"
},
helpText
=
"/clearartifacts"
)
public
static
class
ClearArtifacts
extends
PlayerCommand
{
@Override
public
void
execute
(
GenshinPlayer
player
,
String
raw
)
{
List
<
GenshinItem
>
toRemove
=
new
LinkedList
<>();
for
(
GenshinItem
item
:
player
.
getInventory
().
getItems
().
values
())
{
if
(
item
.
getItemType
()
==
ItemType
.
ITEM_RELIQUARY
&&
item
.
getLevel
()
==
1
&&
item
.
getExp
()
==
0
&&
!
item
.
isLocked
()
&&
!
item
.
isEquipped
())
{
toRemove
.
add
(
item
);
}
}
player
.
getInventory
().
removeItems
(
toRemove
);
}
}
}
src/deprecated/java/emu/grasscutter/commands/ServerCommands.java
0 → 100644
View file @
eac3745f
package
emu.grasscutter.commands
;
import
java.lang.reflect.Modifier
;
import
java.util.Arrays
;
import
java.util.HashMap
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.stream.Collectors
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.def.ItemData
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.inventory.GenshinItem
;
import
emu.grasscutter.utils.Crypto
;
import
emu.grasscutter.utils.Utils
;
public
class
ServerCommands
{
private
static
HashMap
<
String
,
ServerCommand
>
list
=
new
HashMap
<>();
static
{
try
{
// Look for classes
for
(
Class
<?>
cls
:
ServerCommands
.
class
.
getDeclaredClasses
())
{
// Get non abstract classes
if
(!
Modifier
.
isAbstract
(
cls
.
getModifiers
()))
{
String
commandName
=
cls
.
getSimpleName
().
toLowerCase
();
list
.
put
(
commandName
,
(
ServerCommand
)
cls
.
newInstance
());
}
}
}
catch
(
Exception
e
)
{
}
}
public
static
void
handle
(
String
msg
)
{
String
[]
split
=
msg
.
split
(
" "
);
// End if invalid
if
(
split
.
length
==
0
)
{
return
;
}
//
String
first
=
split
[
0
].
toLowerCase
();
ServerCommand
c
=
ServerCommands
.
list
.
get
(
first
);
if
(
c
!=
null
)
{
// Execute
int
len
=
Math
.
min
(
first
.
length
()
+
1
,
msg
.
length
());
c
.
execute
(
msg
.
substring
(
len
));
}
}
public
static
abstract
class
ServerCommand
{
public
abstract
void
execute
(
String
raw
);
}
// ================ Commands ================
public
static
class
Reload
extends
ServerCommand
{
@Override
public
void
execute
(
String
raw
)
{
Grasscutter
.
getLogger
().
info
(
"Reloading config."
);
Grasscutter
.
loadConfig
();
Grasscutter
.
getDispatchServer
().
loadQueries
();
Grasscutter
.
getLogger
().
info
(
"Reload complete."
);
}
}
public
static
class
sendMsg
extends
ServerCommand
{
@Override
public
void
execute
(
String
raw
)
{
List
<
String
>
split
=
Arrays
.
asList
(
raw
.
split
(
" "
));
if
(
split
.
size
()
<
2
)
{
Grasscutter
.
getLogger
().
error
(
"Invalid amount of args"
);
return
;
}
String
playerID
=
split
.
get
(
0
);
String
message
=
split
.
stream
().
skip
(
1
).
collect
(
Collectors
.
joining
(
" "
));
emu
.
grasscutter
.
game
.
Account
account
=
DatabaseHelper
.
getAccountByPlayerId
(
Integer
.
parseInt
(
playerID
));
if
(
account
!=
null
)
{
GenshinPlayer
player
=
Grasscutter
.
getGameServer
().
getPlayerById
(
Integer
.
parseInt
(
playerID
));
if
(
player
!=
null
)
{
player
.
dropMessage
(
message
);
Grasscutter
.
getLogger
().
info
(
String
.
format
(
"Successfully sent message to %s: %s"
,
playerID
,
message
));
}
else
{
Grasscutter
.
getLogger
().
error
(
"Player not online"
);
}
}
else
{
Grasscutter
.
getLogger
().
error
(
String
.
format
(
"Player %s does not exist"
,
playerID
));
}
}
}
public
static
class
Account
extends
ServerCommand
{
@Override
public
void
execute
(
String
raw
)
{
String
[]
split
=
raw
.
split
(
" "
);
if
(
split
.
length
<
2
)
{
Grasscutter
.
getLogger
().
error
(
"Invalid amount of args"
);
return
;
}
String
command
=
split
[
0
].
toLowerCase
();
String
username
=
split
[
1
];
switch
(
command
)
{
case
"create"
:
if
(
split
.
length
<
2
)
{
Grasscutter
.
getLogger
().
error
(
"Invalid amount of args"
);
return
;
}
int
reservedId
=
0
;
try
{
reservedId
=
Integer
.
parseInt
(
split
[
2
]);
}
catch
(
Exception
e
)
{
reservedId
=
0
;
}
emu
.
grasscutter
.
game
.
Account
account
=
DatabaseHelper
.
createAccountWithId
(
username
,
reservedId
);
if
(
account
!=
null
)
{
Grasscutter
.
getLogger
().
info
(
"Account created"
+
(
reservedId
>
0
?
" with an id of "
+
reservedId
:
""
));
}
else
{
Grasscutter
.
getLogger
().
error
(
"Account already exists"
);
}
break
;
case
"delete"
:
boolean
success
=
DatabaseHelper
.
deleteAccount
(
username
);
if
(
success
)
{
Grasscutter
.
getLogger
().
info
(
"Account deleted"
);
}
break
;
/*
case "setpw":
case "setpass":
case "setpassword":
if (split.length < 3) {
Grasscutter.getLogger().error("Invalid amount of args");
return;
}
account = DatabaseHelper.getAccountByName(username);
if (account == null) {
Grasscutter.getLogger().error("No account found!");
return;
}
token = split[2];
token = PasswordHelper.hashPassword(token);
account.setPassword(token);
DatabaseHelper.saveAccount(account);
Grasscutter.getLogger().info("Password set");
break;
*/
}
}
}
}
src/main/java/emu/grasscutter/Config.java
View file @
eac3745f
...
...
@@ -6,12 +6,15 @@ public final class Config {
public
int
DispatchServerPort
=
443
;
public
String
DispatchServerKeystorePath
=
"./keystore.p12"
;
public
String
DispatchServerKeystorePassword
=
""
;
public
Boolean
UseSSL
=
true
;
public
String
GameServerName
=
"Test"
;
public
String
GameServerIp
=
"127.0.0.1"
;
public
String
GameServerPublicIp
=
""
;
public
int
GameServerPort
=
22102
;
public
int
UploadLogPort
=
80
;
public
String
DatabaseUrl
=
"mongodb://localhost:27017"
;
public
String
DatabaseCollection
=
"grasscutter"
;
...
...
src/main/java/emu/grasscutter/Grasscutter.java
View file @
eac3745f
...
...
@@ -7,14 +7,15 @@ import java.io.FileWriter;
import
java.io.InputStreamReader
;
import
java.net.InetSocketAddress
;
import
emu.grasscutter.commands.CommandMap
;
import
emu.grasscutter.utils.Utils
;
import
org.reflections.Reflections
;
import
org.slf4j.LoggerFactory
;
import
com.google.gson.Gson
;
import
com.google.gson.GsonBuilder
;
import
ch.qos.logback.classic.Logger
;
import
emu.grasscutter.commands.ServerCommands
;
import
emu.grasscutter.data.ResourceLoader
;
import
emu.grasscutter.database.DatabaseManager
;
import
emu.grasscutter.server.dispatch.DispatchServer
;
...
...
@@ -23,10 +24,6 @@ import emu.grasscutter.tools.Tools;
import
emu.grasscutter.utils.Crypto
;
public
final
class
Grasscutter
{
static
{
System
.
setProperty
(
"logback.configurationFile"
,
"src/main/resources/logback.xml"
);
}
private
static
final
Logger
log
=
(
Logger
)
LoggerFactory
.
getLogger
(
Grasscutter
.
class
);
private
static
Config
config
;
...
...
@@ -37,8 +34,13 @@ public final class Grasscutter {
private
static
DispatchServer
dispatchServer
;
private
static
GameServer
gameServer
;
public
static
final
Reflections
reflector
=
new
Reflections
();
static
{
// Load configuration.
// Declare logback configuration.
System
.
setProperty
(
"logback.configurationFile"
,
"src/main/resources/logback.xml"
);
// Load server configuration.
Grasscutter
.
loadConfig
();
// Check server structure.
Utils
.
startupCheck
();
...
...
@@ -100,7 +102,11 @@ public final class Grasscutter {
String
input
;
try
(
BufferedReader
br
=
new
BufferedReader
(
new
InputStreamReader
(
System
.
in
)))
{
while
((
input
=
br
.
readLine
())
!=
null
)
{
ServerCommands
.
handle
(
input
);
try
{
CommandMap
.
getInstance
().
invoke
(
null
,
input
);
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"Command error: "
+
e
.
getMessage
());
}
}
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"An error occurred."
,
e
);
...
...
src/main/java/emu/grasscutter/commands/Command.java
View file @
eac3745f
...
...
@@ -5,9 +5,19 @@ import java.lang.annotation.RetentionPolicy;
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
Command
{
String
[]
aliases
()
default
""
;
String
label
()
default
""
;
int
gmLevel
()
default
1
;
String
usage
()
default
""
;
String
helpText
()
default
""
;
String
[]
aliases
()
default
{
""
};
Execution
execution
()
default
Execution
.
ALL
;
String
permission
()
default
""
;
enum
Execution
{
ALL
,
CONSOLE
,
PLAYER
}
}
src/main/java/emu/grasscutter/commands/CommandHandler.java
0 → 100644
View file @
eac3745f
package
emu.grasscutter.commands
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.GenshinPlayer
;
import
java.util.List
;
public
interface
CommandHandler
{
/* Invoked on player execution. */
default
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
}
/* Invoked on server execution. */
default
void
execute
(
List
<
String
>
args
)
{
}
/*
* Utilities.
*/
/**
* Send a message to the target.
* @param player The player to send the message to, or null for the server console.
* @param message The message to send.
*/
static
void
sendMessage
(
GenshinPlayer
player
,
String
message
)
{
if
(
player
==
null
)
{
Grasscutter
.
getLogger
().
info
(
message
);
}
else
player
.
dropMessage
(
message
);
}
}
src/main/java/emu/grasscutter/commands/CommandMap.java
0 → 100644
View file @
eac3745f
package
emu.grasscutter.commands
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.Account
;
import
emu.grasscutter.game.GenshinPlayer
;
import
org.reflections.Reflections
;
import
java.util.*
;
@SuppressWarnings
(
"UnusedReturnValue"
)
public
final
class
CommandMap
{
public
static
CommandMap
getInstance
()
{
return
Grasscutter
.
getGameServer
().
getCommandMap
();
}
private
final
Map
<
String
,
CommandHandler
>
commands
=
new
HashMap
<>();
private
final
Map
<
String
,
Command
>
annotations
=
new
HashMap
<>();
/**
* Register a command handler.
* @param label The command label.
* @param command The command handler.
* @return Instance chaining.
*/
public
CommandMap
registerCommand
(
String
label
,
CommandHandler
command
)
{
Grasscutter
.
getLogger
().
debug
(
"Registered command: "
+
label
);
// Get command data.
Command
annotation
=
command
.
getClass
().
getAnnotation
(
Command
.
class
);
this
.
annotations
.
put
(
label
,
annotation
);
this
.
commands
.
put
(
label
,
command
);
// Register aliases.
if
(
annotation
.
aliases
().
length
>
0
)
{
for
(
String
alias
:
annotation
.
aliases
())
{
this
.
commands
.
put
(
alias
,
command
);
this
.
annotations
.
put
(
alias
,
annotation
);
}
}
return
this
;
}
/**
* Removes a registered command handler.
* @param label The command label.
* @return Instance chaining.
*/
public
CommandMap
unregisterCommand
(
String
label
)
{
Grasscutter
.
getLogger
().
debug
(
"Unregistered command: "
+
label
);
CommandHandler
handler
=
this
.
commands
.
get
(
label
);
if
(
handler
==
null
)
return
this
;
Command
annotation
=
handler
.
getClass
().
getAnnotation
(
Command
.
class
);
this
.
annotations
.
remove
(
label
);
this
.
commands
.
remove
(
label
);
// Unregister aliases.
if
(
annotation
.
aliases
().
length
>
0
)
{
for
(
String
alias
:
annotation
.
aliases
())
{
this
.
commands
.
remove
(
alias
);
this
.
annotations
.
remove
(
alias
);
}
}
return
this
;
}
/**
* Returns a list of all registered commands.
* @return All command handlers as a list.
*/
public
List
<
CommandHandler
>
getHandlers
()
{
return
new
LinkedList
<>(
this
.
commands
.
values
());
}
/**
* Returns a handler by label/alias.
* @param label The command label.
* @return The command handler.
*/
public
CommandHandler
getHandler
(
String
label
)
{
return
this
.
commands
.
get
(
label
);
}
/**
* Invoke a command handler with the given arguments.
* @param player The player invoking the command or null for the server console.
* @param rawMessage The messaged used to invoke the command.
*/
public
void
invoke
(
GenshinPlayer
player
,
String
rawMessage
)
{
rawMessage
=
rawMessage
.
trim
();
if
(
rawMessage
.
length
()
==
0
)
{
CommandHandler
.
sendMessage
(
player
,
"No command specified."
);
}
// Remove prefix if present.
if
(!
Character
.
isLetter
(
rawMessage
.
charAt
(
0
)))
rawMessage
=
rawMessage
.
substring
(
1
);
// Parse message.
String
[]
split
=
rawMessage
.
split
(
" "
);
List
<
String
>
args
=
new
LinkedList
<>(
Arrays
.
asList
(
split
));
String
label
=
args
.
remove
(
0
);
// Get command handler.
CommandHandler
handler
=
this
.
commands
.
get
(
label
);
if
(
handler
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Unknown command: "
+
label
);
return
;
}
// Check for permission.
if
(
player
!=
null
)
{
String
permissionNode
=
this
.
annotations
.
get
(
label
).
permission
();
Account
account
=
player
.
getAccount
();
List
<
String
>
permissions
=
account
.
getPermissions
();
if
(!
permissions
.
contains
(
"*"
)
&&
!
permissions
.
contains
(
permissionNode
))
{
CommandHandler
.
sendMessage
(
player
,
"You do not have permission to run this command."
);
return
;
}
}
// Execution power check.
Command
.
Execution
executionPower
=
this
.
annotations
.
get
(
label
).
execution
();
if
(
player
==
null
&&
executionPower
==
Command
.
Execution
.
PLAYER
)
{
CommandHandler
.
sendMessage
(
null
,
"Run this command in-game."
);
return
;
}
else
if
(
player
!=
null
&&
executionPower
==
Command
.
Execution
.
CONSOLE
)
{
CommandHandler
.
sendMessage
(
player
,
"This command can only be run from the console."
);
return
;
}
// Invoke execute method for handler.
if
(
player
==
null
)
handler
.
execute
(
args
);
else
handler
.
execute
(
player
,
args
);
}
public
CommandMap
()
{
this
(
false
);
}
public
CommandMap
(
boolean
scan
)
{
if
(
scan
)
this
.
scan
();
}
/**
* Scans for all classes annotated with {@link Command} and registers them.
*/
private
void
scan
()
{
Reflections
reflector
=
Grasscutter
.
reflector
;
Set
<
Class
<?>>
classes
=
reflector
.
getTypesAnnotatedWith
(
Command
.
class
);
classes
.
forEach
(
annotated
->
{
try
{
Command
cmdData
=
annotated
.
getAnnotation
(
Command
.
class
);
Object
object
=
annotated
.
newInstance
();
if
(
object
instanceof
CommandHandler
)
this
.
registerCommand
(
cmdData
.
label
(),
(
CommandHandler
)
object
);
else
Grasscutter
.
getLogger
().
error
(
"Class "
+
annotated
.
getName
()
+
" is not a CommandHandler!"
);
}
catch
(
Exception
exception
)
{
Grasscutter
.
getLogger
().
error
(
"Failed to register command handler for "
+
annotated
.
getSimpleName
(),
exception
);
}
});
}
}
src/main/java/emu/grasscutter/commands/PlayerCommands.java
View file @
eac3745f
This diff is collapsed.
Click to expand it.
src/main/java/emu/grasscutter/commands/ServerCommands.java
View file @
eac3745f
package
emu.grasscutter.commands
;
import
java.lang.reflect.Modifier
;
import
java.util.Arrays
;
import
java.util.HashMap
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.stream.Collectors
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.def.ItemData
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.Account
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.inventory.GenshinItem
;
import
emu.grasscutter.utils.Crypto
;
import
emu.grasscutter.utils.Utils
;
public
class
ServerCommands
{
private
static
HashMap
<
String
,
ServerCommand
>
list
=
new
HashMap
<>()
;
import
java.util.List
;
import
java.util.stream.Collectors
;
static
{
try
{
// Look for classes
for
(
Class
<?>
cls
:
ServerCommands
.
class
.
getDeclaredClasses
())
{
// Get non abstract classes
if
(!
Modifier
.
isAbstract
(
cls
.
getModifiers
()))
{
String
commandName
=
cls
.
getSimpleName
().
toLowerCase
();
list
.
put
(
commandName
,
(
ServerCommand
)
cls
.
newInstance
());
}
/**
* A container for server-related commands.
*/
public
final
class
ServerCommands
{
@Command
(
label
=
"reload"
,
usage
=
"Usage: reload"
)
public
static
class
ReloadCommand
implements
CommandHandler
{
@Override
public
void
execute
(
List
<
String
>
args
)
{
Grasscutter
.
getLogger
().
info
(
"Reloading config."
);
Grasscutter
.
loadConfig
();
Grasscutter
.
getDispatchServer
().
loadQueries
();
Grasscutter
.
getLogger
().
info
(
"Reload complete."
);
}
}
catch
(
Exception
e
)
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
this
.
execute
(
args
);
}
}
public
static
void
handle
(
String
msg
)
{
String
[]
split
=
msg
.
split
(
" "
);
@Command
(
label
=
"sendmessage"
,
aliases
=
{
"sendmsg"
,
"msg"
},
usage
=
"Usage: sendmessage <player> <message>"
)
public
static
class
SendMessageCommand
implements
CommandHandler
{
// End if invalid
if
(
split
.
length
==
0
)
{
return
;
@Override
public
void
execute
(
List
<
String
>
args
)
{
if
(
args
.
size
()
<
2
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: sendmessage <player> <message>"
);
return
;
}
//
String
first
=
split
[
0
].
toLowerCase
();
ServerCommand
c
=
ServerCommands
.
list
.
get
(
first
);
try
{
int
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
String
message
=
String
.
join
(
" "
,
args
.
subList
(
1
,
args
.
size
()));
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerById
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Player not found."
);
return
;
}
if
(
c
!=
null
)
{
// Execute
int
len
=
Math
.
min
(
first
.
length
()
+
1
,
msg
.
length
());
c
.
execute
(
msg
.
substring
(
len
)
);
targetPlayer
.
dropMessage
(
message
);
CommandHandler
.
sendMessage
(
null
,
"Message sent."
);
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid player ID."
);
}
}
public
static
abstract
class
ServerCommand
{
public
abstract
void
execute
(
String
raw
);
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
if
(
args
.
size
()
<
2
)
{
CommandHandler
.
sendMessage
(
player
,
"Usage: sendmessage <player> <message>"
);
return
;
}
// ================ Commands ================
try
{
int
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
String
message
=
String
.
join
(
" "
,
args
.
subList
(
1
,
args
.
size
()));
public
static
class
Reload
extends
ServerCommand
{
@Override
public
void
execute
(
String
raw
)
{
Grasscutter
.
getLogger
().
info
(
"Reloading config."
);
Grasscutter
.
loadConfig
();
Grasscutter
.
getDispatchServer
().
loadQueries
();
Grasscutter
.
getLogger
().
info
(
"Reload complete."
);
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerById
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Player not found."
);
return
;
}
targetPlayer
.
sendMessage
(
player
,
message
);
CommandHandler
.
sendMessage
(
player
,
"Message sent."
);
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid player ID."
);
}
}
}
public
static
class
sendMsg
extends
ServerCommand
{
@Override
public
void
execute
(
String
raw
)
{
List
<
String
>
split
=
Arrays
.
asList
(
raw
.
split
(
" "
));
@Command
(
label
=
"account"
,
usage
=
"Usage: account <create|delete> <username> [uid]"
,
execution
=
Command
.
Execution
.
CONSOLE
)
public
static
class
AccountCommand
implements
CommandHandler
{
if
(
split
.
size
()
<
2
)
{
Grasscutter
.
getLogger
().
error
(
"Invalid amount of args"
);
return
;
@Override
public
void
execute
(
List
<
String
>
args
)
{
if
(
args
.
size
()
<
2
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: account <create|delete> <username> [uid]"
);
return
;
}
String
playerID
=
split
.
get
(
0
);
String
message
=
split
.
stream
().
skip
(
1
).
collect
(
Collectors
.
joining
(
" "
)
);
String
action
=
args
.
get
(
0
);
String
username
=
args
.
get
(
1
);
switch
(
action
)
{
default
:
CommandHandler
.
sendMessage
(
null
,
"Usage: account <create|delete> <username> [uid]"
);
return
;
case
"create"
:
int
uid
=
0
;
if
(
args
.
size
()
>
2
)
{
try
{
uid
=
Integer
.
parseInt
(
args
.
get
(
2
));
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid UID."
);
return
;
}
}
emu
.
grasscutter
.
game
.
Account
account
=
DatabaseHelper
.
getAccountByPlayerId
(
Integer
.
parseInt
(
playerID
));
if
(
account
!=
null
)
{
GenshinPlayer
player
=
Grasscutter
.
getGameServer
().
getPlayerById
(
Integer
.
parseInt
(
playerID
));
if
(
player
!=
null
)
{
player
.
dropMessage
(
message
);
Grasscutter
.
getLogger
().
info
(
String
.
format
(
"Successfully sent message to %s: %s"
,
playerID
,
message
));
Account
account
=
DatabaseHelper
.
createAccountWithId
(
username
,
uid
);
if
(
account
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Account already exists."
);
return
;
}
else
{
Grasscutter
.
getLogger
().
error
(
"Player not online"
);
CommandHandler
.
sendMessage
(
null
,
"Account created with UID "
+
account
.
getPlayerId
()
+
"."
);
account
.
addPermission
(
"*"
);
// Grant the player superuser permissions.
}
}
else
{
Grasscutter
.
getLogger
().
error
(
String
.
format
(
"Player %s does not exist"
,
playerID
));
return
;
case
"delete"
:
if
(
DatabaseHelper
.
deleteAccount
(
username
))
{
CommandHandler
.
sendMessage
(
null
,
"Account deleted."
);
return
;
}
else
CommandHandler
.
sendMessage
(
null
,
"Account not found."
);
return
;
}
}
}
public
static
class
Account
extends
ServerCommand
{
@Override
public
void
execute
(
String
raw
)
{
String
[]
split
=
raw
.
split
(
" "
);
@Command
(
label
=
"permission"
,
usage
=
"Usage: permission <add|remove> <username> <permission>"
,
execution
=
Command
.
Execution
.
CONSOLE
)
public
static
class
PermissionCommand
implements
CommandHandler
{
if
(
split
.
length
<
2
)
{
Grasscutter
.
getLogger
().
error
(
"Invalid amount of args"
);
return
;
@Override
public
void
execute
(
List
<
String
>
args
)
{
if
(
args
.
size
()
<
3
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: permission <add|remove> <username> <permission>"
);
return
;
}
String
command
=
split
[
0
].
toLowerCase
();
String
username
=
split
[
1
];
switch
(
command
)
{
case
"create"
:
if
(
split
.
length
<
2
)
{
Grasscutter
.
getLogger
().
error
(
"Invalid amount of args"
);
return
;
}
String
action
=
args
.
get
(
0
);
String
username
=
args
.
get
(
1
);
String
permission
=
args
.
get
(
2
);
int
reservedId
=
0
;
try
{
reservedId
=
Integer
.
parseInt
(
split
[
2
]);
}
catch
(
Exception
e
)
{
reservedId
=
0
;
Account
account
=
Grasscutter
.
getGameServer
().
getAccountByName
(
username
);
if
(
account
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Account not found."
);
return
;
}
emu
.
grasscutter
.
game
.
Account
account
=
DatabaseHelper
.
createAccountWithId
(
username
,
reservedId
);
if
(
account
!=
null
)
{
Grasscutter
.
getLogger
().
info
(
"Account created"
+
(
reservedId
>
0
?
" with an id of "
+
reservedId
:
""
));
}
else
{
Grasscutter
.
getLogger
().
error
(
"Account already exists"
);
}
switch
(
action
)
{
default
:
CommandHandler
.
sendMessage
(
null
,
"Usage: permission <add|remove> <username> <permission>"
);
break
;
case
"delete"
:
boolean
success
=
DatabaseHelper
.
deleteAccount
(
username
);
case
"add"
:
if
(
account
.
addPermission
(
permission
))
{
CommandHandler
.
sendMessage
(
null
,
"Permission added."
);
}
else
CommandHandler
.
sendMessage
(
null
,
"They already have this permission!"
);
break
;
case
"remove"
:
if
(
account
.
removePermission
(
permission
))
{
CommandHandler
.
sendMessage
(
null
,
"Permission removed."
);
}
else
CommandHandler
.
sendMessage
(
null
,
"They don't have this permission!"
);
break
;
}
if
(
success
)
{
Grasscutter
.
getLogger
().
info
(
"Account deleted"
);
account
.
save
();
}
break
;
/*
case "setpw":
case "setpass":
case "setpassword":
if (split.length < 3) {
Grasscutter.getLogger().error("Invalid amount of args");
return;
}
account = DatabaseHelper.getAccountByName(username);
@Command
(
label
=
"help"
,
usage
=
"Usage: help [command]"
)
public
static
class
HelpCommand
implements
CommandHandler
{
if (account == null) {
Grasscutter.getLogger().error("No account found!");
return;
@Override
public
void
execute
(
List
<
String
>
args
)
{
List
<
CommandHandler
>
handlers
=
CommandMap
.
getInstance
().
getHandlers
();
List
<
Command
>
annotations
=
handlers
.
stream
()
.
map
(
handler
->
handler
.
getClass
().
getAnnotation
(
Command
.
class
))
.
collect
(
Collectors
.
toList
());
if
(
args
.
size
()
<
1
)
{
StringBuilder
builder
=
new
StringBuilder
(
"Available commands:\n"
);
annotations
.
forEach
(
annotation
->
builder
.
append
(
annotation
.
usage
()).
append
(
"\n"
));
CommandHandler
.
sendMessage
(
null
,
builder
.
toString
());
}
else
{
String
command
=
args
.
get
(
0
);
CommandHandler
handler
=
CommandMap
.
getInstance
().
getHandler
(
command
);
if
(
handler
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Command not found."
);
return
;
}
token = split[2];
token = PasswordHelper.hashPassword(token);
Command
annotation
=
handler
.
getClass
().
getAnnotation
(
Command
.
class
);
CommandHandler
.
sendMessage
(
null
,
annotation
.
usage
());
}
}
account.setPassword(token);
DatabaseHelper.saveAccount(account);
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
List
<
CommandHandler
>
handlers
=
CommandMap
.
getInstance
().
getHandlers
();
List
<
Command
>
annotations
=
handlers
.
stream
()
.
map
(
handler
->
handler
.
getClass
().
getAnnotation
(
Command
.
class
))
.
collect
(
Collectors
.
toList
());
if
(
args
.
size
()
<
1
)
{
annotations
.
forEach
(
annotation
->
player
.
dropMessage
(
annotation
.
usage
()));
}
else
{
String
command
=
args
.
get
(
0
);
CommandHandler
handler
=
CommandMap
.
getInstance
().
getHandler
(
command
);
if
(
handler
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Command not found."
);
return
;
}
Grasscutter.getLogger().info("Password set");
break;
*/
Command
annotation
=
handler
.
getClass
().
getAnnotation
(
Command
.
class
);
CommandHandler
.
sendMessage
(
player
,
annotation
.
usage
());
}
}
}
...
...
src/main/java/emu/grasscutter/data/ResourceLoader.java
View file @
eac3745f
...
...
@@ -2,20 +2,12 @@ package emu.grasscutter.data;
import
java.io.File
;
import
java.io.FileReader
;
import
java.nio.file.Files
;
import
java.nio.file.Paths
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.TreeMap
;
import
java.util.*
;
import
java.util.Map.Entry
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
java.util.stream.Stream
;
import
emu.grasscutter.utils.Utils
;
import
org.reflections.Reflections
;
import
com.google.gson.reflect.TypeToken
;
...
...
@@ -39,19 +31,12 @@ public class ResourceLoader {
}
});
classList
.
sort
((
a
,
b
)
->
{
return
b
.
getAnnotation
(
ResourceType
.
class
).
loadPriority
().
value
()
-
a
.
getAnnotation
(
ResourceType
.
class
).
loadPriority
().
value
();
});
classList
.
sort
((
a
,
b
)
->
b
.
getAnnotation
(
ResourceType
.
class
).
loadPriority
().
value
()
-
a
.
getAnnotation
(
ResourceType
.
class
).
loadPriority
().
value
());
return
classList
;
}
public
static
void
loadAll
()
{
// Create resource folder if it doesnt exist
File
resFolder
=
new
File
(
Grasscutter
.
getConfig
().
RESOURCE_FOLDER
);
if
(!
resFolder
.
exists
())
{
resFolder
.
mkdir
();
}
// Load ability lists
loadAbilityEmbryos
();
loadOpenConfig
();
...
...
@@ -110,7 +95,7 @@ public class ResourceLoader {
try
{
loadFromResource
(
resourceDefinition
,
type
,
map
);
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading resource file: "
+
type
.
name
(),
e
);
Grasscutter
.
getLogger
().
error
(
"Error loading resource file: "
+
Arrays
.
toString
(
type
.
name
()
)
,
e
);
}
}
}
...
...
@@ -153,10 +138,16 @@ public class ResourceLoader {
Pattern
pattern
=
Pattern
.
compile
(
"(?<=ConfigAvatar_)(.*?)(?=.json)"
);
embryoList
=
new
LinkedList
<>();
File
folder
=
new
File
(
Grasscutter
.
getConfig
().
RESOURCE_FOLDER
+
"BinOutput\\Avatar\\"
);
for
(
File
file
:
folder
.
listFiles
())
{
AvatarConfig
config
=
null
;
String
avatarName
=
null
;
File
folder
=
new
File
(
Utils
.
toFilePath
(
Grasscutter
.
getConfig
().
RESOURCE_FOLDER
+
"BinOutput/Avatar/"
));
File
[]
files
=
folder
.
listFiles
();
if
(
files
==
null
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading ability embryos: no files found in "
+
folder
.
getAbsolutePath
());
return
;
}
for
(
File
file
:
files
)
{
AvatarConfig
config
;
String
avatarName
;
Matcher
matcher
=
pattern
.
matcher
(
file
.
getName
());
if
(
matcher
.
find
())
{
...
...
@@ -209,14 +200,18 @@ public class ResourceLoader {
String
[]
folderNames
=
{
"BinOutput\\Talent\\EquipTalents\\"
,
"BinOutput\\Talent\\AvatarTalents\\"
};
for
(
String
name
:
folderNames
)
{
File
folder
=
new
File
(
Grasscutter
.
getConfig
().
RESOURCE_FOLDER
+
name
);
File
folder
=
new
File
(
Utils
.
toFilePath
(
Grasscutter
.
getConfig
().
RESOURCE_FOLDER
+
name
));
File
[]
files
=
folder
.
listFiles
();
if
(
files
==
null
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading open config: no files found in "
+
folder
.
getAbsolutePath
());
return
;
}
for
(
File
file
:
f
older
.
listF
iles
()
)
{
for
(
File
file
:
files
)
{
if
(!
file
.
getName
().
endsWith
(
".json"
))
{
continue
;
}
Map
<
String
,
OpenConfigData
[]>
config
=
null
;
Map
<
String
,
OpenConfigData
[]>
config
;
try
(
FileReader
fileReader
=
new
FileReader
(
file
))
{
config
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
type
);
...
...
src/main/java/emu/grasscutter/database/DatabaseHelper.java
View file @
eac3745f
...
...
@@ -36,6 +36,7 @@ public class DatabaseHelper {
if
(
reservedId
==
GenshinConstants
.
SERVER_CONSOLE_UID
)
{
return
null
;
}
exists
=
DatabaseHelper
.
getAccountByPlayerId
(
reservedId
);
if
(
exists
!=
null
)
{
return
null
;
...
...
src/main/java/emu/grasscutter/game/Account.java
View file @
eac3745f
...
...
@@ -4,11 +4,17 @@ import dev.morphia.annotations.Collation;
import
dev.morphia.annotations.Entity
;
import
dev.morphia.annotations.Id
;
import
dev.morphia.annotations.Indexed
;
import
dev.morphia.annotations.PreLoad
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.utils.Crypto
;
import
emu.grasscutter.utils.Utils
;
import
dev.morphia.annotations.IndexOptions
;
import
java.util.ArrayList
;
import
java.util.List
;
import
com.mongodb.DBObject
;
@Entity
(
value
=
"accounts"
,
noClassnameStored
=
true
)
public
class
Account
{
@Id
private
String
id
;
...
...
@@ -23,9 +29,12 @@ public class Account {
private
String
token
;
private
String
sessionKey
;
// Session token for dispatch server
private
List
<
String
>
permissions
;
@Deprecated
public
Account
()
{}
public
Account
()
{
this
.
permissions
=
new
ArrayList
<>();
}
public
String
getId
()
{
return
id
;
...
...
@@ -85,6 +94,22 @@ public class Account {
return
this
.
sessionKey
;
}
/**
* The collection of a player's permissions.
*/
public
List
<
String
>
getPermissions
()
{
return
this
.
permissions
;
}
public
boolean
addPermission
(
String
permission
)
{
if
(
this
.
permissions
.
contains
(
permission
))
return
false
;
this
.
permissions
.
add
(
permission
);
return
true
;
}
public
boolean
removePermission
(
String
permission
)
{
return
this
.
permissions
.
remove
(
permission
);
}
// TODO make unique
public
String
generateLoginToken
()
{
this
.
token
=
Utils
.
bytesToHex
(
Crypto
.
createSessionKey
(
32
));
...
...
@@ -92,6 +117,14 @@ public class Account {
return
this
.
token
;
}
@PreLoad
public
void
onLoad
(
DBObject
dbObj
)
{
// Grant the superuser permissions to accounts created before the permissions update
if
(!
dbObj
.
containsField
(
"permissions"
))
{
this
.
addPermission
(
"*"
);
}
}
public
void
save
()
{
DatabaseHelper
.
saveAccount
(
this
);
}
...
...
src/main/java/emu/grasscutter/game/GenshinPlayer.java
View file @
eac3745f
package
emu.grasscutter.game
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.*
;
import
dev.morphia.annotations.*
;
import
emu.grasscutter.GenshinConstants
;
...
...
@@ -485,7 +480,7 @@ public class GenshinPlayer {
this
.
regionId
=
regionId
;
}
public
boolean
has
Godmode
()
{
public
boolean
in
Godmode
()
{
return
godmode
;
}
...
...
@@ -559,6 +554,15 @@ public class GenshinPlayer {
this
.
sendPacket
(
new
PacketPrivateChatNotify
(
GenshinConstants
.
SERVER_CONSOLE_UID
,
getId
(),
message
.
toString
()));
}
/**
* Sends a message to another player.
* @param sender The sender of the message.
* @param message The message to send.
*/
public
void
sendMessage
(
GenshinPlayer
sender
,
Object
message
)
{
this
.
sendPacket
(
new
PacketPrivateChatNotify
(
sender
.
getId
(),
this
.
getId
(),
message
.
toString
()));
}
public
void
interactWith
(
int
gadgetEntityId
)
{
GenshinEntity
entity
=
getWorld
().
getEntityById
(
gadgetEntityId
);
...
...
src/main/java/emu/grasscutter/game/World.java
View file @
eac3745f
...
...
@@ -344,7 +344,7 @@ public class World implements Iterable<GenshinPlayer> {
// Godmode check
if
(
target
instanceof
EntityAvatar
)
{
if
(((
EntityAvatar
)
target
).
getPlayer
().
has
Godmode
())
{
if
(((
EntityAvatar
)
target
).
getPlayer
().
in
Godmode
())
{
return
;
}
}
...
...
src/main/java/emu/grasscutter/game/managers/ChatManager.java
View file @
eac3745f
package
emu.grasscutter.game.managers
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.commands.PlayerCommands
;
import
emu.grasscutter.commands.CommandMap
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.net.packet.GenshinPacket
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.packet.send.PacketPlayerChatNotify
;
import
emu.grasscutter.server.packet.send.PacketPrivateChatNotify
;
import
java.util.Arrays
;
import
java.util.List
;
public
class
ChatManager
{
static
final
List
<
Character
>
PREFIXES
=
Arrays
.
asList
(
'/'
,
'!'
);
private
final
GameServer
server
;
public
ChatManager
(
GameServer
server
)
{
...
...
@@ -19,15 +23,15 @@ public class ChatManager {
return
server
;
}
public
void
sendPriv
Ch
at
(
GenshinPlayer
player
,
int
targetUid
,
String
message
)
{
public
void
sendPrivat
eMessage
(
GenshinPlayer
player
,
int
targetUid
,
String
message
)
{
// Sanity checks
if
(
message
==
null
||
message
.
length
()
==
0
)
{
return
;
}
// Check if command
if
(
message
.
charAt
(
0
)
==
'!'
||
message
.
charAt
(
0
)
==
'/'
)
{
Player
Command
s
.
handl
e
(
player
,
message
);
if
(
PREFIXES
.
contains
(
message
.
charAt
(
0
)
)
)
{
Command
Map
.
getInstance
().
invok
e
(
player
,
message
);
return
;
}
...
...
@@ -45,7 +49,7 @@ public class ChatManager {
target
.
sendPacket
(
packet
);
}
public
void
sendPriv
Ch
at
(
GenshinPlayer
player
,
int
targetUid
,
int
emote
)
{
public
void
sendPrivat
eMessage
(
GenshinPlayer
player
,
int
targetUid
,
int
emote
)
{
// Get target
GenshinPlayer
target
=
getServer
().
getPlayerById
(
targetUid
);
...
...
@@ -60,15 +64,15 @@ public class ChatManager {
target
.
sendPacket
(
packet
);
}
public
void
sendTeam
Chat
(
GenshinPlayer
player
,
int
channel
,
String
message
)
{
public
void
sendTeam
Message
(
GenshinPlayer
player
,
int
channel
,
String
message
)
{
// Sanity checks
if
(
message
==
null
||
message
.
length
()
==
0
)
{
return
;
}
// Check if command
if
(
message
.
charAt
(
0
)
==
'!'
)
{
Player
Command
s
.
handl
e
(
player
,
message
);
if
(
PREFIXES
.
contains
(
message
.
charAt
(
0
)
)
)
{
Command
Map
.
getInstance
().
invok
e
(
player
,
message
);
return
;
}
...
...
@@ -76,7 +80,7 @@ public class ChatManager {
player
.
getWorld
().
broadcastPacket
(
new
PacketPlayerChatNotify
(
player
,
channel
,
message
));
}
public
void
sendTeam
Chat
(
GenshinPlayer
player
,
int
channel
,
int
icon
)
{
public
void
sendTeam
Message
(
GenshinPlayer
player
,
int
channel
,
int
icon
)
{
// Create and send chat packet
player
.
getWorld
().
broadcastPacket
(
new
PacketPlayerChatNotify
(
player
,
channel
,
icon
));
}
...
...
src/main/java/emu/grasscutter/server/dispatch/DispatchServer.java
View file @
eac3745f
...
...
@@ -139,9 +139,11 @@ public final class DispatchServer {
}
public
void
start
()
throws
Exception
{
HttpsServer
server
=
HttpsServer
.
create
(
getAddress
(),
0
);
HttpServer
server
;
if
(
Grasscutter
.
getConfig
().
UseSSL
)
{
HttpsServer
httpsServer
;
httpsServer
=
HttpsServer
.
create
(
getAddress
(),
0
);
SSLContext
sslContext
=
SSLContext
.
getInstance
(
"TLS"
);
try
(
FileInputStream
fis
=
new
FileInputStream
(
Grasscutter
.
getConfig
().
DispatchServerKeystorePath
))
{
char
[]
keystorePassword
=
Grasscutter
.
getConfig
().
DispatchServerKeystorePassword
.
toCharArray
();
KeyStore
ks
=
KeyStore
.
getInstance
(
"PKCS12"
);
...
...
@@ -151,11 +153,15 @@ public final class DispatchServer {
sslContext
.
init
(
kmf
.
getKeyManagers
(),
null
,
null
);
server
.
setHttpsConfigurator
(
new
HttpsConfigurator
(
sslContext
));
httpsServer
.
setHttpsConfigurator
(
new
HttpsConfigurator
(
sslContext
));
server
=
httpsServer
;
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"No SSL cert found!"
);
return
;
}
}
else
{
server
=
HttpServer
.
create
(
getAddress
(),
0
);
}
server
.
createContext
(
"/"
,
t
->
{
//Create a response form the request query parameters
...
...
@@ -396,7 +402,7 @@ public final class DispatchServer {
overseaLogServer
.
start
();
Grasscutter
.
getLogger
().
info
(
"Log server (overseauspider) started on port "
+
8888
);
HttpServer
uploadLogServer
=
HttpServer
.
create
(
new
InetSocketAddress
(
Grasscutter
.
getConfig
().
DispatchServerIp
,
80
),
0
);
HttpServer
uploadLogServer
=
HttpServer
.
create
(
new
InetSocketAddress
(
Grasscutter
.
getConfig
().
DispatchServerIp
,
Grasscutter
.
getConfig
().
UploadLogPort
),
0
);
uploadLogServer
.
createContext
(
// log-upload-os.mihoyo.com
"/crash/dataUpload"
,
new
DispatchHttpJsonHandler
(
"{\"code\":0}"
)
...
...
@@ -413,7 +419,7 @@ public final class DispatchServer {
os
.
close
();
});
uploadLogServer
.
start
();
Grasscutter
.
getLogger
().
info
(
"Log server (log-upload-os) started on port "
+
80
);
Grasscutter
.
getLogger
().
info
(
"Log server (log-upload-os) started on port "
+
Grasscutter
.
getConfig
().
UploadLogPort
);
}
private
Map
<
String
,
String
>
parseQueryString
(
String
qs
)
{
...
...
src/main/java/emu/grasscutter/server/game/GameServer.java
View file @
eac3745f
package
emu.grasscutter.server.game
;
import
java.net.InetSocketAddress
;
import
java.util.ArrayList
;
import
java.util.Date
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Timer
;
import
java.util.TimerTask
;
import
java.util.*
;
import
java.util.concurrent.ConcurrentHashMap
;
import
emu.grasscutter.GenshinConstants
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.commands.CommandMap
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.Account
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.dungeons.DungeonManager
;
import
emu.grasscutter.game.gacha.GachaManager
;
...
...
@@ -23,10 +20,9 @@ import emu.grasscutter.net.packet.PacketHandler;
import
emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail
;
import
emu.grasscutter.netty.MihoyoKcpServer
;
public
class
GameServer
extends
MihoyoKcpServer
{
public
final
class
GameServer
extends
MihoyoKcpServer
{
private
final
InetSocketAddress
address
;
private
final
GameServerPacketHandler
packetHandler
;
private
final
Timer
gameLoop
;
private
final
Map
<
Integer
,
GenshinPlayer
>
players
;
...
...
@@ -36,9 +32,11 @@ public class GameServer extends MihoyoKcpServer {
private
final
ShopManager
shopManager
;
private
final
MultiplayerManager
multiplayerManager
;
private
final
DungeonManager
dungeonManager
;
private
final
CommandMap
commandMap
;
public
GameServer
(
InetSocketAddress
address
)
{
super
(
address
);
this
.
setServerInitializer
(
new
GameServerInitializer
(
this
));
this
.
address
=
address
;
this
.
packetHandler
=
new
GameServerPacketHandler
(
PacketHandler
.
class
);
...
...
@@ -50,22 +48,22 @@ public class GameServer extends MihoyoKcpServer {
this
.
shopManager
=
new
ShopManager
(
this
);
this
.
multiplayerManager
=
new
MultiplayerManager
(
this
);
this
.
dungeonManager
=
new
DungeonManager
(
this
);
this
.
commandMap
=
new
CommandMap
(
true
);
//
Ticker
this
.
gameLoop
=
new
Timer
();
this
.
gameLoop
.
scheduleAtFixedRate
(
new
TimerTask
()
{
//
Schedule game loop.
Timer
gameLoop
=
new
Timer
();
gameLoop
.
scheduleAtFixedRate
(
new
TimerTask
()
{
@Override
public
void
run
()
{
try
{
onTick
();
}
catch
(
Exception
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
();
Grasscutter
.
getLogger
().
error
(
"An error occurred during game update."
,
e
);
}
}
},
new
Date
(),
1000L
);
//
S
hutdown
hook
//
Hook into s
hutdown
event.
Runtime
.
getRuntime
().
addShutdownHook
(
new
Thread
(
this
::
onServerShutdown
));
}
...
...
@@ -101,6 +99,10 @@ public class GameServer extends MihoyoKcpServer {
return
dungeonManager
;
}
public
CommandMap
getCommandMap
()
{
return
this
.
commandMap
;
}
public
void
registerPlayer
(
GenshinPlayer
player
)
{
getPlayers
().
put
(
player
.
getId
(),
player
);
}
...
...
@@ -137,6 +139,14 @@ public class GameServer extends MihoyoKcpServer {
return
player
.
getSocialDetail
();
}
public
Account
getAccountByName
(
String
username
)
{
Optional
<
GenshinPlayer
>
playerOpt
=
getPlayers
().
values
().
stream
().
filter
(
player
->
player
.
getAccount
().
getUsername
().
equals
(
username
)).
findFirst
();
if
(
playerOpt
.
get
()
!=
null
)
{
return
playerOpt
.
get
().
getAccount
();
}
return
DatabaseHelper
.
getAccountByName
(
username
);
}
public
void
onTick
()
throws
Exception
{
for
(
GenshinPlayer
player
:
this
.
getPlayers
().
values
())
{
player
.
onTick
();
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerChatReq.java
View file @
eac3745f
...
...
@@ -17,9 +17,9 @@ public class HandlerPlayerChatReq extends PacketHandler {
ChatInfo
.
ContentCase
content
=
req
.
getChatInfo
().
getContentCase
();
if
(
content
==
ChatInfo
.
ContentCase
.
TEXT
)
{
session
.
getServer
().
getChatManager
().
sendTeam
Chat
(
session
.
getPlayer
(),
req
.
getChannelId
(),
req
.
getChatInfo
().
getText
());
session
.
getServer
().
getChatManager
().
sendTeam
Message
(
session
.
getPlayer
(),
req
.
getChannelId
(),
req
.
getChatInfo
().
getText
());
}
else
if
(
content
==
ChatInfo
.
ContentCase
.
ICON
)
{
session
.
getServer
().
getChatManager
().
sendTeam
Chat
(
session
.
getPlayer
(),
req
.
getChannelId
(),
req
.
getChatInfo
().
getIcon
());
session
.
getServer
().
getChatManager
().
sendTeam
Message
(
session
.
getPlayer
(),
req
.
getChannelId
(),
req
.
getChatInfo
().
getIcon
());
}
session
.
send
(
new
PacketPlayerChatRsp
());
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerPrivateChatReq.java
View file @
eac3745f
...
...
@@ -15,9 +15,9 @@ public class HandlerPrivateChatReq extends PacketHandler {
PrivateChatReq
.
ContentCase
content
=
req
.
getContentCase
();
if
(
content
==
PrivateChatReq
.
ContentCase
.
TEXT
)
{
session
.
getServer
().
getChatManager
().
sendPriv
Ch
at
(
session
.
getPlayer
(),
req
.
getTargetUid
(),
req
.
getText
());
session
.
getServer
().
getChatManager
().
sendPrivat
eMessage
(
session
.
getPlayer
(),
req
.
getTargetUid
(),
req
.
getText
());
}
else
if
(
content
==
PrivateChatReq
.
ContentCase
.
ICON
)
{
session
.
getServer
().
getChatManager
().
sendPriv
Ch
at
(
session
.
getPlayer
(),
req
.
getTargetUid
(),
req
.
getIcon
());
session
.
getServer
().
getChatManager
().
sendPrivat
eMessage
(
session
.
getPlayer
(),
req
.
getTargetUid
(),
req
.
getIcon
());
}
//session.send(new GenshinPacket(PacketOpcodes.PrivateChatRsp)); // Unused by server
...
...
src/main/java/emu/grasscutter/utils/Utils.java
View file @
eac3745f
...
...
@@ -79,6 +79,15 @@ public final class Utils {
return
v7
;
}
/**
* Creates a string with the path to a file.
* @param path The path to the file.
* @return A path using the operating system's file separator.
*/
public
static
String
toFilePath
(
String
path
)
{
return
path
.
replace
(
"/"
,
File
.
separator
);
}
/**
* Checks if a file exists on the file system.
* @param path The path to the file.
...
...
@@ -118,6 +127,16 @@ public final class Utils {
}
}
/**
* Get object with null fallback.
* @param nonNull The object to return if not null.
* @param fallback The object to return if null.
* @return One of the two provided objects.
*/
public
static
<
T
>
T
requireNonNullElseGet
(
T
nonNull
,
T
fallback
)
{
return
nonNull
!=
null
?
nonNull
:
fallback
;
}
/**
* Checks for required files and folders before startup.
*/
...
...
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