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
d98ea08f
Commit
d98ea08f
authored
Apr 18, 2022
by
Melledy
Committed by
GitHub
Apr 18, 2022
Browse files
Merge pull request #12 from Melledy/command-overhaul
Implement a new command handler
parents
85b9d360
7666c92c
Changes
18
Hide whitespace changes
Inline
Side-by-side
src/deprecated/java/emu/grasscutter/commands/PlayerCommands.java
0 → 100644
View file @
d98ea08f
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 @
d98ea08f
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/Grasscutter.java
View file @
d98ea08f
...
...
@@ -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 @
d98ea08f
...
...
@@ -5,9 +5,19 @@ import java.lang.annotation.RetentionPolicy;
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
Command
{
String
[]
aliases
()
default
""
;
String
label
()
default
""
;
String
usage
()
default
""
;
String
[]
aliases
()
default
{
""
};
Execution
execution
()
default
Execution
.
ALL
;
int
gmLevel
()
default
1
;
String
permission
()
default
""
;
String
helpText
()
default
""
;
enum
Execution
{
ALL
,
CONSOLE
,
PLAYER
}
}
src/main/java/emu/grasscutter/commands/CommandHandler.java
0 → 100644
View file @
d98ea08f
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 @
d98ea08f
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 @
d98ea08f
package
emu.grasscutter.commands
;
import
java.lang.reflect.Modifier
;
import
java.util.HashMap
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.Map
;
import
emu.grasscutter.Grasscutter
;
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.World
;
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.Inventory
;
import
emu.grasscutter.game.inventory.ItemType
;
import
emu.grasscutter.game.props.ActionReason
;
import
emu.grasscutter.game.props.FightProperty
;
...
...
@@ -23,306 +19,302 @@ 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
>
commandList
=
new
HashMap
<
String
,
PlayerCommand
>();
private
static
HashMap
<
String
,
PlayerCommand
>
commandAliasList
=
new
HashMap
<
String
,
PlayerCommand
>();
import
java.util.LinkedList
;
import
java.util.List
;
/**
* A container for player-related commands.
*/
public
final
class
PlayerCommands
{
@Command
(
label
=
"give"
,
aliases
=
{
"g"
,
"item"
,
"giveitem"
},
usage
=
"Usage: give [player] <itemId|itemName> [amount]"
)
public
static
class
GiveCommand
implements
CommandHandler
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
int
target
,
item
,
amount
=
1
;
switch
(
args
.
size
())
{
default
:
CommandHandler
.
sendMessage
(
player
,
"Usage: give <player> <itemId|itemName> [amount]"
);
return
;
case
1
:
try
{
item
=
Integer
.
parseInt
(
args
.
get
(
0
));
target
=
player
.
getAccount
().
getPlayerId
();
}
catch
(
NumberFormatException
ignored
)
{
// TODO: Parse from item name using GM Handbook.
CommandHandler
.
sendMessage
(
player
,
"Invalid item id."
);
return
;
}
break
;
case
2
:
try
{
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
if
(
Grasscutter
.
getGameServer
().
getPlayerById
(
target
)
==
null
)
{
target
=
player
.
getId
();
amount
=
Integer
.
parseInt
(
args
.
get
(
1
));
item
=
Integer
.
parseInt
(
args
.
get
(
0
));
}
else
{
item
=
Integer
.
parseInt
(
args
.
get
(
1
));
}
}
catch
(
NumberFormatException
ignored
)
{
// TODO: Parse from item name using GM Handbook.
CommandHandler
.
sendMessage
(
player
,
"Invalid item or player ID."
);
return
;
}
break
;
case
3
:
try
{
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
if
(
Grasscutter
.
getGameServer
().
getPlayerById
(
target
)
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid player ID."
);
return
;
}
item
=
Integer
.
parseInt
(
args
.
get
(
1
));
amount
=
Integer
.
parseInt
(
args
.
get
(
2
));
}
catch
(
NumberFormatException
ignored
)
{
// TODO: Parse from item name using GM Handbook.
CommandHandler
.
sendMessage
(
player
,
"Invalid item or player ID."
);
return
;
}
break
;
}
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerById
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Player not found."
);
return
;
}
ItemData
itemData
=
GenshinData
.
getItemDataMap
().
get
(
item
);
if
(
itemData
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid item id."
);
return
;
}
this
.
item
(
targetPlayer
,
itemData
,
amount
);
}
/**
* give [player] [itemId|itemName] [amount]
*/
@Override
public
void
execute
(
List
<
String
>
args
)
{
if
(
args
.
size
()
<
2
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: give <player> <itemId|itemName> [amount]"
);
return
;
}
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
());
command
.
setHelpText
(
commandAnnotation
.
helpText
());
for
(
String
alias
:
commandAnnotation
.
aliases
())
{
if
(
alias
.
length
()
==
0
)
{
continue
;
}
try
{
int
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
int
item
=
Integer
.
parseInt
(
args
.
get
(
1
));
int
amount
=
1
;
if
(
args
.
size
()
>
2
)
amount
=
Integer
.
parseInt
(
args
.
get
(
2
));
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerById
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Player not found."
);
return
;
}
ItemData
itemData
=
GenshinData
.
getItemDataMap
().
get
(
item
);
if
(
itemData
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid item id."
);
return
;
}
this
.
item
(
targetPlayer
,
itemData
,
amount
);
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid item or player ID."
);
}
}
private
void
item
(
GenshinPlayer
player
,
ItemData
itemData
,
int
amount
)
{
GenshinItem
genshinItem
=
new
GenshinItem
(
itemData
);
if
(
itemData
.
isEquip
())
{
List
<
GenshinItem
>
items
=
new
LinkedList
<>();
for
(
int
i
=
0
;
i
<
amount
;
i
++)
{
items
.
add
(
genshinItem
);
}
player
.
getInventory
().
addItems
(
items
);
player
.
sendPacket
(
new
PacketItemAddHintNotify
(
items
,
ActionReason
.
SubfieldDrop
));
}
else
{
genshinItem
.
setCount
(
amount
);
player
.
getInventory
().
addItem
(
genshinItem
);
player
.
sendPacket
(
new
PacketItemAddHintNotify
(
genshinItem
,
ActionReason
.
SubfieldDrop
));
}
}
}
@Command
(
label
=
"drop"
,
aliases
=
{
"d"
,
"dropitem"
},
usage
=
"Usage: drop <itemId|itemName> [amount]"
,
execution
=
Command
.
Execution
.
PLAYER
)
public
static
class
DropCommand
implements
CommandHandler
{
String
commandName
=
alias
;
commandAliasList
.
put
(
commandName
,
command
);
}
}
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
if
(
args
.
size
()
<
1
)
{
CommandHandler
.
sendMessage
(
player
,
"Usage: drop <itemId|itemName> [amount]"
);
return
;
}
String
commandName
=
cls
.
getSimpleName
().
toLowerCase
();
commandList
.
put
(
commandName
,
command
);
}
}
}
catch
(
Exception
e
)
{
}
}
try
{
int
item
=
Integer
.
parseInt
(
args
.
get
(
0
));
int
amount
=
1
;
if
(
args
.
size
()
>
1
)
amount
=
Integer
.
parseInt
(
args
.
get
(
1
));
public
static
void
handle
(
GenshinPlayer
player
,
String
msg
)
{
String
[]
split
=
msg
.
split
(
" "
);
// End if invalid
if
(
split
.
length
==
0
)
{
return
;
}
ItemData
itemData
=
GenshinData
.
getItemDataMap
().
get
(
item
);
if
(
itemData
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid item id."
);
return
;
}
String
first
=
split
[
0
].
toLowerCase
().
substring
(
1
);
PlayerCommand
c
=
PlayerCommands
.
commandList
.
get
(
first
);
PlayerCommand
a
=
PlayerCommands
.
commandAliasList
.
get
(
first
);
if
(
c
!=
null
||
a
!=
null
)
{
PlayerCommand
cmd
=
c
!=
null
?
c
:
a
;
// Level check
if
(
player
.
getGmLevel
()
<
cmd
.
getLevel
())
{
return
;
}
// Execute
int
len
=
Math
.
min
(
split
[
0
].
length
()
+
1
,
msg
.
length
());
cmd
.
execute
(
player
,
msg
.
substring
(
len
));
}
}
public
static
abstract
class
PlayerCommand
{
// GM level required to use this command
private
int
level
;
private
String
helpText
;
if
(
itemData
.
isEquip
())
{
float
range
=
(
5
f
+
(.
1
f
*
amount
));
for
(
int
i
=
0
;
i
<
amount
;
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
),
amount
);
player
.
getWorld
().
addEntity
(
entity
);
}
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid item or player ID."
);
}
}
}
@Command
(
label
=
"spawn"
,
execution
=
Command
.
Execution
.
PLAYER
,
usage
=
"Usage: spawn <entityId|entityName> [level] [amount]"
)
public
static
class
SpawnCommand
implements
CommandHandler
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
if
(
args
.
size
()
<
1
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: spawn <entityId|entityName> [amount]"
);
return
;
}
protected
int
getLevel
()
{
return
this
.
level
;
}
protected
void
setLevel
(
int
minLevel
)
{
this
.
level
=
minLevel
;
}
try
{
int
entity
=
Integer
.
parseInt
(
args
.
get
(
0
));
int
level
=
1
;
if
(
args
.
size
()
>
1
)
level
=
Integer
.
parseInt
(
args
.
get
(
1
));
int
amount
=
1
;
if
(
args
.
size
()
>
2
)
amount
=
Integer
.
parseInt
(
args
.
get
(
2
));
protected
String
getHelpText
()
{
return
this
.
helpText
;
}
protected
void
setHelpText
(
String
helpText
)
{
this
.
helpText
=
helpText
;
}
MonsterData
entityData
=
GenshinData
.
getMonsterDataMap
().
get
(
entity
);
if
(
entityData
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid entity id."
);
return
;
}
// Main
public
abstract
void
execute
(
GenshinPlayer
player
,
String
raw
);
}
// ================ Commands ================
float
range
=
(
5
f
+
(.
1
f
*
amount
));
for
(
int
i
=
0
;
i
<
amount
;
i
++)
{
Position
pos
=
player
.
getPos
().
clone
().
addX
((
float
)
(
Math
.
random
()
*
range
)
-
(
range
/
2
)).
addY
(
3
f
).
addZ
((
float
)
(
Math
.
random
()
*
range
)
-
(
range
/
2
));
EntityMonster
monster
=
new
EntityMonster
(
player
.
getWorld
(),
entityData
,
pos
,
level
);
player
.
getWorld
().
addEntity
(
monster
);
}
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid item or player ID."
);
}
}
}
@Command
(
label
=
"killall"
,
usage
=
"Usage: killall [sceneId]"
)
public
static
class
KillAllCommand
implements
CommandHandler
{
@Command
(
aliases
=
{
"h"
},
helpText
=
"Shows this command"
)
public
static
class
Help
extends
PlayerCommand
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
World
world
=
player
.
getWorld
();
world
.
getEntities
().
values
().
stream
()
.
filter
(
entity
->
entity
instanceof
EntityMonster
)
.
forEach
(
entity
->
world
.
killEntity
(
entity
,
0
));
}
@Override
public
void
execute
(
List
<
String
>
args
)
{
if
(
args
.
size
()
<
1
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: killall [sceneId]"
);
return
;
}
try
{
int
sceneId
=
Integer
.
parseInt
(
args
.
get
(
0
));
CommandHandler
.
sendMessage
(
null
,
"Killing all monsters in scene "
+
sceneId
);
// TODO: Implement getting worlds by scene ID.
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid scene id."
);
}
}
}
@Command
(
label
=
"resetconst"
,
aliases
=
{
"resetconstellation"
},
usage
=
"Usage: resetconst [all]"
,
execution
=
Command
.
Execution
.
PLAYER
)
public
static
class
ResetConstellationCommand
implements
CommandHandler
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
if
(
args
.
size
()
>
0
&&
args
.
get
(
0
).
equalsIgnoreCase
(
"all"
))
{
player
.
getAvatars
().
forEach
(
this
::
resetConstellation
);
player
.
dropMessage
(
"Reset all avatars' constellations."
);
}
else
{
EntityAvatar
entity
=
player
.
getTeamManager
().
getCurrentAvatarEntity
();
if
(
entity
==
null
)
return
;
GenshinAvatar
avatar
=
entity
.
getAvatar
();
this
.
resetConstellation
(
avatar
);
@Override
public
void
execute
(
GenshinPlayer
player
,
String
raw
)
{
String
helpMessage
=
"Grasscutter Commands: "
;
for
(
Map
.
Entry
<
String
,
PlayerCommand
>
cmd
:
commandList
.
entrySet
())
{
player
.
dropMessage
(
"Constellations for "
+
avatar
.
getAvatarData
().
getName
()
+
" have been reset. Please relog to see changes."
);
}
}
private
void
resetConstellation
(
GenshinAvatar
avatar
)
{
avatar
.
getTalentIdList
().
clear
();
avatar
.
setCoreProudSkillLevel
(
0
);
avatar
.
recalcStats
();
avatar
.
save
();
}
}
@Command
(
label
=
"godmode"
,
usage
=
"Usage: godmode"
,
execution
=
Command
.
Execution
.
PLAYER
)
public
static
class
GodModeCommand
implements
CommandHandler
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
player
.
setGodmode
(!
player
.
inGodmode
());
player
.
dropMessage
(
"Godmode is now "
+
(
player
.
inGodmode
()
?
"enabled"
:
"disabled"
)
+
"."
);
}
}
@Command
(
label
=
"sethealth"
,
aliases
=
{
"sethp"
},
usage
=
"Usage: sethealth <hp>"
,
execution
=
Command
.
Execution
.
PLAYER
)
public
static
class
SetHealthCommand
implements
CommandHandler
{
helpMessage
+=
"\n"
+
cmd
.
getKey
()
+
" - "
+
cmd
.
getValue
().
helpText
;
}
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
if
(
args
.
size
()
<
1
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: sethealth <hp>"
);
return
;
}
try
{
int
health
=
Integer
.
parseInt
(
args
.
get
(
0
));
EntityAvatar
entity
=
player
.
getTeamManager
().
getCurrentAvatarEntity
();
if
(
entity
==
null
)
return
;
entity
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
health
);
entity
.
getWorld
().
broadcastPacket
(
new
PacketEntityFightPropUpdateNotify
(
entity
,
FightProperty
.
FIGHT_PROP_CUR_HP
));
player
.
dropMessage
(
"Health set to "
+
health
+
"."
);
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid health value."
);
}
}
}
@Command
(
label
=
"clearartifacts"
,
aliases
=
{
"clearart"
},
usage
=
"Usage: clearartifacts"
,
execution
=
Command
.
Execution
.
PLAYER
)
public
static
class
ClearArtifactsCommand
implements
CommandHandler
{
player
.
dropMessage
(
helpMessage
);
}
}
@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
);
}
}
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
Inventory
playerInventory
=
player
.
getInventory
();
playerInventory
.
getItems
().
values
().
stream
()
.
filter
(
item
->
item
.
getItemType
()
==
ItemType
.
ITEM_RELIQUARY
)
.
filter
(
item
->
item
.
getLevel
()
==
1
&&
item
.
getExp
()
==
0
)
.
filter
(
item
->
!
item
.
isLocked
()
&&
!
item
.
isEquipped
())
.
forEach
(
item
->
playerInventory
.
removeItem
(
item
,
item
.
getCount
()));
}
}
}
src/main/java/emu/grasscutter/commands/ServerCommands.java
View file @
d98ea08f
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
<>();
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;
*/
}
}
}
import
java.util.List
;
import
java.util.stream.Collectors
;
/**
* 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."
);
}
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
this
.
execute
(
args
);
}
}
@Command
(
label
=
"sendmessage"
,
aliases
=
{
"sendmsg"
,
"msg"
},
usage
=
"Usage: sendmessage <player> <message>"
)
public
static
class
SendMessageCommand
implements
CommandHandler
{
@Override
public
void
execute
(
List
<
String
>
args
)
{
if
(
args
.
size
()
<
2
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: sendmessage <player> <message>"
);
return
;
}
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
;
}
targetPlayer
.
dropMessage
(
message
);
CommandHandler
.
sendMessage
(
null
,
"Message sent."
);
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid player ID."
);
}
}
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
if
(
args
.
size
()
<
2
)
{
CommandHandler
.
sendMessage
(
player
,
"Usage: sendmessage <player> <message>"
);
return
;
}
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
(
player
,
"Player not found."
);
return
;
}
targetPlayer
.
sendMessage
(
player
,
message
);
CommandHandler
.
sendMessage
(
player
,
"Message sent."
);
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid player ID."
);
}
}
}
@Command
(
label
=
"account"
,
usage
=
"Usage: account <create|delete> <username> [uid]"
,
execution
=
Command
.
Execution
.
CONSOLE
)
public
static
class
AccountCommand
implements
CommandHandler
{
@Override
public
void
execute
(
List
<
String
>
args
)
{
if
(
args
.
size
()
<
2
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: account <create|delete> <username> [uid]"
);
return
;
}
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
;
}
}
Account
account
=
DatabaseHelper
.
createAccountWithId
(
username
,
uid
);
if
(
account
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Account already exists."
);
return
;
}
else
{
CommandHandler
.
sendMessage
(
null
,
"Account created with UID "
+
account
.
getPlayerId
()
+
"."
);
account
.
addPermission
(
"*"
);
// Grant the player superuser permissions.
}
return
;
case
"delete"
:
if
(
DatabaseHelper
.
deleteAccount
(
username
))
{
CommandHandler
.
sendMessage
(
null
,
"Account deleted."
);
return
;
}
else
CommandHandler
.
sendMessage
(
null
,
"Account not found."
);
return
;
}
}
}
@Command
(
label
=
"permission"
,
usage
=
"Usage: permission <add|remove> <username> <permission>"
,
execution
=
Command
.
Execution
.
CONSOLE
)
public
static
class
PermissionCommand
implements
CommandHandler
{
@Override
public
void
execute
(
List
<
String
>
args
)
{
if
(
args
.
size
()
<
3
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: permission <add|remove> <username> <permission>"
);
return
;
}
String
action
=
args
.
get
(
0
);
String
username
=
args
.
get
(
1
);
String
permission
=
args
.
get
(
2
);
Account
account
=
DatabaseHelper
.
getAccountByName
(
username
);
if
(
account
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Account not found."
);
return
;
}
switch
(
action
)
{
default
:
CommandHandler
.
sendMessage
(
null
,
"Usage: permission <add|remove> <username> <permission>"
);
return
;
case
"add"
:
if
(
account
.
addPermission
(
permission
))
{
CommandHandler
.
sendMessage
(
null
,
"Permission added."
);
return
;
}
else
CommandHandler
.
sendMessage
(
null
,
"They already have this permission!"
);
return
;
case
"remove"
:
if
(
account
.
removePermission
(
permission
))
{
CommandHandler
.
sendMessage
(
null
,
"Permission removed."
);
return
;
}
else
CommandHandler
.
sendMessage
(
null
,
"They don't have this permission!"
);
return
;
}
}
}
@Command
(
label
=
"help"
,
usage
=
"Usage: help [command]"
)
public
static
class
HelpCommand
implements
CommandHandler
{
@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
;
}
Command
annotation
=
handler
.
getClass
().
getAnnotation
(
Command
.
class
);
CommandHandler
.
sendMessage
(
null
,
annotation
.
usage
());
}
}
@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
;
}
Command
annotation
=
handler
.
getClass
().
getAnnotation
(
Command
.
class
);
CommandHandler
.
sendMessage
(
player
,
annotation
.
usage
());
}
}
}
}
src/main/java/emu/grasscutter/database/DatabaseHelper.java
View file @
d98ea08f
...
...
@@ -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 @
d98ea08f
...
...
@@ -9,6 +9,8 @@ import emu.grasscutter.utils.Crypto;
import
emu.grasscutter.utils.Utils
;
import
dev.morphia.annotations.IndexOptions
;
import
java.util.List
;
@Entity
(
value
=
"accounts"
,
noClassnameStored
=
true
)
public
class
Account
{
@Id
private
String
id
;
...
...
@@ -23,6 +25,7 @@ public class Account {
private
String
token
;
private
String
sessionKey
;
// Session token for dispatch server
private
List
<
String
>
permissions
;
@Deprecated
public
Account
()
{}
...
...
@@ -84,6 +87,22 @@ public class Account {
this
.
save
();
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
()
{
...
...
src/main/java/emu/grasscutter/game/GenshinPlayer.java
View file @
d98ea08f
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
;
}
...
...
@@ -558,6 +553,15 @@ public class GenshinPlayer {
public
void
dropMessage
(
Object
message
)
{
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 @
d98ea08f
...
...
@@ -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 @
d98ea08f
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/game/GameServer.java
View file @
d98ea08f
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.GenshinPlayer
;
import
emu.grasscutter.game.dungeons.DungeonManager
;
...
...
@@ -23,11 +19,10 @@ 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
;
private
final
ChatManager
chatManager
;
...
...
@@ -36,9 +31,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 +47,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 +98,10 @@ public class GameServer extends MihoyoKcpServer {
return
dungeonManager
;
}
public
CommandMap
getCommandMap
()
{
return
this
.
commandMap
;
}
public
void
registerPlayer
(
GenshinPlayer
player
)
{
getPlayers
().
put
(
player
.
getId
(),
player
);
}
...
...
src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerChatReq.java
View file @
d98ea08f
...
...
@@ -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 @
d98ea08f
...
...
@@ -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 @
d98ea08f
...
...
@@ -118,6 +118,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.
*/
...
...
src/main/resources/logback.xml
View file @
d98ea08f
<Configuration>
<appender
name=
"STDOUT"
class=
"ch.qos.logback.core.ConsoleAppender"
>
<encoder>
<pattern>
[%d{HH:mm:ss}] [%level] %msg%n
</pattern>
<pattern>
[%d{HH:mm:ss}] [%
highlight(%
level
)
] %msg%n
</pattern>
</encoder>
</appender>
<logger
name=
"org.reflections"
level=
"OFF"
/>
...
...
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