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
e6402c31
Commit
e6402c31
authored
Apr 22, 2022
by
memetrollsXD
Browse files
Merge branch 'stable' into development
parents
d5d90564
1dfe8733
Changes
107
Show whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/command/commands/StopCommand.java
0 → 100644
View file @
e6402c31
package
emu.grasscutter.command.commands
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.command.Command
;
import
emu.grasscutter.command.CommandHandler
;
import
emu.grasscutter.game.GenshinPlayer
;
import
java.util.List
;
@Command
(
label
=
"stop"
,
usage
=
"stop"
,
description
=
"Stops the server"
,
permission
=
"server.stop"
)
public
final
class
StopCommand
implements
CommandHandler
{
@Override
public
void
execute
(
GenshinPlayer
sender
,
List
<
String
>
args
)
{
CommandHandler
.
sendMessage
(
null
,
"Server shutting down..."
);
for
(
GenshinPlayer
p
:
Grasscutter
.
getGameServer
().
getPlayers
().
values
())
{
CommandHandler
.
sendMessage
(
p
,
"Server shutting down..."
);
}
System
.
exit
(
1
);
}
}
src/main/java/emu/grasscutter/command/commands/WeatherCommand.java
0 → 100644
View file @
e6402c31
package
emu.grasscutter.command.commands
;
import
emu.grasscutter.command.Command
;
import
emu.grasscutter.command.CommandHandler
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.props.ClimateType
;
import
emu.grasscutter.server.packet.send.PacketSceneAreaWeatherNotify
;
import
java.util.List
;
@Command
(
label
=
"weather"
,
usage
=
"weather <weatherId> [climateId]"
,
description
=
"Changes the weather."
,
aliases
=
{
"w"
},
permission
=
"player.weather"
)
public
final
class
WeatherCommand
implements
CommandHandler
{
@Override
public
void
execute
(
GenshinPlayer
sender
,
List
<
String
>
args
)
{
if
(
sender
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Run this command in-game."
);
return
;
}
if
(
args
.
size
()
<
1
)
{
CommandHandler
.
sendMessage
(
sender
,
"Usage: weather <weatherId> [climateId]"
);
return
;
}
try
{
int
weatherId
=
Integer
.
parseInt
(
args
.
get
(
0
));
int
climateId
=
args
.
size
()
>
1
?
Integer
.
parseInt
(
args
.
get
(
1
))
:
1
;
ClimateType
climate
=
ClimateType
.
getTypeByValue
(
climateId
);
sender
.
getScene
().
setWeather
(
weatherId
);
sender
.
getScene
().
setClimate
(
climate
);
sender
.
getScene
().
broadcastPacket
(
new
PacketSceneAreaWeatherNotify
(
sender
));
CommandHandler
.
sendMessage
(
sender
,
"Changed weather to "
+
weatherId
+
" with climate "
+
climateId
);
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
sender
,
"Invalid ID."
);
}
}
}
src/main/java/emu/grasscutter/commands/Command.java
deleted
100644 → 0
View file @
d5d90564
package
emu.grasscutter.commands
;
import
java.lang.annotation.Retention
;
import
java.lang.annotation.RetentionPolicy
;
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
Command
{
String
label
()
default
""
;
String
usage
()
default
""
;
String
[]
aliases
()
default
{
""
};
Execution
execution
()
default
Execution
.
ALL
;
String
permission
()
default
""
;
enum
Execution
{
ALL
,
CONSOLE
,
PLAYER
}
}
src/main/java/emu/grasscutter/commands/PlayerCommands.java
deleted
100644 → 0
View file @
d5d90564
package
emu.grasscutter.commands
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.def.ItemData
;
import
emu.grasscutter.data.def.AvatarData
;
import
emu.grasscutter.data.def.AvatarSkillDepotData
;
import
emu.grasscutter.data.def.MonsterData
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.GenshinScene
;
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.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
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketItemAddHintNotify
;
import
emu.grasscutter.utils.Position
;
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
().
getPlayerByUid
(
target
)
==
null
)
{
target
=
player
.
getUid
();
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
().
getPlayerByUid
(
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
().
getPlayerByUid
(
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
;
}
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
().
getPlayerByUid
(
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
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
if
(
args
.
size
()
<
1
)
{
CommandHandler
.
sendMessage
(
player
,
"Usage: drop <itemId|itemName> [amount]"
);
return
;
}
try
{
int
item
=
Integer
.
parseInt
(
args
.
get
(
0
));
int
amount
=
1
;
if
(
args
.
size
()
>
1
)
amount
=
Integer
.
parseInt
(
args
.
get
(
1
));
ItemData
itemData
=
GenshinData
.
getItemDataMap
().
get
(
item
);
if
(
itemData
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid item id."
);
return
;
}
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
.
getScene
(),
player
,
itemData
,
pos
,
1
);
player
.
getScene
().
addEntity
(
entity
);
}
}
else
{
EntityItem
entity
=
new
EntityItem
(
player
.
getScene
(),
player
,
itemData
,
player
.
getPos
().
clone
().
addY
(
3
f
),
amount
);
player
.
getScene
().
addEntity
(
entity
);
}
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid item or player ID."
);
}
}
}
@Command
(
label
=
"givechar"
,
aliases
=
{
"givec"
},
usage
=
"Usage: givechar <player|avatarId> [level|avatarId] [level]"
)
public
static
class
GiveCharCommand
implements
CommandHandler
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
int
target
,
avatarId
,
level
=
1
,
ascension
=
1
;
if
(
args
.
size
()
<
1
)
{
CommandHandler
.
sendMessage
(
player
,
"Usage: givechar <player> <avatarId> [level]"
);
return
;
}
switch
(
args
.
size
())
{
default
:
CommandHandler
.
sendMessage
(
player
,
"Usage: givechar <player> <avatarId> [level]"
);
return
;
case
2
:
try
{
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
if
(
Grasscutter
.
getGameServer
().
getPlayerByUid
(
target
)
==
null
)
{
target
=
player
.
getUid
();
level
=
Integer
.
parseInt
(
args
.
get
(
1
));
avatarId
=
Integer
.
parseInt
(
args
.
get
(
0
));
}
else
{
avatarId
=
Integer
.
parseInt
(
args
.
get
(
1
));
}
}
catch
(
NumberFormatException
ignored
)
{
// TODO: Parse from avatar name using GM Handbook.
CommandHandler
.
sendMessage
(
player
,
"Invalid avatar or player ID."
);
return
;
}
break
;
case
3
:
try
{
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
if
(
Grasscutter
.
getGameServer
().
getPlayerByUid
(
target
)
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid player ID."
);
return
;
}
avatarId
=
Integer
.
parseInt
(
args
.
get
(
1
));
level
=
Integer
.
parseInt
(
args
.
get
(
2
));
}
catch
(
NumberFormatException
ignored
)
{
// TODO: Parse from avatar name using GM Handbook.
CommandHandler
.
sendMessage
(
player
,
"Invalid avatar or player ID."
);
return
;
}
break
;
}
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerByUid
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Player not found."
);
return
;
}
AvatarData
avatarData
=
GenshinData
.
getAvatarDataMap
().
get
(
avatarId
);
if
(
avatarData
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid avatar id."
);
return
;
}
// Calculate ascension level.
if
(
level
<=
40
)
{
ascension
=
(
int
)
Math
.
ceil
(
level
/
20
f
);
}
else
{
ascension
=
(
int
)
Math
.
ceil
(
level
/
10
f
)
-
3
;
}
GenshinAvatar
avatar
=
new
GenshinAvatar
(
avatarId
);
avatar
.
setLevel
(
level
);
avatar
.
setPromoteLevel
(
ascension
);
// This will handle stats and talents
avatar
.
recalcStats
();
targetPlayer
.
addAvatar
(
avatar
);
}
@Override
public
void
execute
(
List
<
String
>
args
)
{
if
(
args
.
size
()
<
2
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: givechar <player> <itemId|itemName> [amount]"
);
return
;
}
try
{
int
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
int
avatarID
=
Integer
.
parseInt
(
args
.
get
(
1
));
int
level
=
1
;
if
(
args
.
size
()
>
2
)
level
=
Integer
.
parseInt
(
args
.
get
(
2
));
int
ascension
;
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerByUid
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Player not found."
);
return
;
}
AvatarData
avatarData
=
GenshinData
.
getAvatarDataMap
().
get
(
avatarID
);
if
(
avatarData
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid avatar id."
);
return
;
}
// Calculate ascension level.
if
(
level
<=
40
)
{
ascension
=
(
int
)
Math
.
ceil
(
level
/
20
f
);
}
else
{
ascension
=
(
int
)
Math
.
ceil
(
level
/
10
f
)
-
3
;
}
GenshinAvatar
avatar
=
new
GenshinAvatar
(
avatarID
);
avatar
.
setLevel
(
level
);
avatar
.
setPromoteLevel
(
ascension
);
// This will handle stats and talents
avatar
.
recalcStats
();
targetPlayer
.
addAvatar
(
avatar
);
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
null
,
"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
;
}
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
));
MonsterData
entityData
=
GenshinData
.
getMonsterDataMap
().
get
(
entity
);
if
(
entityData
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid entity id."
);
return
;
}
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
.
getScene
(),
entityData
,
pos
,
level
);
player
.
getScene
().
addEntity
(
monster
);
}
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid item or player ID."
);
}
}
}
@Command
(
label
=
"killall"
,
usage
=
"Usage: killall [playerUid] [sceneId]"
)
public
static
class
KillAllCommand
implements
CommandHandler
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
GenshinScene
scene
=
player
.
getScene
();
scene
.
getEntities
().
values
().
stream
()
.
filter
(
entity
->
entity
instanceof
EntityMonster
)
.
forEach
(
entity
->
scene
.
killEntity
(
entity
,
0
));
CommandHandler
.
sendMessage
(
null
,
"Killing all monsters in scene "
+
scene
.
getId
());
}
@Override
public
void
execute
(
List
<
String
>
args
)
{
if
(
args
.
size
()
<
2
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: killall [playerUid] [sceneId]"
);
return
;
}
try
{
int
playerUid
=
Integer
.
parseInt
(
args
.
get
(
0
));
int
sceneId
=
Integer
.
parseInt
(
args
.
get
(
1
));
GenshinPlayer
player
=
Grasscutter
.
getGameServer
().
getPlayerByUid
(
playerUid
);
if
(
player
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Player not found or offline."
);
return
;
}
GenshinScene
scene
=
player
.
getWorld
().
getSceneById
(
sceneId
);
if
(
scene
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Scene not found in player world"
);
return
;
}
scene
.
getEntities
().
values
().
stream
()
.
filter
(
entity
->
entity
instanceof
EntityMonster
)
.
forEach
(
entity
->
scene
.
killEntity
(
entity
,
0
));
CommandHandler
.
sendMessage
(
null
,
"Killing all monsters in scene "
+
scene
.
getId
());
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid arguments."
);
}
}
}
@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
);
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
{
@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
=
"setworldlevel"
,
aliases
=
{
"setworldlvl"
},
usage
=
"Usage: setworldlevel <level>"
,
execution
=
Command
.
Execution
.
PLAYER
)
public
static
class
SetWorldLevelCommand
implements
CommandHandler
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
if
(
args
.
size
()
<
1
)
{
CommandHandler
.
sendMessage
(
player
,
"Usage: setworldlevel <level>"
);
return
;
}
try
{
int
level
=
Integer
.
parseInt
(
args
.
get
(
0
));
// Set in both world and player props
player
.
getWorld
().
setWorldLevel
(
level
);
player
.
setProperty
(
PlayerProperty
.
PROP_PLAYER_WORLD_LEVEL
,
level
);
player
.
dropMessage
(
"World level set to "
+
level
+
"."
);
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid world level."
);
}
}
}
@Command
(
label
=
"clearartifacts"
,
aliases
=
{
"clearart"
},
usage
=
"Usage: clearartifacts"
,
execution
=
Command
.
Execution
.
PLAYER
)
public
static
class
ClearArtifactsCommand
implements
CommandHandler
{
@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
()));
}
}
@Command
(
label
=
"changescene"
,
aliases
=
{
"scene"
},
usage
=
"Usage: changescene <scene id>"
,
execution
=
Command
.
Execution
.
PLAYER
)
public
static
class
ChangeSceneCommand
implements
CommandHandler
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
if
(
args
.
size
()
<
1
)
{
CommandHandler
.
sendMessage
(
player
,
"Usage: changescene <scene id>"
);
return
;
}
try
{
int
sceneId
=
Integer
.
parseInt
(
args
.
get
(
0
));
boolean
result
=
player
.
getWorld
().
transferPlayerToScene
(
player
,
sceneId
,
player
.
getPos
());
if
(!
result
)
{
CommandHandler
.
sendMessage
(
null
,
"Scene does not exist or you are already in it"
);
}
}
catch
(
Exception
e
)
{
CommandHandler
.
sendMessage
(
player
,
"Usage: changescene <scene id>"
);
return
;
}
}
}
}
src/main/java/emu/grasscutter/commands/ServerCommands.java
deleted
100644 → 0
View file @
d5d90564
package
emu.grasscutter.commands
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.Account
;
import
emu.grasscutter.game.GenshinPlayer
;
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
().
getPlayerByUid
(
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
().
getPlayerByUid
(
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
=
Grasscutter
.
getGameServer
().
getAccountByName
(
username
);
if
(
account
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Account not found."
);
return
;
}
switch
(
action
)
{
default
:
CommandHandler
.
sendMessage
(
null
,
"Usage: permission <add|remove> <username> <permission>"
);
break
;
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
;
}
account
.
save
();
}
}
@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/data/GenshinData.java
View file @
e6402c31
package
emu.grasscutter.data
;
import
java.lang.reflect.Field
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.utils.Utils
;
import
emu.grasscutter.data.custom.AbilityEmbryoEntry
;
import
emu.grasscutter.data.custom.OpenConfigEntry
;
import
emu.grasscutter.data.custom.ScenePointEntry
;
import
emu.grasscutter.data.def.*
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
...
...
@@ -18,6 +21,7 @@ public class GenshinData {
private
static
final
Int2ObjectMap
<
String
>
abilityHashes
=
new
Int2ObjectOpenHashMap
<>();
private
static
final
Map
<
String
,
AbilityEmbryoEntry
>
abilityEmbryos
=
new
HashMap
<>();
private
static
final
Map
<
String
,
OpenConfigEntry
>
openConfigEntries
=
new
HashMap
<>();
private
static
final
Map
<
String
,
ScenePointEntry
>
scenePointEntries
=
new
HashMap
<>();
// ExcelConfigs
private
static
final
Int2ObjectMap
<
PlayerLevelData
>
playerLevelDataMap
=
new
Int2ObjectOpenHashMap
<>();
...
...
@@ -52,6 +56,10 @@ public class GenshinData {
private
static
final
Int2ObjectMap
<
AvatarCostumeData
>
avatarCostumeDataItemIdMap
=
new
Int2ObjectLinkedOpenHashMap
<>();
private
static
final
Int2ObjectMap
<
SceneData
>
sceneDataMap
=
new
Int2ObjectLinkedOpenHashMap
<>();
private
static
final
Int2ObjectMap
<
FetterData
>
fetterDataMap
=
new
Int2ObjectOpenHashMap
<>();
// Cache
private
static
Map
<
Integer
,
List
<
Integer
>>
fetters
=
new
HashMap
<>();
public
static
Int2ObjectMap
<?>
getMapByResourceDef
(
Class
<?>
resourceDefinition
)
{
Int2ObjectMap
<?>
map
=
null
;
...
...
@@ -82,6 +90,10 @@ public class GenshinData {
return
openConfigEntries
;
}
public
static
Map
<
String
,
ScenePointEntry
>
getScenePointEntries
()
{
return
scenePointEntries
;
}
public
static
Int2ObjectMap
<
AvatarData
>
getAvatarDataMap
()
{
return
avatarDataMap
;
}
...
...
@@ -215,4 +227,17 @@ public class GenshinData {
public
static
Int2ObjectMap
<
SceneData
>
getSceneDataMap
()
{
return
sceneDataMap
;
}
public
static
Map
<
Integer
,
List
<
Integer
>>
getFetterDataEntries
()
{
if
(
fetters
.
isEmpty
())
{
fetterDataMap
.
forEach
((
k
,
v
)
->
{
if
(!
fetters
.
containsKey
(
v
.
getAvatarId
()))
{
fetters
.
put
(
v
.
getAvatarId
(),
new
ArrayList
<>());
}
fetters
.
get
(
v
.
getAvatarId
()).
add
(
k
);
});
}
return
fetters
;
}
}
src/main/java/emu/grasscutter/data/ResourceLoader.java
View file @
e6402c31
...
...
@@ -10,11 +10,15 @@ import java.util.regex.Pattern;
import
emu.grasscutter.utils.Utils
;
import
org.reflections.Reflections
;
import
com.google.gson.JsonElement
;
import
com.google.gson.reflect.TypeToken
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.common.PointData
;
import
emu.grasscutter.data.common.ScenePointConfig
;
import
emu.grasscutter.data.custom.AbilityEmbryoEntry
;
import
emu.grasscutter.data.custom.OpenConfigEntry
;
import
emu.grasscutter.data.custom.ScenePointEntry
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
public
class
ResourceLoader
{
...
...
@@ -42,6 +46,7 @@ public class ResourceLoader {
loadOpenConfig
();
// Load resources
loadResources
();
loadScenePoints
();
// Process into depots
GenshinDepot
.
load
();
// Custom - TODO move this somewhere else
...
...
@@ -121,6 +126,51 @@ public class ResourceLoader {
}
}
private
static
void
loadScenePoints
()
{
Pattern
pattern
=
Pattern
.
compile
(
"(?<=scene)(.*?)(?=_point.json)"
);
File
folder
=
new
File
(
Grasscutter
.
getConfig
().
RESOURCE_FOLDER
+
"BinOutput/Scene/Point"
);
if
(!
folder
.
isDirectory
()
||
!
folder
.
exists
()
||
folder
.
listFiles
()
==
null
)
{
Grasscutter
.
getLogger
().
error
(
"Scene point files cannot be found, you cannot use teleport waypoints!"
);
return
;
}
List
<
ScenePointEntry
>
scenePointList
=
new
ArrayList
<>();
for
(
File
file
:
folder
.
listFiles
())
{
ScenePointConfig
config
=
null
;
Integer
sceneId
=
null
;
Matcher
matcher
=
pattern
.
matcher
(
file
.
getName
());
if
(
matcher
.
find
())
{
sceneId
=
Integer
.
parseInt
(
matcher
.
group
(
1
));
}
else
{
continue
;
}
try
(
FileReader
fileReader
=
new
FileReader
(
file
))
{
config
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
ScenePointConfig
.
class
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
continue
;
}
if
(
config
.
points
==
null
)
{
continue
;
}
for
(
Map
.
Entry
<
String
,
JsonElement
>
entry
:
config
.
points
.
entrySet
())
{
PointData
pointData
=
Grasscutter
.
getGsonFactory
().
fromJson
(
entry
.
getValue
(),
PointData
.
class
);
ScenePointEntry
sl
=
new
ScenePointEntry
(
sceneId
+
"_"
+
entry
.
getKey
(),
pointData
);
scenePointList
.
add
(
sl
);
}
for
(
ScenePointEntry
entry
:
scenePointList
)
{
GenshinData
.
getScenePointEntries
().
put
(
entry
.
getName
(),
entry
);
}
}
}
private
static
void
loadAbilityEmbryos
()
{
// Read from cached file if exists
File
embryoCache
=
new
File
(
Grasscutter
.
getConfig
().
DATA_FOLDER
+
"AbilityEmbryos.json"
);
...
...
@@ -197,7 +247,7 @@ public class ResourceLoader {
}
else
{
Map
<
String
,
OpenConfigEntry
>
map
=
new
TreeMap
<>();
java
.
lang
.
reflect
.
Type
type
=
new
TypeToken
<
Map
<
String
,
OpenConfigData
[]>>()
{}.
getType
();
String
[]
folderNames
=
{
"BinOutput
\\
Talent
\\
EquipTalents
\\
"
,
"BinOutput
\\
Talent
\\
AvatarTalents
\\
"
};
String
[]
folderNames
=
{
"BinOutput
/
Talent
/
EquipTalents
/
"
,
"BinOutput
/
Talent
/
AvatarTalents
/
"
};
for
(
String
name
:
folderNames
)
{
File
folder
=
new
File
(
Utils
.
toFilePath
(
Grasscutter
.
getConfig
().
RESOURCE_FOLDER
+
name
));
...
...
src/main/java/emu/grasscutter/data/common/PointData.java
0 → 100644
View file @
e6402c31
package
emu.grasscutter.data.common
;
public
class
PointData
{
private
pos
tranPos
;
public
pos
getTranPos
()
{
return
tranPos
;
}
public
void
setTranPos
(
pos
tranPos
)
{
this
.
tranPos
=
tranPos
;
}
public
class
pos
{
private
float
x
;
private
float
y
;
private
float
z
;
public
float
getX
()
{
return
x
;
}
public
void
setX
(
float
x
)
{
this
.
x
=
x
;
}
public
float
getY
()
{
return
y
;
}
public
void
setY
(
float
y
)
{
this
.
y
=
y
;
}
public
float
getZ
()
{
return
z
;
}
public
void
setZ
(
float
z
)
{
this
.
z
=
z
;
}
}
}
src/main/java/emu/grasscutter/data/common/ScenePointConfig.java
0 → 100644
View file @
e6402c31
package
emu.grasscutter.data.common
;
import
com.google.gson.JsonObject
;
public
class
ScenePointConfig
{
public
JsonObject
points
;
public
JsonObject
getPoints
()
{
return
points
;
}
public
void
setPoints
(
JsonObject
Points
)
{
points
=
Points
;
}
}
src/main/java/emu/grasscutter/data/custom/ScenePointEntry.java
0 → 100644
View file @
e6402c31
package
emu.grasscutter.data.custom
;
import
emu.grasscutter.data.common.PointData
;
public
class
ScenePointEntry
{
private
String
name
;
private
PointData
pointData
;
public
ScenePointEntry
(
String
name
,
PointData
pointData
)
{
this
.
name
=
name
;
this
.
pointData
=
pointData
;
}
public
String
getName
()
{
return
name
;
}
public
PointData
getPointData
()
{
return
pointData
;
}
}
src/main/java/emu/grasscutter/data/def/AvatarData.java
View file @
e6402c31
...
...
@@ -56,6 +56,8 @@ public class AvatarData extends GenshinResource {
private
AvatarSkillDepotData
skillDepot
;
private
IntList
abilities
;
private
List
<
Integer
>
fetters
;
@Override
public
int
getId
(){
return
this
.
Id
;
...
...
@@ -193,10 +195,17 @@ public class AvatarData extends GenshinResource {
return
abilities
;
}
public
List
<
Integer
>
getFetters
()
{
return
fetters
;
}
@Override
public
void
onLoad
()
{
this
.
skillDepot
=
GenshinData
.
getAvatarSkillDepotDataMap
().
get
(
this
.
SkillDepotId
);
// Get fetters from GenshinData
this
.
fetters
=
GenshinData
.
getFetterDataEntries
().
get
(
this
.
Id
);
int
size
=
GenshinData
.
getAvatarCurveDataMap
().
size
();
this
.
hpGrowthCurve
=
new
float
[
size
];
this
.
attackGrowthCurve
=
new
float
[
size
];
...
...
src/main/java/emu/grasscutter/data/def/FetterData.java
0 → 100644
View file @
e6402c31
package
emu.grasscutter.data.def
;
import
emu.grasscutter.data.GenshinResource
;
import
emu.grasscutter.data.ResourceType
;
import
emu.grasscutter.data.ResourceType.LoadPriority
;
@ResourceType
(
name
=
{
"FetterInfoExcelConfigData.json"
,
"FettersExcelConfigData.json"
,
"FetterStoryExcelConfigData.json"
},
loadPriority
=
LoadPriority
.
HIGHEST
)
public
class
FetterData
extends
GenshinResource
{
private
int
AvatarId
;
private
int
FetterId
;
@Override
public
int
getId
()
{
return
FetterId
;
}
public
int
getAvatarId
()
{
return
AvatarId
;
}
@Override
public
void
onLoad
()
{
}
}
src/main/java/emu/grasscutter/database/DatabaseHelper.java
View file @
e6402c31
...
...
@@ -74,36 +74,36 @@ public class DatabaseHelper {
}
public
static
void
saveAccount
(
Account
account
)
{
DatabaseManager
.
getDatastore
().
save
(
account
);
DatabaseManager
.
get
Account
Datastore
().
save
(
account
);
}
public
static
Account
getAccountByName
(
String
username
)
{
MorphiaCursor
<
Account
>
cursor
=
DatabaseManager
.
getDatastore
().
createQuery
(
Account
.
class
).
field
(
"username"
).
equalIgnoreCase
(
username
).
find
(
FIND_ONE
);
MorphiaCursor
<
Account
>
cursor
=
DatabaseManager
.
get
Account
Datastore
().
createQuery
(
Account
.
class
).
field
(
"username"
).
equalIgnoreCase
(
username
).
find
(
FIND_ONE
);
if
(!
cursor
.
hasNext
())
return
null
;
return
cursor
.
next
();
}
public
static
Account
getAccountByToken
(
String
token
)
{
if
(
token
==
null
)
return
null
;
MorphiaCursor
<
Account
>
cursor
=
DatabaseManager
.
getDatastore
().
createQuery
(
Account
.
class
).
field
(
"token"
).
equal
(
token
).
find
(
FIND_ONE
);
MorphiaCursor
<
Account
>
cursor
=
DatabaseManager
.
get
Account
Datastore
().
createQuery
(
Account
.
class
).
field
(
"token"
).
equal
(
token
).
find
(
FIND_ONE
);
if
(!
cursor
.
hasNext
())
return
null
;
return
cursor
.
next
();
}
public
static
Account
getAccountById
(
String
uid
)
{
MorphiaCursor
<
Account
>
cursor
=
DatabaseManager
.
getDatastore
().
createQuery
(
Account
.
class
).
field
(
"_id"
).
equal
(
uid
).
find
(
FIND_ONE
);
MorphiaCursor
<
Account
>
cursor
=
DatabaseManager
.
get
Account
Datastore
().
createQuery
(
Account
.
class
).
field
(
"_id"
).
equal
(
uid
).
find
(
FIND_ONE
);
if
(!
cursor
.
hasNext
())
return
null
;
return
cursor
.
next
();
}
public
static
Account
getAccountByPlayerId
(
int
playerId
)
{
MorphiaCursor
<
Account
>
cursor
=
DatabaseManager
.
getDatastore
().
createQuery
(
Account
.
class
).
field
(
"playerId"
).
equal
(
playerId
).
find
(
FIND_ONE
);
MorphiaCursor
<
Account
>
cursor
=
DatabaseManager
.
get
Account
Datastore
().
createQuery
(
Account
.
class
).
field
(
"playerId"
).
equal
(
playerId
).
find
(
FIND_ONE
);
if
(!
cursor
.
hasNext
())
return
null
;
return
cursor
.
next
();
}
public
static
boolean
deleteAccount
(
String
username
)
{
Query
<
Account
>
q
=
DatabaseManager
.
getDatastore
().
createQuery
(
Account
.
class
).
field
(
"username"
).
equalIgnoreCase
(
username
);
Query
<
Account
>
q
=
DatabaseManager
.
get
Account
Datastore
().
createQuery
(
Account
.
class
).
field
(
"username"
).
equalIgnoreCase
(
username
);
return
DatabaseManager
.
getDatastore
().
findAndDelete
(
q
)
!=
null
;
}
...
...
src/main/java/emu/grasscutter/database/DatabaseManager.java
View file @
e6402c31
...
...
@@ -17,7 +17,10 @@ import emu.grasscutter.game.inventory.GenshinItem;
public
final
class
DatabaseManager
{
private
static
MongoClient
mongoClient
;
private
static
MongoClient
dispatchMongoClient
;
private
static
Datastore
datastore
;
private
static
Datastore
dispatchDatastore
;
private
static
final
Class
<?>[]
mappedClasses
=
new
Class
<?>[]
{
DatabaseCounter
.
class
,
Account
.
class
,
GenshinPlayer
.
class
,
GenshinAvatar
.
class
,
GenshinItem
.
class
,
Friendship
.
class
...
...
@@ -35,6 +38,16 @@ public final class DatabaseManager {
return
getDatastore
().
getDatabase
();
}
// Yes. I very dislike this method. However, this will be good for now.
// TODO: Add dispatch routes for player account management
public
static
Datastore
getAccountDatastore
()
{
if
(
Grasscutter
.
getConfig
().
RunMode
.
equalsIgnoreCase
(
"GAME_ONLY"
))
{
return
dispatchDatastore
;
}
else
{
return
datastore
;
}
}
public
static
void
initialize
()
{
// Initialize
mongoClient
=
new
MongoClient
(
new
MongoClientURI
(
Grasscutter
.
getConfig
().
DatabaseUrl
));
...
...
@@ -67,6 +80,28 @@ public final class DatabaseManager {
datastore
.
ensureIndexes
();
}
}
if
(
Grasscutter
.
getConfig
().
RunMode
.
equalsIgnoreCase
(
"GAME_ONLY"
))
{
dispatchMongoClient
=
new
MongoClient
(
new
MongoClientURI
(
Grasscutter
.
getConfig
().
getGameServerOptions
().
DispatchServerDatabaseUrl
));
dispatchDatastore
=
morphia
.
createDatastore
(
dispatchMongoClient
,
Grasscutter
.
getConfig
().
getGameServerOptions
().
DispatchServerDatabaseCollection
);
// Ensure indexes for dispatch server
try
{
dispatchDatastore
.
ensureIndexes
();
}
catch
(
MongoCommandException
e
)
{
Grasscutter
.
getLogger
().
info
(
"Mongo index error: "
,
e
);
// Duplicate index error
if
(
e
.
getCode
()
==
85
)
{
// Drop all indexes and re add them
MongoIterable
<
String
>
collections
=
dispatchDatastore
.
getDatabase
().
listCollectionNames
();
for
(
String
name
:
collections
)
{
dispatchDatastore
.
getDatabase
().
getCollection
(
name
).
dropIndexes
();
}
// Add back indexes
dispatchDatastore
.
ensureIndexes
();
}
}
}
}
public
static
synchronized
int
getNextId
(
Class
<?>
c
)
{
...
...
src/main/java/emu/grasscutter/game/Account.java
View file @
e6402c31
package
emu.grasscutter.game
;
import
dev.morphia.annotations.AlsoLoad
;
import
dev.morphia.annotations.Collation
;
import
dev.morphia.annotations.Entity
;
import
dev.morphia.annotations.Id
;
...
...
@@ -24,7 +25,7 @@ public class Account {
private
String
username
;
private
String
password
;
// Unused for now
private
int
playerId
;
@AlsoLoad
(
"playerUid"
)
private
int
playerId
;
private
String
email
;
private
String
token
;
...
...
@@ -68,7 +69,7 @@ public class Account {
this
.
token
=
token
;
}
public
int
getPlayer
I
d
()
{
public
int
getPlayer
Ui
d
()
{
return
this
.
playerId
;
}
...
...
@@ -106,6 +107,10 @@ public class Account {
this
.
permissions
.
add
(
permission
);
return
true
;
}
public
boolean
hasPermission
(
String
permission
)
{
return
this
.
permissions
.
contains
(
permission
)
||
this
.
permissions
.
contains
(
"*"
)
?
true
:
false
;
}
public
boolean
removePermission
(
String
permission
)
{
return
this
.
permissions
.
remove
(
permission
);
}
...
...
src/main/java/emu/grasscutter/game/GenshinPlayer.java
View file @
e6402c31
...
...
@@ -31,6 +31,7 @@ import emu.grasscutter.net.proto.OnlinePlayerInfoOuterClass.OnlinePlayerInfo;
import
emu.grasscutter.net.proto.PlayerApplyEnterMpReasonOuterClass.PlayerApplyEnterMpReason
;
import
emu.grasscutter.net.proto.PlayerLocationInfoOuterClass.PlayerLocationInfo
;
import
emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail
;
import
emu.grasscutter.net.proto.WorldPlayerLocationInfoOuterClass.WorldPlayerLocationInfo
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketAbilityInvocationsNotify
;
...
...
@@ -38,6 +39,7 @@ import emu.grasscutter.server.packet.send.PacketAvatarAddNotify;
import
emu.grasscutter.server.packet.send.PacketAvatarDataNotify
;
import
emu.grasscutter.server.packet.send.PacketAvatarGainCostumeNotify
;
import
emu.grasscutter.server.packet.send.PacketAvatarGainFlycloakNotify
;
import
emu.grasscutter.server.packet.send.PacketClientAbilityInitFinishNotify
;
import
emu.grasscutter.server.packet.send.PacketCombatInvocationsNotify
;
import
emu.grasscutter.server.packet.send.PacketGadgetInteractRsp
;
import
emu.grasscutter.server.packet.send.PacketItemAddHintNotify
;
...
...
@@ -48,9 +50,11 @@ import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify;
import
emu.grasscutter.server.packet.send.PacketPlayerPropNotify
;
import
emu.grasscutter.server.packet.send.PacketPlayerStoreNotify
;
import
emu.grasscutter.server.packet.send.PacketPrivateChatNotify
;
import
emu.grasscutter.server.packet.send.PacketScenePlayerLocationNotify
;
import
emu.grasscutter.server.packet.send.PacketSetNameCardRsp
;
import
emu.grasscutter.server.packet.send.PacketStoreWeightLimitNotify
;
import
emu.grasscutter.server.packet.send.PacketUnlockNameCardNotify
;
import
emu.grasscutter.server.packet.send.PacketWorldPlayerLocationNotify
;
import
emu.grasscutter.server.packet.send.PacketWorldPlayerRTTNotify
;
import
emu.grasscutter.utils.Position
;
...
...
@@ -100,10 +104,12 @@ public class GenshinPlayer {
@Transient
private
int
enterSceneToken
;
@Transient
private
SceneLoadState
sceneState
;
@Transient
private
boolean
hasSentAvatarDataNotify
;
@Transient
private
long
nextSendPlayerLocTime
=
0
;
@Transient
private
final
Int2ObjectMap
<
CoopRequest
>
coopRequests
;
@Transient
private
final
InvokeHandler
<
CombatInvokeEntry
>
combatInvokeHandler
;
@Transient
private
final
InvokeHandler
<
AbilityInvokeEntry
>
abilityInvokeHandler
;
@Transient
private
final
InvokeHandler
<
AbilityInvokeEntry
>
clientAbilityInitFinishHandler
;
@Deprecated
@SuppressWarnings
({
"rawtypes"
,
"unchecked"
})
// Morphia only!
public
GenshinPlayer
()
{
...
...
@@ -119,6 +125,12 @@ public class GenshinPlayer {
}
this
.
properties
.
put
(
prop
.
getId
(),
0
);
}
this
.
gachaInfo
=
new
PlayerGachaInfo
();
this
.
nameCardList
=
new
HashSet
<>();
this
.
flyCloakList
=
new
HashSet
<>();
this
.
costumeList
=
new
HashSet
<>();
this
.
setSceneId
(
3
);
this
.
setRegionId
(
1
);
this
.
sceneState
=
SceneLoadState
.
NONE
;
...
...
@@ -126,6 +138,7 @@ public class GenshinPlayer {
this
.
coopRequests
=
new
Int2ObjectOpenHashMap
<>();
this
.
combatInvokeHandler
=
new
InvokeHandler
(
PacketCombatInvocationsNotify
.
class
);
this
.
abilityInvokeHandler
=
new
InvokeHandler
(
PacketAbilityInvocationsNotify
.
class
);
this
.
clientAbilityInitFinishHandler
=
new
InvokeHandler
(
PacketClientAbilityInitFinishNotify
.
class
);
}
// On player creation
...
...
@@ -137,11 +150,6 @@ public class GenshinPlayer {
this
.
nickname
=
"Traveler"
;
this
.
signature
=
""
;
this
.
teamManager
=
new
TeamManager
(
this
);
this
.
gachaInfo
=
new
PlayerGachaInfo
();
this
.
playerProfile
=
new
PlayerProfile
(
this
);
this
.
nameCardList
=
new
HashSet
<>();
this
.
flyCloakList
=
new
HashSet
<>();
this
.
costumeList
=
new
HashSet
<>();
this
.
setProperty
(
PlayerProperty
.
PROP_PLAYER_LEVEL
,
1
);
this
.
setProperty
(
PlayerProperty
.
PROP_IS_SPRING_AUTO_USE
,
1
);
this
.
setProperty
(
PlayerProperty
.
PROP_SPRING_AUTO_USE_PERCENT
,
50
);
...
...
@@ -285,7 +293,7 @@ public class GenshinPlayer {
}
private
float
getExpModifier
()
{
return
Grasscutter
.
getConfig
().
getGameRates
().
ADVENTURE_EXP_RATE
;
return
Grasscutter
.
getConfig
().
getGameServerOptions
().
getGameRates
().
ADVENTURE_EXP_RATE
;
}
// Affected by exp rate
...
...
@@ -344,7 +352,6 @@ public class GenshinPlayer {
public
PlayerProfile
getProfile
()
{
if
(
this
.
playerProfile
==
null
)
{
this
.
playerProfile
=
new
PlayerProfile
(
this
);
this
.
save
();
}
return
playerProfile
;
}
...
...
@@ -389,6 +396,10 @@ public class GenshinPlayer {
return
this
.
abilityInvokeHandler
;
}
public
InvokeHandler
<
AbilityInvokeEntry
>
getClientAbilityInitFinishHandler
()
{
return
clientAbilityInitFinishHandler
;
}
public
void
setMpSetting
(
MpSettingType
mpSetting
)
{
this
.
mpSetting
=
mpSetting
;
}
...
...
@@ -647,6 +658,13 @@ public class GenshinPlayer {
return
social
;
}
public
WorldPlayerLocationInfo
getWorldPlayerLocationInfo
()
{
return
WorldPlayerLocationInfo
.
newBuilder
()
.
setSceneId
(
this
.
getSceneId
())
.
setPlayerLoc
(
this
.
getPlayerLocationInfo
())
.
build
();
}
public
PlayerLocationInfo
getPlayerLocationInfo
()
{
return
PlayerLocationInfo
.
newBuilder
()
.
setUid
(
this
.
getUid
())
...
...
@@ -672,10 +690,23 @@ public class GenshinPlayer {
}
// Ping
if
(
this
.
getWorld
()
!=
null
)
{
this
.
sendPacket
(
new
PacketWorldPlayerRTTNotify
(
this
.
getWorld
()));
// Player ping
// RTT notify - very important to send this often
this
.
sendPacket
(
new
PacketWorldPlayerRTTNotify
(
this
.
getWorld
()));
// Update player locations if in multiplayer every 5 seconds
long
time
=
System
.
currentTimeMillis
();
if
(
this
.
getWorld
().
isMultiplayer
()
&&
this
.
getScene
()
!=
null
&&
time
>
nextSendPlayerLocTime
)
{
this
.
sendPacket
(
new
PacketWorldPlayerLocationNotify
(
this
.
getWorld
()));
this
.
sendPacket
(
new
PacketScenePlayerLocationNotify
(
this
.
getScene
()));
this
.
resetSendPlayerLocTime
();
}
}
}
public
void
resetSendPlayerLocTime
()
{
this
.
nextSendPlayerLocTime
=
System
.
currentTimeMillis
()
+
5000
;
}
@PostLoad
private
void
onLoad
()
{
this
.
getTeamManager
().
setPlayer
(
this
);
...
...
@@ -689,12 +720,8 @@ public class GenshinPlayer {
// Make sure these exist
if
(
this
.
getTeamManager
()
==
null
)
{
this
.
teamManager
=
new
TeamManager
(
this
);
}
if
(
this
.
getGachaInfo
()
==
null
)
{
this
.
gachaInfo
=
new
PlayerGachaInfo
();
}
if
(
this
.
nameCardList
==
null
)
{
this
.
nameCardList
=
new
HashSet
<>();
}
if
(
this
.
costumeList
==
null
)
{
this
.
costumeList
=
new
HashSet
<>();
}
if
(
this
.
getProfile
().
getUid
()
==
0
)
{
this
.
getProfile
().
syncWithCharacter
(
this
);
}
// Check if player object exists in server
...
...
src/main/java/emu/grasscutter/game/GenshinScene.java
View file @
e6402c31
...
...
@@ -34,6 +34,7 @@ public class GenshinScene {
private
int
time
;
private
ClimateType
climate
;
private
int
weather
;
public
GenshinScene
(
World
world
,
SceneData
sceneData
)
{
this
.
world
=
world
;
...
...
@@ -89,10 +90,18 @@ public class GenshinScene {
return
climate
;
}
public
int
getWeather
()
{
return
weather
;
}
public
void
setClimate
(
ClimateType
climate
)
{
this
.
climate
=
climate
;
}
public
void
setWeather
(
int
weather
)
{
this
.
weather
=
weather
;
}
public
boolean
isInScene
(
GenshinEntity
entity
)
{
return
this
.
entities
.
containsKey
(
entity
.
getId
());
}
...
...
src/main/java/emu/grasscutter/game/TeamInfo.java
View file @
e6402c31
...
...
@@ -13,7 +13,7 @@ public class TeamInfo {
public
TeamInfo
()
{
this
.
name
=
""
;
this
.
avatars
=
new
ArrayList
<>(
Grasscutter
.
getConfig
().
getServerOptions
().
MaxAvatarsInTeam
);
this
.
avatars
=
new
ArrayList
<>(
Grasscutter
.
getConfig
().
get
Game
ServerOptions
().
MaxAvatarsInTeam
);
}
public
String
getName
()
{
...
...
@@ -37,7 +37,7 @@ public class TeamInfo {
}
public
boolean
addAvatar
(
GenshinAvatar
avatar
)
{
if
(
size
()
>=
Grasscutter
.
getConfig
().
getServerOptions
().
MaxAvatarsInTeam
||
contains
(
avatar
))
{
if
(
size
()
>=
Grasscutter
.
getConfig
().
get
Game
ServerOptions
().
MaxAvatarsInTeam
||
contains
(
avatar
))
{
return
false
;
}
...
...
@@ -57,7 +57,7 @@ public class TeamInfo {
}
public
void
copyFrom
(
TeamInfo
team
)
{
copyFrom
(
team
,
Grasscutter
.
getConfig
().
getServerOptions
().
MaxAvatarsInTeam
);
copyFrom
(
team
,
Grasscutter
.
getConfig
().
get
Game
ServerOptions
().
MaxAvatarsInTeam
);
}
public
void
copyFrom
(
TeamInfo
team
,
int
maxTeamSize
)
{
...
...
src/main/java/emu/grasscutter/game/TeamManager.java
View file @
e6402c31
...
...
@@ -164,13 +164,13 @@ public class TeamManager {
public
int
getMaxTeamSize
()
{
if
(
getPlayer
().
isInMultiplayer
())
{
int
max
=
Grasscutter
.
getConfig
().
getServerOptions
().
MaxAvatarsInTeamMultiplayer
;
int
max
=
Grasscutter
.
getConfig
().
get
Game
ServerOptions
().
MaxAvatarsInTeamMultiplayer
;
if
(
getPlayer
().
getWorld
().
getHost
()
==
this
.
getPlayer
())
{
return
Math
.
max
(
1
,
(
int
)
Math
.
ceil
(
max
/
(
double
)
getWorld
().
getPlayerCount
()));
}
return
Math
.
max
(
1
,
(
int
)
Math
.
floor
(
max
/
(
double
)
getWorld
().
getPlayerCount
()));
}
return
Grasscutter
.
getConfig
().
getServerOptions
().
MaxAvatarsInTeam
;
return
Grasscutter
.
getConfig
().
get
Game
ServerOptions
().
MaxAvatarsInTeam
;
}
// Methods
...
...
src/main/java/emu/grasscutter/game/World.java
View file @
e6402c31
...
...
@@ -208,11 +208,14 @@ public class World implements Iterable<GenshinPlayer> {
}
public
boolean
transferPlayerToScene
(
GenshinPlayer
player
,
int
sceneId
,
Position
pos
)
{
if
(
player
.
getScene
().
getId
()
==
sceneId
||
GenshinData
.
getSceneDataMap
().
get
(
sceneId
)
==
null
)
{
if
(
GenshinData
.
getSceneDataMap
().
get
(
sceneId
)
==
null
)
{
return
false
;
}
Integer
oldSceneId
=
null
;
if
(
player
.
getScene
()
!=
null
)
{
oldSceneId
=
player
.
getScene
().
getId
();
player
.
getScene
().
removePlayer
(
player
);
}
...
...
@@ -221,7 +224,11 @@ public class World implements Iterable<GenshinPlayer> {
player
.
getPos
().
set
(
pos
);
// Teleport packet
player
.
sendPacket
(
new
PacketPlayerEnterSceneNotify
(
player
,
EnterType
.
EnterSelf
,
EnterReason
.
TransPoint
,
sceneId
,
pos
));
if
(
oldSceneId
.
equals
(
sceneId
))
{
player
.
sendPacket
(
new
PacketPlayerEnterSceneNotify
(
player
,
EnterType
.
EnterGoto
,
EnterReason
.
TransPoint
,
sceneId
,
pos
));
}
else
{
player
.
sendPacket
(
new
PacketPlayerEnterSceneNotify
(
player
,
EnterType
.
EnterJump
,
EnterReason
.
TransPoint
,
sceneId
,
pos
));
}
return
true
;
}
...
...
Prev
1
2
3
4
5
6
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