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
058d3222
Commit
058d3222
authored
Apr 19, 2022
by
Benjamin Elsdon
Browse files
Merge remote-tracking branch 'upstream/main'
parents
dfc956a1
2572d55c
Changes
66
Show whitespace changes
Inline
Side-by-side
run.bat
0 → 100644
View file @
058d3222
@echo
off
::This will not work if your java is in a different location, plugin as necessary
::this just saves you from changing your PATH
"C:\Program Files\Java\jdk1.8.0_202\bin\java.exe"
-jar
./grasscutter.jar
\ No newline at end of file
src/main/java/emu/grasscutter/Config.java
View file @
058d3222
...
...
@@ -43,6 +43,13 @@ public final class Config {
}
public
static
class
ServerOptions
{
public
int
InventoryLimitWeapon
=
2000
;
public
int
InventoryLimitRelic
=
2000
;
public
int
InventoryLimitMaterial
=
2000
;
public
int
InventoryLimitFurniture
=
2000
;
public
int
InventoryLimitAll
=
30000
;
public
int
MaxAvatarsInTeam
=
4
;
public
int
MaxAvatarsInTeamMultiplayer
=
4
;
public
int
MaxEntityLimit
=
1000
;
// Max entity limit per world. // TODO: Enforce later.
public
int
[]
WelcomeEmotes
=
{
2007
,
1002
,
4010
};
public
String
WelcomeMotd
=
"Welcome to Grasscutter emu"
;
...
...
src/main/java/emu/grasscutter/GenshinConstants.java
View file @
058d3222
...
...
@@ -9,14 +9,6 @@ public final class GenshinConstants {
public
static
String
VERSION
=
"2.6.0"
;
public
static
final
int
MAX_TEAMS
=
4
;
public
static
final
int
MAX_AVATARS_IN_TEAM
=
4
;
public
static
final
int
LIMIT_WEAPON
=
2000
;
public
static
final
int
LIMIT_RELIC
=
2000
;
public
static
final
int
LIMIT_MATERIAL
=
2000
;
public
static
final
int
LIMIT_FURNITURE
=
2000
;
public
static
final
int
LIMIT_ALL
=
30000
;
public
static
final
int
MAIN_CHARACTER_MALE
=
10000005
;
public
static
final
int
MAIN_CHARACTER_FEMALE
=
10000007
;
public
static
final
Position
START_POSITION
=
new
Position
(
2747
,
194
,
-
1719
);
...
...
src/main/java/emu/grasscutter/Grasscutter.java
View file @
058d3222
...
...
@@ -42,6 +42,7 @@ public final class Grasscutter {
// Load server configuration.
Grasscutter
.
loadConfig
();
// Check server structure.
Utils
.
startupCheck
();
}
...
...
src/main/java/emu/grasscutter/commands/PlayerCommands.java
View file @
058d3222
...
...
@@ -7,6 +7,7 @@ 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
;
...
...
@@ -54,8 +55,9 @@ public final class PlayerCommands {
case
2
:
try
{
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
if
(
Grasscutter
.
getGameServer
().
getPlayerById
(
target
)
==
null
)
{
target
=
player
.
getId
();
amount
=
Integer
.
parseInt
(
args
.
get
(
1
));
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
));
...
...
@@ -69,7 +71,8 @@ public final class PlayerCommands {
case
3
:
try
{
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
if
(
Grasscutter
.
getGameServer
().
getPlayerById
(
target
)
==
null
)
{
if
(
Grasscutter
.
getGameServer
().
getPlayerByUid
(
target
)
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid player ID."
);
return
;
}
...
...
@@ -83,7 +86,8 @@ public final class PlayerCommands {
break
;
}
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerById
(
target
);
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerByUid
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Player not found."
);
return
;
}
...
...
@@ -110,7 +114,8 @@ public final class PlayerCommands {
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
);
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerByUid
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Player not found."
);
return
;
}
...
...
@@ -167,12 +172,12 @@ public final class PlayerCommands {
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
.
get
World
(),
player
,
itemData
,
pos
,
1
);
player
.
get
World
().
addEntity
(
entity
);
EntityItem
entity
=
new
EntityItem
(
player
.
get
Scene
(),
player
,
itemData
,
pos
,
1
);
player
.
get
Scene
().
addEntity
(
entity
);
}
}
else
{
EntityItem
entity
=
new
EntityItem
(
player
.
get
World
(),
player
,
itemData
,
player
.
getPos
().
clone
().
addY
(
3
f
),
amount
);
player
.
get
World
().
addEntity
(
entity
);
EntityItem
entity
=
new
EntityItem
(
player
.
get
Scene
(),
player
,
itemData
,
player
.
getPos
().
clone
().
addY
(
3
f
),
amount
);
player
.
get
Scene
().
addEntity
(
entity
);
}
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid item or player ID."
);
...
...
@@ -208,8 +213,8 @@ public final class PlayerCommands {
case
2
:
try
{
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
if
(
Grasscutter
.
getGameServer
().
getPlayerBy
I
d
(
target
)
==
null
)
{
target
=
player
.
get
I
d
();
level
=
Integer
.
parseInt
(
args
.
get
(
1
));
if
(
Grasscutter
.
getGameServer
().
getPlayerBy
Ui
d
(
target
)
==
null
)
{
target
=
player
.
get
Ui
d
();
level
=
Integer
.
parseInt
(
args
.
get
(
1
));
avatarID
=
Integer
.
parseInt
(
args
.
get
(
0
));
}
else
{
avatarID
=
Integer
.
parseInt
(
args
.
get
(
1
));
...
...
@@ -223,7 +228,7 @@ public final class PlayerCommands {
case
3
:
try
{
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
if
(
Grasscutter
.
getGameServer
().
getPlayerBy
I
d
(
target
)
==
null
)
{
if
(
Grasscutter
.
getGameServer
().
getPlayerBy
Ui
d
(
target
)
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Invalid player ID."
);
return
;
}
...
...
@@ -237,7 +242,7 @@ public final class PlayerCommands {
break
;
}
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerBy
I
d
(
target
);
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerBy
Ui
d
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Player not found."
);
return
;
}
...
...
@@ -277,7 +282,7 @@ public final class PlayerCommands {
int
level
=
1
;
if
(
args
.
size
()
>
2
)
level
=
Integer
.
parseInt
(
args
.
get
(
2
));
int
ascension
=
1
;
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerBy
I
d
(
target
);
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerBy
Ui
d
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Player not found."
);
return
;
}
...
...
@@ -332,8 +337,8 @@ public final class PlayerCommands {
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
.
get
World
(),
entityData
,
pos
,
level
);
player
.
get
World
().
addEntity
(
monster
);
EntityMonster
monster
=
new
EntityMonster
(
player
.
get
Scene
(),
entityData
,
pos
,
level
);
player
.
get
Scene
().
addEntity
(
monster
);
}
}
catch
(
NumberFormatException
ignored
)
{
CommandHandler
.
sendMessage
(
null
,
"Invalid item or player ID."
);
...
...
@@ -342,29 +347,46 @@ public final class PlayerCommands {
}
@Command
(
label
=
"killall"
,
usage
=
"killall [sceneId]"
,
description
=
"Kill all entities"
,
permission
=
"server.killall"
)
usage
=
"killall
[playerUid]
[sceneId]"
,
description
=
"Kill all entities"
,
permission
=
"server.killall"
)
public
static
class
KillAllCommand
implements
CommandHandler
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
World
world
=
player
.
get
World
();
world
.
getEntities
().
values
().
stream
()
GenshinScene
scene
=
player
.
get
Scene
();
scene
.
getEntities
().
values
().
stream
()
.
filter
(
entity
->
entity
instanceof
EntityMonster
)
.
forEach
(
entity
->
world
.
killEntity
(
entity
,
0
));
.
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
()
<
1
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: killall [sceneId]"
);
return
;
if
(
args
.
size
()
<
2
)
{
CommandHandler
.
sendMessage
(
null
,
"Usage: killall
[playerUid]
[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.
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
scene id
."
);
CommandHandler
.
sendMessage
(
null
,
"Invalid
arguments
."
);
}
}
}
...
...
@@ -464,7 +486,6 @@ public final class PlayerCommands {
usage
=
"clearartifacts"
,
execution
=
Command
.
Execution
.
PLAYER
,
permission
=
"player.clearartifacts"
,
description
=
"Deletes all unequipped and unlocked level 0 artifacts, including yellow rarity ones from your inventory"
)
public
static
class
ClearArtifactsCommand
implements
CommandHandler
{
@Override
public
void
execute
(
GenshinPlayer
player
,
List
<
String
>
args
)
{
Inventory
playerInventory
=
player
.
getInventory
();
...
...
@@ -476,6 +497,31 @@ public final class PlayerCommands {
}
}
@Command
(
label
=
"changescene"
,
aliases
=
{
"scene"
},
usage
=
"changescene <scene id>"
,
description
=
"Changes your scene"
,
permission
=
"player.changescene"
,
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
(
null
,
"Usage: changescene <scene id>"
);
return
;
}
int
sceneId
=
0
;
try
{
sceneId
=
Integer
.
parseInt
(
args
.
get
(
0
));
}
catch
(
Exception
e
)
{
return
;
}
boolean
result
=
player
.
getWorld
().
transferPlayerToScene
(
player
,
sceneId
,
player
.
getPos
());
if
(!
result
)
{
CommandHandler
.
sendMessage
(
null
,
"Scene does not exist or you are already in it"
);
}
}
}
@Command
(
label
=
"sendservermessage"
,
aliases
=
{
"sendservmsg"
},
usage
=
"sendservermessage <player> <message>"
,
description
=
"Sends a message to a player as the server"
,
execution
=
Command
.
Execution
.
PLAYER
,
permission
=
"server.sendmessage"
)
...
...
@@ -490,7 +536,7 @@ public final class PlayerCommands {
int
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
String
message
=
String
.
join
(
" "
,
args
.
subList
(
1
,
args
.
size
()));
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerBy
I
d
(
target
);
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerBy
Ui
d
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Player not found."
);
return
;
}
...
...
src/main/java/emu/grasscutter/commands/ServerCommands.java
View file @
058d3222
...
...
@@ -114,7 +114,8 @@ public final class ServerCommands {
int
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
String
message
=
String
.
join
(
" "
,
args
.
subList
(
1
,
args
.
size
()));
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerById
(
target
);
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerByUid
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
null
,
"Player not found."
);
return
;
}
...
...
@@ -136,7 +137,8 @@ public final class ServerCommands {
int
target
=
Integer
.
parseInt
(
args
.
get
(
0
));
String
message
=
String
.
join
(
" "
,
args
.
subList
(
1
,
args
.
size
()));
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerById
(
target
);
GenshinPlayer
targetPlayer
=
Grasscutter
.
getGameServer
().
getPlayerByUid
(
target
);
if
(
targetPlayer
==
null
)
{
CommandHandler
.
sendMessage
(
player
,
"Player not found."
);
return
;
}
...
...
src/main/java/emu/grasscutter/data/GenshinData.java
View file @
058d3222
...
...
@@ -51,6 +51,8 @@ public class GenshinData {
private
static
final
Int2ObjectMap
<
AvatarCostumeData
>
avatarCostumeDataMap
=
new
Int2ObjectLinkedOpenHashMap
<>();
private
static
final
Int2ObjectMap
<
AvatarCostumeData
>
avatarCostumeDataItemIdMap
=
new
Int2ObjectLinkedOpenHashMap
<>();
private
static
final
Int2ObjectMap
<
SceneData
>
sceneDataMap
=
new
Int2ObjectLinkedOpenHashMap
<>();
public
static
Int2ObjectMap
<?>
getMapByResourceDef
(
Class
<?>
resourceDefinition
)
{
Int2ObjectMap
<?>
map
=
null
;
...
...
@@ -209,4 +211,8 @@ public class GenshinData {
public
static
Int2ObjectMap
<
AvatarCostumeData
>
getAvatarCostumeDataItemIdMap
()
{
return
avatarCostumeDataItemIdMap
;
}
public
static
Int2ObjectMap
<
SceneData
>
getSceneDataMap
()
{
return
sceneDataMap
;
}
}
src/main/java/emu/grasscutter/data/def/ItemData.java
View file @
058d3222
...
...
@@ -48,6 +48,7 @@ public class ItemData extends GenshinResource {
private
int
WeaponBaseExp
;
private
int
StoryId
;
private
int
AvatarPromoteId
;
private
int
AwakenMaterial
;
private
int
[]
AwakenCosts
;
private
int
[]
SkillAffix
;
private
WeaponProperty
[]
WeaponProp
;
...
...
@@ -160,6 +161,10 @@ public class ItemData extends GenshinResource {
return
WeaponBaseExp
;
}
public
int
getAwakenMaterial
()
{
return
AwakenMaterial
;
}
public
int
[]
getAwakenCosts
()
{
return
AwakenCosts
;
}
...
...
src/main/java/emu/grasscutter/data/def/SceneData.java
0 → 100644
View file @
058d3222
package
emu.grasscutter.data.def
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.GenshinResource
;
import
emu.grasscutter.data.ResourceType
;
import
emu.grasscutter.game.props.SceneType
;
@ResourceType
(
name
=
"SceneExcelConfigData.json"
)
public
class
SceneData
extends
GenshinResource
{
private
int
Id
;
private
SceneType
SceneType
;
private
String
ScriptData
;
@Override
public
int
getId
()
{
return
this
.
Id
;
}
public
SceneType
getSceneType
()
{
return
SceneType
;
}
public
String
getScriptData
()
{
return
ScriptData
;
}
@Override
public
void
onLoad
()
{
}
}
src/main/java/emu/grasscutter/database/DatabaseHelper.java
View file @
058d3222
...
...
@@ -124,13 +124,13 @@ public class DatabaseHelper {
int
id
=
0
;
if
(
reservedId
>
0
&&
!
checkPlayerExists
(
reservedId
))
{
id
=
reservedId
;
character
.
set
I
d
(
id
);
character
.
set
Ui
d
(
id
);
}
else
{
do
{
id
=
DatabaseManager
.
getNextId
(
character
);
}
while
(
checkPlayerExists
(
id
));
character
.
set
I
d
(
id
);
character
.
set
Ui
d
(
id
);
}
// Save to database
DatabaseManager
.
getDatastore
().
save
(
character
);
...
...
@@ -160,7 +160,7 @@ public class DatabaseHelper {
}
public
static
List
<
GenshinAvatar
>
getAvatars
(
GenshinPlayer
player
)
{
Query
<
GenshinAvatar
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
GenshinAvatar
.
class
).
filter
(
"ownerId"
,
player
.
get
I
d
());
Query
<
GenshinAvatar
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
GenshinAvatar
.
class
).
filter
(
"ownerId"
,
player
.
get
Ui
d
());
return
query
.
find
().
toList
();
}
...
...
@@ -174,16 +174,16 @@ public class DatabaseHelper {
}
public
static
List
<
GenshinItem
>
getInventoryItems
(
GenshinPlayer
player
)
{
Query
<
GenshinItem
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
GenshinItem
.
class
).
filter
(
"ownerId"
,
player
.
get
I
d
());
Query
<
GenshinItem
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
GenshinItem
.
class
).
filter
(
"ownerId"
,
player
.
get
Ui
d
());
return
query
.
find
().
toList
();
}
public
static
List
<
Friendship
>
getFriends
(
GenshinPlayer
player
)
{
Query
<
Friendship
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
Friendship
.
class
).
filter
(
"ownerId"
,
player
.
get
I
d
());
Query
<
Friendship
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
Friendship
.
class
).
filter
(
"ownerId"
,
player
.
get
Ui
d
());
return
query
.
find
().
toList
();
}
public
static
List
<
Friendship
>
getReverseFriends
(
GenshinPlayer
player
)
{
Query
<
Friendship
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
Friendship
.
class
).
filter
(
"friendId"
,
player
.
get
I
d
());
Query
<
Friendship
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
Friendship
.
class
).
filter
(
"friendId"
,
player
.
get
Ui
d
());
return
query
.
find
().
toList
();
}
...
...
src/main/java/emu/grasscutter/game/GenshinPlayer.java
View file @
058d3222
...
...
@@ -78,6 +78,7 @@ public class GenshinPlayer {
@Transient
private
long
nextGuid
=
0
;
@Transient
private
int
peerId
;
@Transient
private
World
world
;
@Transient
private
GenshinScene
scene
;
@Transient
private
GameSession
session
;
@Transient
private
AvatarStorage
avatars
;
@Transient
private
Inventory
inventory
;
...
...
@@ -155,17 +156,17 @@ public class GenshinPlayer {
this
.
getRotation
().
set
(
0
,
307
,
0
);
}
public
int
get
I
d
()
{
public
int
get
Ui
d
()
{
return
id
;
}
public
void
set
I
d
(
int
id
)
{
public
void
set
Ui
d
(
int
id
)
{
this
.
id
=
id
;
}
public
long
getNextGuid
()
{
public
long
getNextG
enshinG
uid
()
{
long
nextId
=
++
this
.
nextGuid
;
return
((
long
)
this
.
get
I
d
()
<<
32
)
+
nextId
;
return
((
long
)
this
.
get
Ui
d
()
<<
32
)
+
nextId
;
}
public
Account
getAccount
()
{
...
...
@@ -174,7 +175,7 @@ public class GenshinPlayer {
public
void
setAccount
(
Account
account
)
{
this
.
account
=
account
;
this
.
account
.
setPlayerId
(
get
I
d
());
this
.
account
.
setPlayerId
(
get
Ui
d
());
}
public
GameSession
getSession
()
{
...
...
@@ -201,6 +202,14 @@ public class GenshinPlayer {
this
.
world
=
world
;
}
public
GenshinScene
getScene
()
{
return
scene
;
}
public
void
setScene
(
GenshinScene
scene
)
{
this
.
scene
=
scene
;
}
public
int
getGmLevel
()
{
return
1
;
}
...
...
@@ -551,7 +560,7 @@ public class GenshinPlayer {
}
public
void
dropMessage
(
Object
message
)
{
this
.
sendPacket
(
new
PacketPrivateChatNotify
(
GenshinConstants
.
SERVER_CONSOLE_UID
,
get
I
d
(),
message
.
toString
()));
this
.
sendPacket
(
new
PacketPrivateChatNotify
(
GenshinConstants
.
SERVER_CONSOLE_UID
,
get
Ui
d
(),
message
.
toString
()));
}
/**
...
...
@@ -560,18 +569,18 @@ public class GenshinPlayer {
* @param message The message to send.
*/
public
void
sendMessage
(
GenshinPlayer
sender
,
Object
message
)
{
this
.
sendPacket
(
new
PacketPrivateChatNotify
(
sender
.
get
I
d
(),
this
.
get
I
d
(),
message
.
toString
()));
this
.
sendPacket
(
new
PacketPrivateChatNotify
(
sender
.
get
Ui
d
(),
this
.
get
Ui
d
(),
message
.
toString
()));
}
public
void
interactWith
(
int
gadgetEntityId
)
{
GenshinEntity
entity
=
get
World
().
getEntityById
(
gadgetEntityId
);
GenshinEntity
entity
=
get
Scene
().
getEntityById
(
gadgetEntityId
);
if
(
entity
==
null
)
{
return
;
}
// Delete
entity
.
get
World
().
removeEntity
(
entity
);
entity
.
get
Scene
().
removeEntity
(
entity
);
// Handle
if
(
entity
instanceof
EntityItem
)
{
...
...
@@ -605,7 +614,7 @@ public class GenshinPlayer {
public
OnlinePlayerInfo
getOnlinePlayerInfo
()
{
OnlinePlayerInfo
.
Builder
onlineInfo
=
OnlinePlayerInfo
.
newBuilder
()
.
setUid
(
this
.
get
I
d
())
.
setUid
(
this
.
get
Ui
d
())
.
setNickname
(
this
.
getNickname
())
.
setPlayerLevel
(
this
.
getLevel
())
.
setMpSettingType
(
this
.
getMpSetting
())
...
...
@@ -624,7 +633,7 @@ public class GenshinPlayer {
public
SocialDetail
.
Builder
getSocialDetail
()
{
SocialDetail
.
Builder
social
=
SocialDetail
.
newBuilder
()
.
setUid
(
this
.
get
I
d
())
.
setUid
(
this
.
get
Ui
d
())
.
setAvatar
(
HeadImage
.
newBuilder
().
setAvatarId
(
this
.
getHeadImage
()))
.
setNickname
(
this
.
getNickname
())
.
setSignature
(
this
.
getSignature
())
...
...
@@ -640,7 +649,7 @@ public class GenshinPlayer {
public
PlayerLocationInfo
getPlayerLocationInfo
()
{
return
PlayerLocationInfo
.
newBuilder
()
.
setUid
(
this
.
get
I
d
())
.
setUid
(
this
.
get
Ui
d
())
.
setPos
(
this
.
getPos
().
toProto
())
.
setRot
(
this
.
getRotation
().
toProto
())
.
build
();
...
...
@@ -690,7 +699,7 @@ public class GenshinPlayer {
// Check if player object exists in server
// TODO - optimize
GenshinPlayer
exists
=
this
.
getServer
().
getPlayerBy
I
d
(
get
I
d
());
GenshinPlayer
exists
=
this
.
getServer
().
getPlayerBy
Ui
d
(
get
Ui
d
());
if
(
exists
!=
null
)
{
exists
.
getSession
().
close
();
}
...
...
src/main/java/emu/grasscutter/game/GenshinScene.java
0 → 100644
View file @
058d3222
package
emu.grasscutter.game
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.Iterator
;
import
java.util.LinkedList
;
import
java.util.List
;
import
emu.grasscutter.data.def.SceneData
;
import
emu.grasscutter.game.entity.EntityAvatar
;
import
emu.grasscutter.game.entity.EntityClientGadget
;
import
emu.grasscutter.game.entity.EntityGadget
;
import
emu.grasscutter.game.entity.GenshinEntity
;
import
emu.grasscutter.game.props.ClimateType
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.game.props.SceneType
;
import
emu.grasscutter.net.packet.GenshinPacket
;
import
emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult
;
import
emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify
;
import
emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify
;
import
emu.grasscutter.server.packet.send.PacketSceneEntityDisappearNotify
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
public
class
GenshinScene
{
private
final
World
world
;
private
final
SceneData
sceneData
;
private
final
List
<
GenshinPlayer
>
players
;
private
final
Int2ObjectMap
<
GenshinEntity
>
entities
;
private
int
time
;
private
ClimateType
climate
;
public
GenshinScene
(
World
world
,
SceneData
sceneData
)
{
this
.
world
=
world
;
this
.
sceneData
=
sceneData
;
this
.
players
=
Collections
.
synchronizedList
(
new
ArrayList
<>());
this
.
entities
=
new
Int2ObjectOpenHashMap
<>();
this
.
time
=
8
*
60
;
this
.
climate
=
ClimateType
.
CLIMATE_SUNNY
;
}
public
int
getId
()
{
return
sceneData
.
getId
();
}
public
World
getWorld
()
{
return
world
;
}
public
SceneData
getSceneData
()
{
return
this
.
sceneData
;
}
public
SceneType
getSceneType
()
{
return
getSceneData
().
getSceneType
();
}
public
List
<
GenshinPlayer
>
getPlayers
()
{
return
players
;
}
public
int
getPlayerCount
()
{
return
this
.
getPlayers
().
size
();
}
public
Int2ObjectMap
<
GenshinEntity
>
getEntities
()
{
return
entities
;
}
public
GenshinEntity
getEntityById
(
int
id
)
{
return
this
.
entities
.
get
(
id
);
}
public
int
getTime
()
{
return
time
;
}
public
void
changeTime
(
int
time
)
{
this
.
time
=
time
%
1440
;
}
public
ClimateType
getClimate
()
{
return
climate
;
}
public
void
setClimate
(
ClimateType
climate
)
{
this
.
climate
=
climate
;
}
public
boolean
isInScene
(
GenshinEntity
entity
)
{
return
this
.
entities
.
containsKey
(
entity
.
getId
());
}
public
void
addPlayer
(
GenshinPlayer
player
)
{
// Check if player already in
if
(
getPlayers
().
contains
(
player
))
{
return
;
}
// Remove player from prev scene
if
(
player
.
getScene
()
!=
null
)
{
player
.
getScene
().
removePlayer
(
player
);
}
// Add
getPlayers
().
add
(
player
);
player
.
setSceneId
(
this
.
getId
());
player
.
setScene
(
this
);
this
.
setupPlayerAvatars
(
player
);
}
public
void
removePlayer
(
GenshinPlayer
player
)
{
// Remove player from scene
getPlayers
().
remove
(
player
);
player
.
setScene
(
null
);
// Remove player avatars
this
.
removePlayerAvatars
(
player
);
// Remove player gadgets
for
(
EntityGadget
gadget
:
player
.
getTeamManager
().
getGadgets
())
{
this
.
removeEntity
(
gadget
);
}
// Deregister scene if not in use
if
(
this
.
getEntities
().
size
()
<=
0
)
{
this
.
getWorld
().
deregisterScene
(
this
);
}
}
private
void
setupPlayerAvatars
(
GenshinPlayer
player
)
{
// Clear entities from old team
player
.
getTeamManager
().
getActiveTeam
().
clear
();
// Add new entities for player
TeamInfo
teamInfo
=
player
.
getTeamManager
().
getCurrentTeamInfo
();
for
(
int
avatarId
:
teamInfo
.
getAvatars
())
{
EntityAvatar
entity
=
new
EntityAvatar
(
player
.
getScene
(),
player
.
getAvatars
().
getAvatarById
(
avatarId
));
player
.
getTeamManager
().
getActiveTeam
().
add
(
entity
);
}
// Limit character index in case its out of bounds
if
(
player
.
getTeamManager
().
getCurrentCharacterIndex
()
>=
player
.
getTeamManager
().
getActiveTeam
().
size
()
||
player
.
getTeamManager
().
getCurrentCharacterIndex
()
<
0
)
{
player
.
getTeamManager
().
setCurrentCharacterIndex
(
player
.
getTeamManager
().
getCurrentCharacterIndex
()
-
1
);
}
}
private
void
removePlayerAvatars
(
GenshinPlayer
player
)
{
Iterator
<
EntityAvatar
>
it
=
player
.
getTeamManager
().
getActiveTeam
().
iterator
();
while
(
it
.
hasNext
())
{
this
.
removeEntity
(
it
.
next
(),
VisionType
.
VisionRemove
);
it
.
remove
();
}
}
public
void
spawnPlayer
(
GenshinPlayer
player
)
{
if
(
this
.
isInScene
(
player
.
getTeamManager
().
getCurrentAvatarEntity
()))
{
return
;
}
if
(
player
.
getTeamManager
().
getCurrentAvatarEntity
().
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
)
<=
0
f
)
{
player
.
getTeamManager
().
getCurrentAvatarEntity
().
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
1
f
);
}
this
.
addEntity
(
player
.
getTeamManager
().
getCurrentAvatarEntity
());
}
private
void
addEntityDirectly
(
GenshinEntity
entity
)
{
getEntities
().
put
(
entity
.
getId
(),
entity
);
}
public
synchronized
void
addEntity
(
GenshinEntity
entity
)
{
this
.
addEntityDirectly
(
entity
);
this
.
broadcastPacket
(
new
PacketSceneEntityAppearNotify
(
entity
));
}
public
synchronized
void
addEntities
(
Collection
<
GenshinEntity
>
entities
)
{
for
(
GenshinEntity
entity
:
entities
)
{
this
.
addEntityDirectly
(
entity
);
}
this
.
broadcastPacket
(
new
PacketSceneEntityAppearNotify
(
entities
,
VisionType
.
VisionBorn
));
}
private
GenshinEntity
removeEntityDirectly
(
GenshinEntity
entity
)
{
return
getEntities
().
remove
(
entity
.
getId
());
}
public
void
removeEntity
(
GenshinEntity
entity
)
{
this
.
removeEntity
(
entity
,
VisionType
.
VisionDie
);
}
public
synchronized
void
removeEntity
(
GenshinEntity
entity
,
VisionType
visionType
)
{
GenshinEntity
removed
=
this
.
removeEntityDirectly
(
entity
);
if
(
removed
!=
null
)
{
this
.
broadcastPacket
(
new
PacketSceneEntityDisappearNotify
(
removed
,
visionType
));
}
}
public
synchronized
void
replaceEntity
(
EntityAvatar
oldEntity
,
EntityAvatar
newEntity
)
{
this
.
removeEntityDirectly
(
oldEntity
);
this
.
addEntityDirectly
(
newEntity
);
this
.
broadcastPacket
(
new
PacketSceneEntityDisappearNotify
(
oldEntity
,
VisionType
.
VisionReplace
));
this
.
broadcastPacket
(
new
PacketSceneEntityAppearNotify
(
newEntity
,
VisionType
.
VisionReplace
,
oldEntity
.
getId
()));
}
public
void
showOtherEntities
(
GenshinPlayer
player
)
{
List
<
GenshinEntity
>
entities
=
new
LinkedList
<>();
GenshinEntity
currentEntity
=
player
.
getTeamManager
().
getCurrentAvatarEntity
();
for
(
GenshinEntity
entity
:
this
.
getEntities
().
values
())
{
if
(
entity
==
currentEntity
)
{
continue
;
}
entities
.
add
(
entity
);
}
player
.
sendPacket
(
new
PacketSceneEntityAppearNotify
(
entities
,
VisionType
.
VisionMeet
));
}
public
void
handleAttack
(
AttackResult
result
)
{
//GenshinEntity attacker = getEntityById(result.getAttackerId());
GenshinEntity
target
=
getEntityById
(
result
.
getDefenseId
());
if
(
target
==
null
)
{
return
;
}
// Godmode check
if
(
target
instanceof
EntityAvatar
)
{
if
(((
EntityAvatar
)
target
).
getPlayer
().
inGodmode
())
{
return
;
}
}
// Lose hp
target
.
addFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
-
result
.
getDamage
());
// Check if dead
boolean
isDead
=
false
;
if
(
target
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
)
<=
0
f
)
{
target
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
0
f
);
isDead
=
true
;
}
// Packets
this
.
broadcastPacket
(
new
PacketEntityFightPropUpdateNotify
(
target
,
FightProperty
.
FIGHT_PROP_CUR_HP
));
// Check if dead
if
(
isDead
)
{
this
.
killEntity
(
target
,
result
.
getAttackerId
());
}
}
public
void
killEntity
(
GenshinEntity
target
,
int
attackerId
)
{
// Packet
this
.
broadcastPacket
(
new
PacketLifeStateChangeNotify
(
attackerId
,
target
,
LifeState
.
LIFE_DEAD
));
this
.
removeEntity
(
target
);
// Death event
target
.
onDeath
(
attackerId
);
}
// Gadgets
public
void
onPlayerCreateGadget
(
EntityClientGadget
gadget
)
{
// Directly add
this
.
addEntityDirectly
(
gadget
);
// Add to owner's gadget list
gadget
.
getOwner
().
getTeamManager
().
getGadgets
().
add
(
gadget
);
// Optimization
if
(
this
.
getPlayerCount
()
==
1
&&
this
.
getPlayers
().
get
(
0
)
==
gadget
.
getOwner
())
{
return
;
}
this
.
broadcastPacketToOthers
(
gadget
.
getOwner
(),
new
PacketSceneEntityAppearNotify
(
gadget
));
}
public
void
onPlayerDestroyGadget
(
int
entityId
)
{
GenshinEntity
entity
=
getEntities
().
get
(
entityId
);
if
(
entity
==
null
||
!(
entity
instanceof
EntityClientGadget
))
{
return
;
}
// Get and remove entity
EntityClientGadget
gadget
=
(
EntityClientGadget
)
entity
;
this
.
removeEntityDirectly
(
gadget
);
// Remove from owner's gadget list
gadget
.
getOwner
().
getTeamManager
().
getGadgets
().
remove
(
gadget
);
// Optimization
if
(
this
.
getPlayerCount
()
==
1
&&
this
.
getPlayers
().
get
(
0
)
==
gadget
.
getOwner
())
{
return
;
}
this
.
broadcastPacketToOthers
(
gadget
.
getOwner
(),
new
PacketSceneEntityDisappearNotify
(
gadget
,
VisionType
.
VisionDie
));
}
// Broadcasting
public
void
broadcastPacket
(
GenshinPacket
packet
)
{
// Send to all players - might have to check if player has been sent data packets
for
(
GenshinPlayer
player
:
this
.
getPlayers
())
{
player
.
getSession
().
send
(
packet
);
}
}
public
void
broadcastPacketToOthers
(
GenshinPlayer
excludedPlayer
,
GenshinPacket
packet
)
{
// Optimization
if
(
this
.
getPlayerCount
()
==
1
&&
this
.
getPlayers
().
get
(
0
)
==
excludedPlayer
)
{
return
;
}
// Send to all players - might have to check if player has been sent data packets
for
(
GenshinPlayer
player
:
this
.
getPlayers
())
{
if
(
player
==
excludedPlayer
)
{
continue
;
}
// Send
player
.
getSession
().
send
(
packet
);
}
}
}
src/main/java/emu/grasscutter/game/InvokeHandler.java
View file @
058d3222
...
...
@@ -46,12 +46,12 @@ public class InvokeHandler<T> {
try
{
if
(
entryListForwardAll
.
size
()
>
0
)
{
GenshinPacket
packet
=
packetClass
.
getDeclaredConstructor
(
List
.
class
).
newInstance
(
this
.
entryListForwardAll
);
player
.
get
World
().
broadcastPacket
(
packet
);
player
.
get
Scene
().
broadcastPacket
(
packet
);
this
.
entryListForwardAll
.
clear
();
}
if
(
entryListForwardAllExceptCur
.
size
()
>
0
)
{
GenshinPacket
packet
=
packetClass
.
getDeclaredConstructor
(
List
.
class
).
newInstance
(
this
.
entryListForwardAllExceptCur
);
player
.
get
World
().
broadcastPacketToOthers
(
player
,
packet
);
player
.
get
Scene
().
broadcastPacketToOthers
(
player
,
packet
);
this
.
entryListForwardAllExceptCur
.
clear
();
}
if
(
entryListForwardHost
.
size
()
>
0
)
{
...
...
src/main/java/emu/grasscutter/game/TeamInfo.java
View file @
058d3222
...
...
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import
java.util.List
;
import
emu.grasscutter.GenshinConstants
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.avatar.GenshinAvatar
;
public
class
TeamInfo
{
...
...
@@ -12,7 +13,7 @@ public class TeamInfo {
public
TeamInfo
()
{
this
.
name
=
""
;
this
.
avatars
=
new
ArrayList
<>(
G
enshinConstants
.
MAX_AVATARS_IN_TEAM
);
this
.
avatars
=
new
ArrayList
<>(
G
rasscutter
.
getConfig
().
getServerOptions
().
MaxAvatarsInTeam
);
}
public
String
getName
()
{
...
...
@@ -36,7 +37,7 @@ public class TeamInfo {
}
public
boolean
addAvatar
(
GenshinAvatar
avatar
)
{
if
(
size
()
>=
G
enshinConstants
.
MAX_AVATARS_IN_TEAM
||
contains
(
avatar
))
{
if
(
size
()
>=
G
rasscutter
.
getConfig
().
getServerOptions
().
MaxAvatarsInTeam
||
contains
(
avatar
))
{
return
false
;
}
...
...
@@ -56,7 +57,7 @@ public class TeamInfo {
}
public
void
copyFrom
(
TeamInfo
team
)
{
copyFrom
(
team
,
G
enshinConstants
.
MAX_AVATARS_IN_TEAM
);
copyFrom
(
team
,
G
rasscutter
.
getConfig
().
getServerOptions
().
MaxAvatarsInTeam
);
}
public
void
copyFrom
(
TeamInfo
team
,
int
maxTeamSize
)
{
...
...
src/main/java/emu/grasscutter/game/TeamManager.java
View file @
058d3222
...
...
@@ -10,6 +10,7 @@ import java.util.Set;
import
dev.morphia.annotations.Transient
;
import
emu.grasscutter.GenshinConstants
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.def.AvatarSkillDepotData
;
import
emu.grasscutter.game.avatar.GenshinAvatar
;
import
emu.grasscutter.game.entity.EntityAvatar
;
...
...
@@ -158,17 +159,18 @@ public class TeamManager {
}
public
boolean
isSpawned
()
{
return
getPlayer
().
get
World
()
!=
null
&&
getPlayer
().
get
World
().
getEntities
().
containsKey
(
getCurrentAvatarEntity
().
getId
());
return
getPlayer
().
get
Scene
()
!=
null
&&
getPlayer
().
get
Scene
().
getEntities
().
containsKey
(
getCurrentAvatarEntity
().
getId
());
}
public
int
getMaxTeamSize
()
{
if
(
getPlayer
().
isInMultiplayer
())
{
int
max
=
Grasscutter
.
getConfig
().
getServerOptions
().
MaxAvatarsInTeamMultiplayer
;
if
(
getPlayer
().
getWorld
().
getHost
()
==
this
.
getPlayer
())
{
return
Math
.
max
(
1
,
(
int
)
Math
.
ceil
(
GenshinConstants
.
MAX_AVATARS_IN_TEAM
/
(
double
)
getWorld
().
getPlayerCount
()));
return
Math
.
max
(
1
,
(
int
)
Math
.
ceil
(
max
/
(
double
)
getWorld
().
getPlayerCount
()));
}
return
Math
.
max
(
1
,
(
int
)
Math
.
floor
(
GenshinConstants
.
MAX_AVATARS_IN_TEAM
/
(
double
)
getWorld
().
getPlayerCount
()));
return
Math
.
max
(
1
,
(
int
)
Math
.
floor
(
max
/
(
double
)
getWorld
().
getPlayerCount
()));
}
return
G
enshinConstants
.
MAX_AVATARS_IN_TEAM
;
return
G
rasscutter
.
getConfig
().
getServerOptions
().
MaxAvatarsInTeam
;
}
// Methods
...
...
@@ -233,7 +235,7 @@ public class TeamManager {
prevSelectedAvatarIndex
=
i
;
}
}
else
{
entity
=
new
EntityAvatar
(
getPlayer
().
get
World
(),
getPlayer
().
getAvatars
().
getAvatarById
(
avatarId
));
entity
=
new
EntityAvatar
(
getPlayer
().
get
Scene
(),
getPlayer
().
getAvatars
().
getAvatarById
(
avatarId
));
}
this
.
getActiveTeam
().
add
(
entity
);
...
...
@@ -241,7 +243,7 @@ public class TeamManager {
// Unload removed entities
for
(
EntityAvatar
entity
:
existingAvatars
.
values
())
{
getPlayer
().
get
World
().
removeEntity
(
entity
);
getPlayer
().
get
Scene
().
removeEntity
(
entity
);
entity
.
getAvatar
().
save
();
}
...
...
@@ -266,7 +268,7 @@ public class TeamManager {
// Check if character changed
if
(
currentEntity
!=
getCurrentAvatarEntity
())
{
// Remove and Add
get
World
().
replaceEntity
(
currentEntity
,
getCurrentAvatarEntity
());
get
Player
().
getScene
().
replaceEntity
(
currentEntity
,
getCurrentAvatarEntity
());
}
}
...
...
@@ -396,7 +398,7 @@ public class TeamManager {
oldEntity
.
setMotionState
(
MotionState
.
MotionStandby
);
// Remove and Add
get
World
().
replaceEntity
(
oldEntity
,
newEntity
);
get
Player
().
getScene
().
replaceEntity
(
oldEntity
,
newEntity
);
getPlayer
().
sendPacket
(
new
PacketChangeAvatarRsp
(
guid
));
}
...
...
@@ -426,7 +428,7 @@ public class TeamManager {
}
else
{
// Set index and spawn replacement member
this
.
setCurrentCharacterIndex
(
replaceIndex
);
get
World
().
addEntity
(
replacement
);
get
Player
().
getScene
().
addEntity
(
replacement
);
}
// Response packet
...
...
src/main/java/emu/grasscutter/game/World.java
View file @
058d3222
...
...
@@ -14,6 +14,8 @@ import emu.grasscutter.game.props.EnterReason;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.def.SceneData
;
import
emu.grasscutter.game.GenshinPlayer.SceneLoadState
;
import
emu.grasscutter.game.entity.EntityAvatar
;
import
emu.grasscutter.game.entity.EntityClientGadget
;
...
...
@@ -33,24 +35,21 @@ import emu.grasscutter.server.packet.send.PacketSyncScenePlayTeamEntityNotify;
import
emu.grasscutter.server.packet.send.PacketSyncTeamEntityNotify
;
import
emu.grasscutter.server.packet.send.PacketWorldPlayerInfoNotify
;
import
emu.grasscutter.server.packet.send.PacketWorldPlayerRTTNotify
;
import
emu.grasscutter.utils.Position
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
public
class
World
implements
Iterable
<
GenshinPlayer
>
{
private
final
GenshinPlayer
owner
;
private
final
List
<
GenshinPlayer
>
players
;
private
final
Int2ObjectMap
<
GenshinScene
>
scenes
;
private
int
levelEntityId
;
private
int
nextEntityId
=
0
;
private
int
nextPeerId
=
0
;
private
final
Int2ObjectMap
<
GenshinEntity
>
entities
;
private
int
worldLevel
;
private
int
sceneId
;
private
int
time
;
private
ClimateType
climate
;
private
boolean
isMultiplayer
;
private
boolean
isDungeon
;
public
World
(
GenshinPlayer
player
)
{
this
(
player
,
false
);
...
...
@@ -59,11 +58,9 @@ public class World implements Iterable<GenshinPlayer> {
public
World
(
GenshinPlayer
player
,
boolean
isMultiplayer
)
{
this
.
owner
=
player
;
this
.
players
=
Collections
.
synchronizedList
(
new
ArrayList
<>());
this
.
entities
=
new
Int2ObjectOpenHashMap
<>();
this
.
scenes
=
new
Int2ObjectOpenHashMap
<>();
this
.
levelEntityId
=
getNextEntityId
(
EntityIdType
.
MPLEVEL
);
this
.
sceneId
=
player
.
getSceneId
();
this
.
time
=
8
*
60
;
this
.
climate
=
ClimateType
.
CLIMATE_SUNNY
;
this
.
worldLevel
=
player
.
getWorldLevel
();
this
.
isMultiplayer
=
isMultiplayer
;
}
...
...
@@ -87,22 +84,6 @@ public class World implements Iterable<GenshinPlayer> {
return
++
this
.
nextPeerId
;
}
public
int
getSceneId
()
{
return
sceneId
;
}
public
void
setSceneId
(
int
sceneId
)
{
this
.
sceneId
=
sceneId
;
}
public
int
getTime
()
{
return
time
;
}
public
void
changeTime
(
int
time
)
{
this
.
time
=
time
%
1440
;
}
public
int
getWorldLevel
()
{
return
worldLevel
;
}
...
...
@@ -111,46 +92,44 @@ public class World implements Iterable<GenshinPlayer> {
this
.
worldLevel
=
worldLevel
;
}
public
ClimateType
getClimate
()
{
return
climate
;
public
List
<
GenshinPlayer
>
getPlayers
()
{
return
players
;
}
public
void
setClimate
(
ClimateType
climate
)
{
this
.
climate
=
climate
;
public
Int2ObjectMap
<
GenshinScene
>
getScenes
(
)
{
return
this
.
scenes
;
}
public
List
<
GenshinPlayer
>
getPlayers
()
{
return
players
;
public
GenshinScene
getSceneById
(
int
sceneId
)
{
// Get scene normally
GenshinScene
scene
=
getScenes
().
get
(
sceneId
);
if
(
scene
!=
null
)
{
return
scene
;
}
public
int
getPlayerCount
()
{
return
getPlayers
().
size
();
// Create scene from scene data if it doesnt exist
SceneData
sceneData
=
GenshinData
.
getSceneDataMap
().
get
(
sceneId
);
if
(
sceneData
!=
null
)
{
scene
=
new
GenshinScene
(
this
,
sceneData
);
this
.
registerScene
(
scene
);
return
scene
;
}
public
Int2ObjectMap
<
GenshinEntity
>
getEntities
()
{
return
this
.
entities
;
return
null
;
}
public
boolean
isInWorld
(
GenshinEntity
entity
)
{
return
this
.
entities
.
containsKey
(
entity
.
getId
()
);
public
int
getPlayerCount
(
)
{
return
getPlayers
().
size
(
);
}
public
boolean
isMultiplayer
()
{
return
isMultiplayer
;
}
public
boolean
isDungeon
()
{
return
isDungeon
;
}
public
int
getNextEntityId
(
EntityIdType
idType
)
{
return
(
idType
.
getId
()
<<
24
)
+
++
this
.
nextEntityId
;
}
public
GenshinEntity
getEntityById
(
int
id
)
{
return
this
.
entities
.
get
(
id
);
}
public
synchronized
void
addPlayer
(
GenshinPlayer
player
)
{
// Check if player already in
if
(
getPlayers
().
contains
(
player
))
{
...
...
@@ -166,11 +145,19 @@ public class World implements Iterable<GenshinPlayer> {
player
.
setWorld
(
this
);
getPlayers
().
add
(
player
);
// Set player variables
player
.
setPeerId
(
this
.
getNextPeerId
());
player
.
getTeamManager
().
setEntityId
(
getNextEntityId
(
EntityIdType
.
TEAM
));
// Setup team avatars
this
.
setupPlayerAvatars
(
player
);
// Copy main team to mp team
if
(
this
.
isMultiplayer
())
{
player
.
getTeamManager
().
getMpTeam
().
copyFrom
(
player
.
getTeamManager
().
getCurrentSinglePlayerTeamInfo
(),
player
.
getTeamManager
().
getMaxTeamSize
());
player
.
getTeamManager
().
setCurrentCharacterIndex
(
0
);
}
// Add to scene
GenshinScene
scene
=
this
.
getSceneById
(
player
.
getSceneId
());
scene
.
addPlayer
(
player
);
// Info packet for other players
if
(
this
.
getPlayers
().
size
()
>
1
)
{
...
...
@@ -191,18 +178,15 @@ public class World implements Iterable<GenshinPlayer> {
getPlayers
().
remove
(
player
);
player
.
setWorld
(
null
);
this
.
removePlayerAvatars
(
player
);
// Remove from scene
GenshinScene
scene
=
this
.
getSceneById
(
player
.
getSceneId
());
scene
.
removePlayer
(
player
);
// Info packet for other players
if
(
this
.
getPlayers
().
size
()
>
0
)
{
this
.
updatePlayerInfos
(
player
);
}
// Remove player gadgets
for
(
EntityGadget
gadget
:
player
.
getTeamManager
().
getGadgets
())
{
this
.
removeEntity
(
gadget
);
}
// Disband world if host leaves
if
(
getHost
()
==
player
)
{
List
<
GenshinPlayer
>
kicked
=
new
ArrayList
<>(
this
.
getPlayers
());
...
...
@@ -210,11 +194,37 @@ public class World implements Iterable<GenshinPlayer> {
World
world
=
new
World
(
victim
);
world
.
addPlayer
(
victim
);
victim
.
sendPacket
(
new
PacketPlayerEnterSceneNotify
(
victim
,
EnterType
.
EnterSelf
,
EnterReason
.
TeamKick
,
victim
.
getWorld
().
getSceneId
(),
victim
.
getPos
()));
victim
.
sendPacket
(
new
PacketPlayerEnterSceneNotify
(
victim
,
EnterType
.
EnterSelf
,
EnterReason
.
TeamKick
,
victim
.
getSceneId
(),
victim
.
getPos
()));
}
}
}
public
void
registerScene
(
GenshinScene
scene
)
{
this
.
getScenes
().
put
(
scene
.
getId
(),
scene
);
}
public
void
deregisterScene
(
GenshinScene
scene
)
{
this
.
getScenes
().
remove
(
scene
.
getId
());
}
public
boolean
transferPlayerToScene
(
GenshinPlayer
player
,
int
sceneId
,
Position
pos
)
{
if
(
player
.
getScene
().
getId
()
==
sceneId
||
GenshinData
.
getSceneDataMap
().
get
(
sceneId
)
==
null
)
{
return
false
;
}
if
(
player
.
getScene
()
!=
null
)
{
player
.
getScene
().
removePlayer
(
player
);
}
GenshinScene
scene
=
this
.
getSceneById
(
sceneId
);
scene
.
addPlayer
(
player
);
player
.
getPos
().
set
(
pos
);
// Teleport packet
player
.
sendPacket
(
new
PacketPlayerEnterSceneNotify
(
player
,
EnterType
.
EnterSelf
,
EnterReason
.
TransPoint
,
sceneId
,
pos
));
return
true
;
}
private
void
updatePlayerInfos
(
GenshinPlayer
paramPlayer
)
{
for
(
GenshinPlayer
player
:
getPlayers
())
{
// Dont send packets if player is loading in and filter out joining player
...
...
@@ -239,185 +249,6 @@ public class World implements Iterable<GenshinPlayer> {
}
}
private
void
addEntityDirectly
(
GenshinEntity
entity
)
{
getEntities
().
put
(
entity
.
getId
(),
entity
);
}
public
synchronized
void
addEntity
(
GenshinEntity
entity
)
{
this
.
addEntityDirectly
(
entity
);
this
.
broadcastPacket
(
new
PacketSceneEntityAppearNotify
(
entity
));
}
public
synchronized
void
addEntities
(
Collection
<
GenshinEntity
>
entities
)
{
for
(
GenshinEntity
entity
:
entities
)
{
this
.
addEntityDirectly
(
entity
);
}
this
.
broadcastPacket
(
new
PacketSceneEntityAppearNotify
(
entities
,
VisionType
.
VisionBorn
));
}
private
GenshinEntity
removeEntityDirectly
(
GenshinEntity
entity
)
{
return
getEntities
().
remove
(
entity
.
getId
());
}
public
void
removeEntity
(
GenshinEntity
entity
)
{
this
.
removeEntity
(
entity
,
VisionType
.
VisionDie
);
}
public
synchronized
void
removeEntity
(
GenshinEntity
entity
,
VisionType
visionType
)
{
GenshinEntity
removed
=
this
.
removeEntityDirectly
(
entity
);
if
(
removed
!=
null
)
{
this
.
broadcastPacket
(
new
PacketSceneEntityDisappearNotify
(
removed
,
visionType
));
}
}
public
synchronized
void
replaceEntity
(
EntityAvatar
oldEntity
,
EntityAvatar
newEntity
)
{
this
.
removeEntityDirectly
(
oldEntity
);
this
.
addEntityDirectly
(
newEntity
);
this
.
broadcastPacket
(
new
PacketSceneEntityDisappearNotify
(
oldEntity
,
VisionType
.
VisionReplace
));
this
.
broadcastPacket
(
new
PacketSceneEntityAppearNotify
(
newEntity
,
VisionType
.
VisionReplace
,
oldEntity
.
getId
()));
}
private
void
setupPlayerAvatars
(
GenshinPlayer
player
)
{
// Copy main team to mp team
if
(
this
.
isMultiplayer
())
{
player
.
getTeamManager
().
getMpTeam
().
copyFrom
(
player
.
getTeamManager
().
getCurrentSinglePlayerTeamInfo
(),
player
.
getTeamManager
().
getMaxTeamSize
());
}
// Clear entities from old team
player
.
getTeamManager
().
getActiveTeam
().
clear
();
// Add new entities for player
TeamInfo
teamInfo
=
player
.
getTeamManager
().
getCurrentTeamInfo
();
for
(
int
avatarId
:
teamInfo
.
getAvatars
())
{
EntityAvatar
entity
=
new
EntityAvatar
(
this
,
player
.
getAvatars
().
getAvatarById
(
avatarId
));
player
.
getTeamManager
().
getActiveTeam
().
add
(
entity
);
}
// Limit character index in case its out of bounds
if
(
player
.
getTeamManager
().
getCurrentCharacterIndex
()
>=
player
.
getTeamManager
().
getActiveTeam
().
size
()
||
player
.
getTeamManager
().
getCurrentCharacterIndex
()
<
0
)
{
player
.
getTeamManager
().
setCurrentCharacterIndex
(
player
.
getTeamManager
().
getCurrentCharacterIndex
()
-
1
);
}
}
private
void
removePlayerAvatars
(
GenshinPlayer
player
)
{
Iterator
<
EntityAvatar
>
it
=
player
.
getTeamManager
().
getActiveTeam
().
iterator
();
while
(
it
.
hasNext
())
{
this
.
removeEntity
(
it
.
next
(),
VisionType
.
VisionRemove
);
it
.
remove
();
}
}
public
void
spawnPlayer
(
GenshinPlayer
player
)
{
if
(
isInWorld
(
player
.
getTeamManager
().
getCurrentAvatarEntity
()))
{
return
;
}
if
(
player
.
getTeamManager
().
getCurrentAvatarEntity
().
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
)
<=
0
f
)
{
player
.
getTeamManager
().
getCurrentAvatarEntity
().
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
1
f
);
}
this
.
addEntity
(
player
.
getTeamManager
().
getCurrentAvatarEntity
());
}
public
void
showOtherEntities
(
GenshinPlayer
player
)
{
List
<
GenshinEntity
>
entities
=
new
LinkedList
<>();
GenshinEntity
currentEntity
=
player
.
getTeamManager
().
getCurrentAvatarEntity
();
for
(
GenshinEntity
entity
:
this
.
getEntities
().
values
())
{
if
(
entity
==
currentEntity
)
{
continue
;
}
entities
.
add
(
entity
);
}
player
.
sendPacket
(
new
PacketSceneEntityAppearNotify
(
entities
,
VisionType
.
VisionMeet
));
}
public
void
handleAttack
(
AttackResult
result
)
{
//GenshinEntity attacker = getEntityById(result.getAttackerId());
GenshinEntity
target
=
getEntityById
(
result
.
getDefenseId
());
if
(
target
==
null
)
{
return
;
}
// Godmode check
if
(
target
instanceof
EntityAvatar
)
{
if
(((
EntityAvatar
)
target
).
getPlayer
().
inGodmode
())
{
return
;
}
}
// Lose hp
target
.
addFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
-
result
.
getDamage
());
// Check if dead
boolean
isDead
=
false
;
if
(
target
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
)
<=
0
f
)
{
target
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
0
f
);
isDead
=
true
;
}
// Packets
this
.
broadcastPacket
(
new
PacketEntityFightPropUpdateNotify
(
target
,
FightProperty
.
FIGHT_PROP_CUR_HP
));
// Check if dead
if
(
isDead
)
{
this
.
killEntity
(
target
,
result
.
getAttackerId
());
}
}
public
void
killEntity
(
GenshinEntity
target
,
int
attackerId
)
{
// Packet
this
.
broadcastPacket
(
new
PacketLifeStateChangeNotify
(
attackerId
,
target
,
LifeState
.
LIFE_DEAD
));
this
.
removeEntity
(
target
);
// Death event
target
.
onDeath
(
attackerId
);
}
// Gadgets
public
void
onPlayerCreateGadget
(
EntityClientGadget
gadget
)
{
// Directly add
this
.
addEntityDirectly
(
gadget
);
// Add to owner's gadget list
gadget
.
getOwner
().
getTeamManager
().
getGadgets
().
add
(
gadget
);
// Optimization
if
(
this
.
getPlayerCount
()
==
1
&&
this
.
getPlayers
().
get
(
0
)
==
gadget
.
getOwner
())
{
return
;
}
this
.
broadcastPacketToOthers
(
gadget
.
getOwner
(),
new
PacketSceneEntityAppearNotify
(
gadget
));
}
public
void
onPlayerDestroyGadget
(
int
entityId
)
{
GenshinEntity
entity
=
getEntities
().
get
(
entityId
);
if
(
entity
==
null
||
!(
entity
instanceof
EntityClientGadget
))
{
return
;
}
// Get and remove entity
EntityClientGadget
gadget
=
(
EntityClientGadget
)
entity
;
this
.
removeEntityDirectly
(
gadget
);
// Remove from owner's gadget list
gadget
.
getOwner
().
getTeamManager
().
getGadgets
().
remove
(
gadget
);
// Optimization
if
(
this
.
getPlayerCount
()
==
1
&&
this
.
getPlayers
().
get
(
0
)
==
gadget
.
getOwner
())
{
return
;
}
this
.
broadcastPacketToOthers
(
gadget
.
getOwner
(),
new
PacketSceneEntityDisappearNotify
(
gadget
,
VisionType
.
VisionDie
));
}
// Broadcasting
public
void
broadcastPacket
(
GenshinPacket
packet
)
{
// Send to all players - might have to check if player has been sent data packets
for
(
GenshinPlayer
player
:
this
.
getPlayers
())
{
...
...
@@ -425,21 +256,6 @@ public class World implements Iterable<GenshinPlayer> {
}
}
public
void
broadcastPacketToOthers
(
GenshinPlayer
excludedPlayer
,
GenshinPacket
packet
)
{
// Optimization
if
(
this
.
getPlayerCount
()
==
1
&&
this
.
getPlayers
().
get
(
0
)
==
excludedPlayer
)
{
return
;
}
// Send to all players - might have to check if player has been sent data packets
for
(
GenshinPlayer
player
:
this
.
getPlayers
())
{
if
(
player
==
excludedPlayer
)
{
continue
;
}
// Send
player
.
getSession
().
send
(
packet
);
}
}
public
void
close
()
{
}
...
...
src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java
View file @
058d3222
...
...
@@ -122,7 +122,7 @@ public class AvatarStorage implements Iterable<GenshinAvatar> {
entity
=
new
EntityAvatar
(
avatar
);
getPlayer
().
sendPacket
(
new
PacketAvatarChangeCostumeNotify
(
entity
));
}
else
{
getPlayer
().
get
World
().
broadcastPacket
(
new
PacketAvatarChangeCostumeNotify
(
entity
));
getPlayer
().
get
Scene
().
broadcastPacket
(
new
PacketAvatarChangeCostumeNotify
(
entity
));
}
// Done
...
...
src/main/java/emu/grasscutter/game/avatar/GenshinAvatar.java
View file @
058d3222
...
...
@@ -148,8 +148,8 @@ public class GenshinAvatar {
public
void
setOwner
(
GenshinPlayer
player
)
{
this
.
owner
=
player
;
this
.
ownerId
=
player
.
get
I
d
();
this
.
guid
=
player
.
getNextGuid
();
this
.
ownerId
=
player
.
get
Ui
d
();
this
.
guid
=
player
.
getNextG
enshinG
uid
();
}
public
int
getSatiation
()
{
...
...
src/main/java/emu/grasscutter/game/entity/EntityAvatar.java
View file @
058d3222
...
...
@@ -5,6 +5,7 @@ import emu.grasscutter.data.GenshinData;
import
emu.grasscutter.data.def.AvatarData
;
import
emu.grasscutter.data.def.AvatarSkillDepotData
;
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.inventory.EquipType
;
...
...
@@ -39,14 +40,14 @@ public class EntityAvatar extends GenshinEntity {
private
PlayerDieType
killedType
;
private
int
killedBy
;
public
EntityAvatar
(
World
world
,
GenshinAvatar
avatar
)
{
super
(
world
);
public
EntityAvatar
(
GenshinScene
scene
,
GenshinAvatar
avatar
)
{
super
(
scene
);
this
.
avatar
=
avatar
;
this
.
id
=
w
orld
.
getNextEntityId
(
EntityIdType
.
AVATAR
);
this
.
id
=
getScene
().
getW
orld
()
.
getNextEntityId
(
EntityIdType
.
AVATAR
);
GenshinItem
weapon
=
this
.
getAvatar
().
getWeapon
();
if
(
weapon
!=
null
)
{
weapon
.
setWeaponEntityId
(
w
orld
.
getNextEntityId
(
EntityIdType
.
WEAPON
));
weapon
.
setWeaponEntityId
(
getScene
().
getW
orld
()
.
getNextEntityId
(
EntityIdType
.
WEAPON
));
}
}
...
...
@@ -106,7 +107,7 @@ public class EntityAvatar extends GenshinEntity {
public
SceneAvatarInfo
getSceneAvatarInfo
()
{
SceneAvatarInfo
.
Builder
avatarInfo
=
SceneAvatarInfo
.
newBuilder
()
.
setPlayerId
(
this
.
getPlayer
().
get
I
d
())
.
setPlayerId
(
this
.
getPlayer
().
get
Ui
d
())
.
setAvatarId
(
this
.
getAvatar
().
getAvatarId
())
.
setGuid
(
this
.
getAvatar
().
getGuid
())
.
setPeerId
(
this
.
getPlayer
().
getPeerId
())
...
...
@@ -152,7 +153,7 @@ public class EntityAvatar extends GenshinEntity {
.
setLastMoveReliableSeq
(
this
.
getLastMoveReliableSeq
())
.
setLifeState
(
this
.
getLifeState
().
getValue
());
if
(
this
.
get
World
()
!=
null
)
{
if
(
this
.
get
Scene
()
!=
null
)
{
entityInfo
.
setMotionInfo
(
this
.
getMotionInfo
());
}
...
...
src/main/java/emu/grasscutter/game/entity/EntityClientGadget.java
View file @
058d3222
package
emu.grasscutter.game.entity
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.GenshinScene
;
import
emu.grasscutter.game.World
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo
;
...
...
@@ -34,8 +35,8 @@ public class EntityClientGadget extends EntityGadget {
private
int
targetEntityId
;
private
boolean
asyncLoad
;
public
EntityClientGadget
(
World
world
,
GenshinPlayer
player
,
EvtCreateGadgetNotify
notify
)
{
super
(
world
);
public
EntityClientGadget
(
GenshinScene
scene
,
GenshinPlayer
player
,
EvtCreateGadgetNotify
notify
)
{
super
(
scene
);
this
.
owner
=
player
;
this
.
id
=
notify
.
getEntityId
();
this
.
pos
=
new
Position
(
notify
.
getInitPos
());
...
...
Prev
1
2
3
4
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