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
7925d1cd
Commit
7925d1cd
authored
Apr 17, 2022
by
Melledy
Browse files
Initial commit
parents
Changes
354
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/data/def/WeaponPromoteData.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.data.def
;
import
java.util.ArrayList
;
import
emu.grasscutter.data.GenshinResource
;
import
emu.grasscutter.data.ResourceType
;
import
emu.grasscutter.data.common.FightPropData
;
import
emu.grasscutter.data.common.ItemParamData
;
@ResourceType
(
name
=
"WeaponPromoteExcelConfigData.json"
)
public
class
WeaponPromoteData
extends
GenshinResource
{
private
int
WeaponPromoteId
;
private
int
PromoteLevel
;
private
ItemParamData
[]
CostItems
;
private
int
CoinCost
;
private
FightPropData
[]
AddProps
;
private
int
UnlockMaxLevel
;
private
int
RequiredPlayerLevel
;
@Override
public
int
getId
()
{
return
(
WeaponPromoteId
<<
8
)
+
PromoteLevel
;
}
public
int
getWeaponPromoteId
()
{
return
WeaponPromoteId
;
}
public
int
getPromoteLevel
()
{
return
PromoteLevel
;
}
public
ItemParamData
[]
getCostItems
()
{
return
CostItems
;
}
public
int
getCoinCost
()
{
return
CoinCost
;
}
public
FightPropData
[]
getAddProps
()
{
return
AddProps
;
}
public
int
getUnlockMaxLevel
()
{
return
UnlockMaxLevel
;
}
public
int
getRequiredPlayerLevel
()
{
return
RequiredPlayerLevel
;
}
@Override
public
void
onLoad
()
{
// Trim item params
ArrayList
<
ItemParamData
>
trim
=
new
ArrayList
<>(
getAddProps
().
length
);
for
(
ItemParamData
itemParam
:
getCostItems
())
{
if
(
itemParam
.
getId
()
==
0
)
{
continue
;
}
trim
.
add
(
itemParam
);
}
this
.
CostItems
=
trim
.
toArray
(
new
ItemParamData
[
trim
.
size
()]);
// Trim fight prop data
ArrayList
<
FightPropData
>
parsed
=
new
ArrayList
<>(
getAddProps
().
length
);
for
(
FightPropData
prop
:
getAddProps
())
{
if
(
prop
.
getPropType
()
!=
null
&&
prop
.
getValue
()
!=
0
f
)
{
prop
.
onLoad
();
parsed
.
add
(
prop
);
}
}
this
.
AddProps
=
parsed
.
toArray
(
new
FightPropData
[
parsed
.
size
()]);
}
}
src/main/java/emu/grasscutter/database/DatabaseCounter.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.database
;
import
dev.morphia.annotations.Entity
;
import
dev.morphia.annotations.Id
;
@Entity
(
value
=
"counters"
,
noClassnameStored
=
true
)
public
class
DatabaseCounter
{
@Id
private
String
id
;
private
int
count
;
public
DatabaseCounter
()
{}
public
DatabaseCounter
(
String
id
)
{
this
.
id
=
id
;
this
.
count
=
10000
;
}
public
int
getNextId
()
{
int
id
=
++
count
;
return
id
;
}
}
src/main/java/emu/grasscutter/database/DatabaseHelper.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.database
;
import
java.util.List
;
import
com.mongodb.WriteResult
;
import
dev.morphia.query.FindOptions
;
import
dev.morphia.query.Query
;
import
dev.morphia.query.internal.MorphiaCursor
;
import
emu.grasscutter.GenshinConstants
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.Account
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.avatar.GenshinAvatar
;
import
emu.grasscutter.game.friends.Friendship
;
import
emu.grasscutter.game.inventory.GenshinItem
;
public
class
DatabaseHelper
{
protected
static
FindOptions
FIND_ONE
=
new
FindOptions
().
limit
(
1
);
public
static
Account
createAccount
(
String
username
)
{
return
createAccountWithId
(
username
,
0
);
}
public
static
Account
createAccountWithId
(
String
username
,
int
reservedId
)
{
// Unique names only
Account
exists
=
DatabaseHelper
.
getAccountByName
(
username
);
if
(
exists
!=
null
)
{
return
null
;
}
// Make sure there are no id collisions
if
(
reservedId
>
0
)
{
// Cannot make account with the same uid as the server console
if
(
reservedId
==
GenshinConstants
.
SERVER_CONSOLE_UID
)
{
return
null
;
}
exists
=
DatabaseHelper
.
getAccountByPlayerId
(
reservedId
);
if
(
exists
!=
null
)
{
return
null
;
}
}
// Account
Account
account
=
new
Account
();
account
.
setUsername
(
username
);
account
.
setId
(
Integer
.
toString
(
DatabaseManager
.
getNextId
(
account
)));
if
(
reservedId
>
0
)
{
account
.
setPlayerId
(
reservedId
);
}
DatabaseHelper
.
saveAccount
(
account
);
return
account
;
}
@Deprecated
public
static
Account
createAccountWithPassword
(
String
username
,
String
password
)
{
// Unique names only
Account
exists
=
DatabaseHelper
.
getAccountByName
(
username
);
if
(
exists
!=
null
)
{
return
null
;
}
// Account
Account
account
=
new
Account
();
account
.
setId
(
Integer
.
toString
(
DatabaseManager
.
getNextId
(
account
)));
account
.
setUsername
(
username
);
account
.
setPassword
(
password
);
DatabaseHelper
.
saveAccount
(
account
);
return
account
;
}
public
static
void
saveAccount
(
Account
account
)
{
DatabaseManager
.
getDatastore
().
save
(
account
);
}
public
static
Account
getAccountByName
(
String
username
)
{
MorphiaCursor
<
Account
>
cursor
=
DatabaseManager
.
getDatastore
().
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
);
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
);
if
(!
cursor
.
hasNext
())
return
null
;
return
cursor
.
next
();
}
private
static
Account
getAccountByPlayerId
(
int
playerId
)
{
MorphiaCursor
<
Account
>
cursor
=
DatabaseManager
.
getDatastore
().
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
);
return
DatabaseManager
.
getDatastore
().
findAndDelete
(
q
)
!=
null
;
}
public
static
GenshinPlayer
getPlayerById
(
int
id
)
{
Query
<
GenshinPlayer
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
GenshinPlayer
.
class
).
field
(
"_id"
).
equal
(
id
);
MorphiaCursor
<
GenshinPlayer
>
cursor
=
query
.
find
(
FIND_ONE
);
if
(!
cursor
.
hasNext
())
return
null
;
return
cursor
.
next
();
}
public
static
boolean
checkPlayerExists
(
int
id
)
{
MorphiaCursor
<
GenshinPlayer
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
GenshinPlayer
.
class
).
field
(
"_id"
).
equal
(
id
).
find
(
FIND_ONE
);
return
query
.
hasNext
();
}
public
static
synchronized
GenshinPlayer
createPlayer
(
GenshinPlayer
character
,
int
reservedId
)
{
// Check if reserved id
int
id
=
0
;
if
(
reservedId
>
0
&&
!
checkPlayerExists
(
reservedId
))
{
id
=
reservedId
;
character
.
setId
(
id
);
}
else
{
do
{
id
=
DatabaseManager
.
getNextId
(
character
);
}
while
(
checkPlayerExists
(
id
));
character
.
setId
(
id
);
}
// Save to database
DatabaseManager
.
getDatastore
().
save
(
character
);
return
character
;
}
public
static
synchronized
int
getNextPlayerId
(
int
reservedId
)
{
// Check if reserved id
int
id
=
0
;
if
(
reservedId
>
0
&&
!
checkPlayerExists
(
reservedId
))
{
id
=
reservedId
;
}
else
{
do
{
id
=
DatabaseManager
.
getNextId
(
GenshinPlayer
.
class
);
}
while
(
checkPlayerExists
(
id
));
}
return
id
;
}
public
static
void
savePlayer
(
GenshinPlayer
character
)
{
DatabaseManager
.
getDatastore
().
save
(
character
);
}
public
static
void
saveAvatar
(
GenshinAvatar
avatar
)
{
DatabaseManager
.
getDatastore
().
save
(
avatar
);
}
public
static
List
<
GenshinAvatar
>
getAvatars
(
GenshinPlayer
player
)
{
Query
<
GenshinAvatar
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
GenshinAvatar
.
class
).
filter
(
"ownerId"
,
player
.
getId
());
return
query
.
find
().
toList
();
}
public
static
void
saveItem
(
GenshinItem
item
)
{
DatabaseManager
.
getDatastore
().
save
(
item
);
}
public
static
boolean
deleteItem
(
GenshinItem
item
)
{
WriteResult
result
=
DatabaseManager
.
getDatastore
().
delete
(
item
);
return
result
.
wasAcknowledged
();
}
public
static
List
<
GenshinItem
>
getInventoryItems
(
GenshinPlayer
player
)
{
Query
<
GenshinItem
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
GenshinItem
.
class
).
filter
(
"ownerId"
,
player
.
getId
());
return
query
.
find
().
toList
();
}
public
static
List
<
Friendship
>
getFriends
(
GenshinPlayer
player
)
{
Query
<
Friendship
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
Friendship
.
class
).
filter
(
"ownerId"
,
player
.
getId
());
return
query
.
find
().
toList
();
}
public
static
List
<
Friendship
>
getReverseFriends
(
GenshinPlayer
player
)
{
Query
<
Friendship
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
Friendship
.
class
).
filter
(
"friendId"
,
player
.
getId
());
return
query
.
find
().
toList
();
}
public
static
void
saveFriendship
(
Friendship
friendship
)
{
DatabaseManager
.
getDatastore
().
save
(
friendship
);
}
public
static
void
deleteFriendship
(
Friendship
friendship
)
{
DatabaseManager
.
getDatastore
().
delete
(
friendship
);
}
public
static
Friendship
getReverseFriendship
(
Friendship
friendship
)
{
Query
<
Friendship
>
query
=
DatabaseManager
.
getDatastore
().
createQuery
(
Friendship
.
class
);
query
.
and
(
query
.
criteria
(
"ownerId"
).
equal
(
friendship
.
getFriendId
()),
query
.
criteria
(
"friendId"
).
equal
(
friendship
.
getOwnerId
())
);
MorphiaCursor
<
Friendship
>
reverseFriendship
=
query
.
find
(
FIND_ONE
);
if
(!
reverseFriendship
.
hasNext
())
return
null
;
return
reverseFriendship
.
next
();
}
}
src/main/java/emu/grasscutter/database/DatabaseManager.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.database
;
import
java.sql.Connection
;
import
java.sql.SQLException
;
import
com.mongodb.MongoClient
;
import
com.mongodb.MongoClientURI
;
import
com.mongodb.MongoCommandException
;
import
com.mongodb.client.MongoDatabase
;
import
com.mongodb.client.MongoIterable
;
import
dev.morphia.Datastore
;
import
dev.morphia.Morphia
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.Account
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.avatar.GenshinAvatar
;
import
emu.grasscutter.game.friends.Friendship
;
import
emu.grasscutter.game.inventory.GenshinItem
;
public
class
DatabaseManager
{
private
static
MongoClient
mongoClient
;
private
static
Morphia
morphia
;
private
static
Datastore
datastore
;
private
static
Class
<?>[]
mappedClasses
=
new
Class
<?>[]
{
DatabaseCounter
.
class
,
Account
.
class
,
GenshinPlayer
.
class
,
GenshinAvatar
.
class
,
GenshinItem
.
class
,
Friendship
.
class
};
public
static
MongoClient
getMongoClient
()
{
return
mongoClient
;
}
public
static
Datastore
getDatastore
()
{
return
datastore
;
}
public
static
MongoDatabase
getDatabase
()
{
return
getDatastore
().
getDatabase
();
}
public
static
Connection
getConnection
()
throws
SQLException
{
return
null
;
}
public
static
void
initialize
()
{
// Initialize
mongoClient
=
new
MongoClient
(
new
MongoClientURI
(
Grasscutter
.
getConfig
().
DatabaseUrl
));
morphia
=
new
Morphia
();
// TODO Update when migrating to Morphia 2.0
morphia
.
getMapper
().
getOptions
().
setStoreEmpties
(
true
);
morphia
.
getMapper
().
getOptions
().
setStoreNulls
(
false
);
morphia
.
getMapper
().
getOptions
().
setDisableEmbeddedIndexes
(
true
);
// Map
morphia
.
map
(
mappedClasses
);
// Build datastore
datastore
=
morphia
.
createDatastore
(
mongoClient
,
Grasscutter
.
getConfig
().
DatabaseCollection
);
// Ensure indexes
try
{
datastore
.
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
=
datastore
.
getDatabase
().
listCollectionNames
();
for
(
String
name
:
collections
)
{
datastore
.
getDatabase
().
getCollection
(
name
).
dropIndexes
();
}
// Add back indexes
datastore
.
ensureIndexes
();
}
}
}
public
static
synchronized
int
getNextId
(
Class
<?>
c
)
{
DatabaseCounter
counter
=
getDatastore
().
createQuery
(
DatabaseCounter
.
class
).
field
(
"_id"
).
equal
(
c
.
getSimpleName
()).
find
().
tryNext
();
if
(
counter
==
null
)
{
counter
=
new
DatabaseCounter
(
c
.
getSimpleName
());
}
try
{
return
counter
.
getNextId
();
}
finally
{
getDatastore
().
save
(
counter
);
}
}
public
static
synchronized
int
getNextId
(
Object
o
)
{
return
getNextId
(
o
.
getClass
());
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/game/Account.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game
;
import
dev.morphia.annotations.Collation
;
import
dev.morphia.annotations.Entity
;
import
dev.morphia.annotations.Id
;
import
dev.morphia.annotations.Indexed
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.utils.Crypto
;
import
emu.grasscutter.utils.Utils
;
import
dev.morphia.annotations.IndexOptions
;
@Entity
(
value
=
"accounts"
,
noClassnameStored
=
true
)
public
class
Account
{
@Id
private
String
id
;
@Indexed
(
options
=
@IndexOptions
(
unique
=
true
))
@Collation
(
locale
=
"simple"
,
caseLevel
=
true
)
private
String
username
;
private
String
password
;
// Unused for now
private
int
playerId
;
private
String
email
;
private
String
token
;
private
String
sessionKey
;
// Session token for dispatch server
@Deprecated
public
Account
()
{}
public
String
getId
()
{
return
id
;
}
public
void
setId
(
String
id
)
{
this
.
id
=
id
;
}
public
String
getUsername
()
{
return
username
;
}
public
void
setUsername
(
String
username
)
{
this
.
username
=
username
;
}
public
String
getPassword
()
{
return
password
;
}
public
void
setPassword
(
String
password
)
{
this
.
password
=
password
;
}
public
String
getToken
()
{
return
token
;
}
public
void
setToken
(
String
token
)
{
this
.
token
=
token
;
}
public
int
getPlayerId
()
{
return
this
.
playerId
;
}
public
void
setPlayerId
(
int
playerId
)
{
this
.
playerId
=
playerId
;
}
public
String
getEmail
()
{
return
email
;
}
public
void
setEmail
(
String
email
)
{
this
.
email
=
email
;
}
public
String
getSessionKey
()
{
return
this
.
sessionKey
;
}
public
String
generateSessionKey
()
{
this
.
sessionKey
=
Utils
.
bytesToHex
(
Crypto
.
createSessionKey
(
32
));
this
.
save
();
return
this
.
sessionKey
;
}
// TODO make unique
public
String
generateLoginToken
()
{
this
.
token
=
Utils
.
bytesToHex
(
Crypto
.
createSessionKey
(
32
));
this
.
save
();
return
this
.
token
;
}
public
void
save
()
{
DatabaseHelper
.
saveAccount
(
this
);
}
}
src/main/java/emu/grasscutter/game/CoopRequest.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game
;
public
class
CoopRequest
{
private
final
GenshinPlayer
requester
;
private
final
long
requestTime
;
private
final
long
expireTime
;
public
CoopRequest
(
GenshinPlayer
requester
)
{
this
.
requester
=
requester
;
this
.
requestTime
=
System
.
currentTimeMillis
();
this
.
expireTime
=
this
.
requestTime
+
10000
;
}
public
GenshinPlayer
getRequester
()
{
return
requester
;
}
public
long
getRequestTime
()
{
return
requestTime
;
}
public
long
getExpireTime
()
{
return
expireTime
;
}
public
boolean
isExpired
()
{
return
System
.
currentTimeMillis
()
>
getExpireTime
();
}
}
src/main/java/emu/grasscutter/game/GenshinPlayer.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.Set
;
import
dev.morphia.annotations.*
;
import
emu.grasscutter.GenshinConstants
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.def.PlayerLevelData
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.avatar.AvatarProfileData
;
import
emu.grasscutter.game.avatar.AvatarStorage
;
import
emu.grasscutter.game.avatar.GenshinAvatar
;
import
emu.grasscutter.game.entity.EntityItem
;
import
emu.grasscutter.game.entity.GenshinEntity
;
import
emu.grasscutter.game.friends.FriendsList
;
import
emu.grasscutter.game.friends.PlayerProfile
;
import
emu.grasscutter.game.gacha.PlayerGachaInfo
;
import
emu.grasscutter.game.inventory.GenshinItem
;
import
emu.grasscutter.game.inventory.Inventory
;
import
emu.grasscutter.game.props.ActionReason
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.net.packet.GenshinPacket
;
import
emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry
;
import
emu.grasscutter.net.proto.BirthdayOuterClass.Birthday
;
import
emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry
;
import
emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage
;
import
emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType
;
import
emu.grasscutter.net.proto.MpSettingTypeOuterClass.MpSettingType
;
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.server.game.GameServer
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketAbilityInvocationsNotify
;
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.PacketCombatInvocationsNotify
;
import
emu.grasscutter.server.packet.send.PacketGadgetInteractRsp
;
import
emu.grasscutter.server.packet.send.PacketItemAddHintNotify
;
import
emu.grasscutter.server.packet.send.PacketOpenStateUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketPlayerApplyEnterMpResultNotify
;
import
emu.grasscutter.server.packet.send.PacketPlayerDataNotify
;
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.PacketSetNameCardRsp
;
import
emu.grasscutter.server.packet.send.PacketStoreWeightLimitNotify
;
import
emu.grasscutter.server.packet.send.PacketUnlockNameCardNotify
;
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
;
@Entity
(
value
=
"players"
,
noClassnameStored
=
true
)
public
class
GenshinPlayer
{
@Id
private
int
id
;
@Indexed
(
options
=
@IndexOptions
(
unique
=
true
))
private
String
accountId
;
@Transient
private
Account
account
;
private
String
nickname
;
private
String
signature
;
private
int
headImage
;
private
int
nameCardId
=
210001
;
private
Position
pos
;
private
Position
rotation
;
private
Map
<
Integer
,
Integer
>
properties
;
private
Set
<
Integer
>
nameCardList
;
private
Set
<
Integer
>
flyCloakList
;
private
Set
<
Integer
>
costumeList
;
@Transient
private
long
nextGuid
=
0
;
@Transient
private
int
peerId
;
@Transient
private
World
world
;
@Transient
private
GameSession
session
;
@Transient
private
AvatarStorage
avatars
;
@Transient
private
Inventory
inventory
;
@Transient
private
FriendsList
friendsList
;
private
TeamManager
teamManager
;
private
PlayerGachaInfo
gachaInfo
;
private
PlayerProfile
playerProfile
;
private
MpSettingType
mpSetting
=
MpSettingType
.
MpSettingEnterAfterApply
;
private
boolean
showAvatar
;
private
ArrayList
<
AvatarProfileData
>
shownAvatars
;
private
int
sceneId
;
private
int
regionId
;
private
int
mainCharacterId
;
private
boolean
godmode
;
@Transient
private
boolean
paused
;
@Transient
private
int
enterSceneToken
;
@Transient
private
SceneLoadState
sceneState
;
@Transient
private
boolean
hasSentAvatarDataNotify
;
@Transient
private
final
Int2ObjectMap
<
CoopRequest
>
coopRequests
;
@Transient
private
final
InvokeHandler
<
CombatInvokeEntry
>
combatInvokeHandler
;
@Transient
private
final
InvokeHandler
<
AbilityInvokeEntry
>
abilityInvokeHandler
;
@Deprecated
@SuppressWarnings
({
"rawtypes"
,
"unchecked"
})
// Morphia only!
public
GenshinPlayer
()
{
this
.
inventory
=
new
Inventory
(
this
);
this
.
avatars
=
new
AvatarStorage
(
this
);
this
.
friendsList
=
new
FriendsList
(
this
);
this
.
pos
=
new
Position
();
this
.
rotation
=
new
Position
();
this
.
properties
=
new
HashMap
<>();
for
(
PlayerProperty
prop
:
PlayerProperty
.
values
())
{
if
(
prop
.
getId
()
<
10000
)
{
continue
;
}
this
.
properties
.
put
(
prop
.
getId
(),
0
);
}
this
.
setSceneId
(
3
);
this
.
setRegionId
(
1
);
this
.
sceneState
=
SceneLoadState
.
NONE
;
this
.
coopRequests
=
new
Int2ObjectOpenHashMap
<>();
this
.
combatInvokeHandler
=
new
InvokeHandler
(
PacketCombatInvocationsNotify
.
class
);
this
.
abilityInvokeHandler
=
new
InvokeHandler
(
PacketAbilityInvocationsNotify
.
class
);
}
// On player creation
public
GenshinPlayer
(
GameSession
session
)
{
this
();
this
.
account
=
session
.
getAccount
();
this
.
accountId
=
this
.
getAccount
().
getId
();
this
.
session
=
session
;
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
);
this
.
setProperty
(
PlayerProperty
.
PROP_IS_FLYABLE
,
1
);
this
.
setProperty
(
PlayerProperty
.
PROP_IS_TRANSFERABLE
,
1
);
this
.
setProperty
(
PlayerProperty
.
PROP_MAX_STAMINA
,
24000
);
this
.
setProperty
(
PlayerProperty
.
PROP_CUR_PERSIST_STAMINA
,
24000
);
this
.
setProperty
(
PlayerProperty
.
PROP_PLAYER_RESIN
,
160
);
this
.
getFlyCloakList
().
add
(
140001
);
this
.
getNameCardList
().
add
(
210001
);
this
.
getPos
().
set
(
GenshinConstants
.
START_POSITION
);
this
.
getRotation
().
set
(
0
,
307
,
0
);
}
public
int
getId
()
{
return
id
;
}
public
void
setId
(
int
id
)
{
this
.
id
=
id
;
}
public
long
getNextGuid
()
{
long
nextId
=
++
this
.
nextGuid
;
return
((
long
)
this
.
getId
()
<<
32
)
+
nextId
;
}
public
Account
getAccount
()
{
return
account
;
}
public
void
setAccount
(
Account
account
)
{
this
.
account
=
account
;
this
.
account
.
setPlayerId
(
getId
());
}
public
GameSession
getSession
()
{
return
session
;
}
public
void
setSession
(
GameSession
session
)
{
this
.
session
=
session
;
}
public
boolean
isOnline
()
{
return
this
.
getSession
()
!=
null
&&
this
.
getSession
().
isActive
();
}
public
GameServer
getServer
()
{
return
this
.
getSession
().
getServer
();
}
public
synchronized
World
getWorld
()
{
return
this
.
world
;
}
public
synchronized
void
setWorld
(
World
world
)
{
this
.
world
=
world
;
}
public
int
getGmLevel
()
{
return
1
;
}
public
String
getNickname
()
{
return
nickname
;
}
public
void
setNickname
(
String
nickName
)
{
this
.
nickname
=
nickName
;
this
.
updateProfile
();
}
public
int
getHeadImage
()
{
return
headImage
;
}
public
void
setHeadImage
(
int
picture
)
{
this
.
headImage
=
picture
;
this
.
updateProfile
();
}
public
String
getSignature
()
{
return
signature
;
}
public
void
setSignature
(
String
signature
)
{
this
.
signature
=
signature
;
this
.
updateProfile
();
}
public
Position
getPos
()
{
return
pos
;
}
public
Position
getRotation
()
{
return
rotation
;
}
public
int
getLevel
()
{
return
this
.
getProperty
(
PlayerProperty
.
PROP_PLAYER_LEVEL
);
}
public
int
getExp
()
{
return
this
.
getProperty
(
PlayerProperty
.
PROP_PLAYER_EXP
);
}
public
int
getWorldLevel
()
{
return
this
.
getProperty
(
PlayerProperty
.
PROP_PLAYER_WORLD_LEVEL
);
}
public
int
getPrimogems
()
{
return
this
.
getProperty
(
PlayerProperty
.
PROP_PLAYER_HCOIN
);
}
public
void
setPrimogems
(
int
primogem
)
{
this
.
setProperty
(
PlayerProperty
.
PROP_PLAYER_HCOIN
,
primogem
);
this
.
sendPacket
(
new
PacketPlayerPropNotify
(
this
,
PlayerProperty
.
PROP_PLAYER_HCOIN
));
}
public
int
getMora
()
{
return
this
.
getProperty
(
PlayerProperty
.
PROP_PLAYER_SCOIN
);
}
public
void
setMora
(
int
mora
)
{
this
.
setProperty
(
PlayerProperty
.
PROP_PLAYER_SCOIN
,
mora
);
this
.
sendPacket
(
new
PacketPlayerPropNotify
(
this
,
PlayerProperty
.
PROP_PLAYER_SCOIN
));
}
private
int
getExpRequired
(
int
level
)
{
PlayerLevelData
levelData
=
GenshinData
.
getPlayerLevelDataMap
().
get
(
level
);
return
levelData
!=
null
?
levelData
.
getExp
()
:
0
;
}
private
float
getExpModifier
()
{
return
Grasscutter
.
getConfig
().
getGameRates
().
ADVENTURE_EXP_RATE
;
}
// Affected by exp rate
public
void
earnExp
(
int
exp
)
{
addExpDirectly
((
int
)
(
exp
*
getExpModifier
()));
}
// Directly give player exp
public
void
addExpDirectly
(
int
gain
)
{
boolean
hasLeveledUp
=
false
;
int
level
=
getLevel
();
int
exp
=
getExp
();
int
reqExp
=
getExpRequired
(
level
);
exp
+=
gain
;
while
(
exp
>=
reqExp
&&
reqExp
>
0
)
{
exp
-=
reqExp
;
level
+=
1
;
reqExp
=
getExpRequired
(
level
);
hasLeveledUp
=
true
;
}
if
(
hasLeveledUp
)
{
// Set level property
this
.
setProperty
(
PlayerProperty
.
PROP_PLAYER_LEVEL
,
level
);
// Update social status
this
.
updateProfile
();
// Update player with packet
this
.
sendPacket
(
new
PacketPlayerPropNotify
(
this
,
PlayerProperty
.
PROP_PLAYER_LEVEL
));
}
// Set exp
this
.
setProperty
(
PlayerProperty
.
PROP_PLAYER_EXP
,
exp
);
// Update player with packet
this
.
sendPacket
(
new
PacketPlayerPropNotify
(
this
,
PlayerProperty
.
PROP_PLAYER_EXP
));
}
private
void
updateProfile
()
{
getProfile
().
syncWithCharacter
(
this
);
}
public
boolean
isFirstLoginEnterScene
()
{
return
!
this
.
hasSentAvatarDataNotify
;
}
public
TeamManager
getTeamManager
()
{
return
this
.
teamManager
;
}
public
PlayerGachaInfo
getGachaInfo
()
{
return
gachaInfo
;
}
public
PlayerProfile
getProfile
()
{
if
(
this
.
playerProfile
==
null
)
{
this
.
playerProfile
=
new
PlayerProfile
(
this
);
this
.
save
();
}
return
playerProfile
;
}
public
Map
<
Integer
,
Integer
>
getProperties
()
{
return
properties
;
}
public
void
setProperty
(
PlayerProperty
prop
,
int
value
)
{
getProperties
().
put
(
prop
.
getId
(),
value
);
}
public
int
getProperty
(
PlayerProperty
prop
)
{
return
getProperties
().
get
(
prop
.
getId
());
}
public
Set
<
Integer
>
getFlyCloakList
()
{
return
flyCloakList
;
}
public
Set
<
Integer
>
getCostumeList
()
{
return
costumeList
;
}
public
Set
<
Integer
>
getNameCardList
()
{
return
this
.
nameCardList
;
}
public
MpSettingType
getMpSetting
()
{
return
mpSetting
;
}
public
synchronized
Int2ObjectMap
<
CoopRequest
>
getCoopRequests
()
{
return
coopRequests
;
}
public
InvokeHandler
<
CombatInvokeEntry
>
getCombatInvokeHandler
()
{
return
this
.
combatInvokeHandler
;
}
public
InvokeHandler
<
AbilityInvokeEntry
>
getAbilityInvokeHandler
()
{
return
this
.
abilityInvokeHandler
;
}
public
void
setMpSetting
(
MpSettingType
mpSetting
)
{
this
.
mpSetting
=
mpSetting
;
}
public
AvatarStorage
getAvatars
()
{
return
avatars
;
}
public
Inventory
getInventory
()
{
return
inventory
;
}
public
FriendsList
getFriendsList
()
{
return
this
.
friendsList
;
}
public
int
getEnterSceneToken
()
{
return
enterSceneToken
;
}
public
void
setEnterSceneToken
(
int
enterSceneToken
)
{
this
.
enterSceneToken
=
enterSceneToken
;
}
public
int
getNameCardId
()
{
return
nameCardId
;
}
public
void
setNameCardId
(
int
nameCardId
)
{
this
.
nameCardId
=
nameCardId
;
this
.
updateProfile
();
}
public
int
getMainCharacterId
()
{
return
mainCharacterId
;
}
public
void
setMainCharacterId
(
int
mainCharacterId
)
{
this
.
mainCharacterId
=
mainCharacterId
;
}
public
int
getPeerId
()
{
return
peerId
;
}
public
void
setPeerId
(
int
peerId
)
{
this
.
peerId
=
peerId
;
}
public
int
getClientTime
()
{
return
session
.
getClientTime
();
}
public
long
getLastPingTime
()
{
return
session
.
getLastPingTime
();
}
public
boolean
isPaused
()
{
return
paused
;
}
public
void
setPaused
(
boolean
newPauseState
)
{
boolean
oldPauseState
=
this
.
paused
;
this
.
paused
=
newPauseState
;
if
(
newPauseState
&&
!
oldPauseState
)
{
this
.
onPause
();
}
else
if
(
oldPauseState
&&
!
newPauseState
)
{
this
.
onUnpause
();
}
}
public
SceneLoadState
getSceneLoadState
()
{
return
sceneState
;
}
public
void
setSceneLoadState
(
SceneLoadState
sceneState
)
{
this
.
sceneState
=
sceneState
;
}
public
boolean
isInMultiplayer
()
{
return
this
.
getWorld
()
!=
null
&&
this
.
getWorld
().
isMultiplayer
();
}
public
int
getSceneId
()
{
return
sceneId
;
}
public
void
setSceneId
(
int
sceneId
)
{
this
.
sceneId
=
sceneId
;
}
public
int
getRegionId
()
{
return
regionId
;
}
public
void
setRegionId
(
int
regionId
)
{
this
.
regionId
=
regionId
;
}
public
boolean
hasGodmode
()
{
return
godmode
;
}
public
void
setGodmode
(
boolean
godmode
)
{
this
.
godmode
=
godmode
;
}
public
boolean
hasSentAvatarDataNotify
()
{
return
hasSentAvatarDataNotify
;
}
public
void
setHasSentAvatarDataNotify
(
boolean
hasSentAvatarDataNotify
)
{
this
.
hasSentAvatarDataNotify
=
hasSentAvatarDataNotify
;
}
public
void
addAvatar
(
GenshinAvatar
avatar
)
{
boolean
result
=
getAvatars
().
addAvatar
(
avatar
);
if
(
result
)
{
// Add starting weapon
getAvatars
().
addStartingWeapon
(
avatar
);
// Try adding to team if possible
//List<EntityAvatar> currentTeam = this.getTeamManager().getCurrentTeam();
boolean
addedToTeam
=
false
;
/*
if (currentTeam.size() <= GenshinConstants.MAX_AVATARS_IN_TEAM) {
addedToTeam = currentTeam
}
*/
// Done
if
(
hasSentAvatarDataNotify
())
{
// Recalc stats
avatar
.
recalcStats
();
// Packet
sendPacket
(
new
PacketAvatarAddNotify
(
avatar
,
addedToTeam
));
}
}
else
{
// Failed adding avatar
}
}
public
void
addFlycloak
(
int
flycloakId
)
{
this
.
getFlyCloakList
().
add
(
flycloakId
);
this
.
sendPacket
(
new
PacketAvatarGainFlycloakNotify
(
flycloakId
));
}
public
void
addCostume
(
int
costumeId
)
{
this
.
getCostumeList
().
add
(
costumeId
);
this
.
sendPacket
(
new
PacketAvatarGainCostumeNotify
(
costumeId
));
}
public
void
addNameCard
(
int
nameCardId
)
{
this
.
getNameCardList
().
add
(
nameCardId
);
this
.
sendPacket
(
new
PacketUnlockNameCardNotify
(
nameCardId
));
}
public
void
setNameCard
(
int
nameCardId
)
{
if
(!
this
.
getNameCardList
().
contains
(
nameCardId
))
{
return
;
}
this
.
setNameCardId
(
nameCardId
);
this
.
sendPacket
(
new
PacketSetNameCardRsp
(
nameCardId
));
}
public
void
dropMessage
(
Object
message
)
{
this
.
sendPacket
(
new
PacketPrivateChatNotify
(
GenshinConstants
.
SERVER_CONSOLE_UID
,
getId
(),
message
.
toString
()));
}
public
void
interactWith
(
int
gadgetEntityId
)
{
GenshinEntity
entity
=
getWorld
().
getEntityById
(
gadgetEntityId
);
if
(
entity
==
null
)
{
return
;
}
// Delete
entity
.
getWorld
().
removeEntity
(
entity
);
// Handle
if
(
entity
instanceof
EntityItem
)
{
// Pick item
EntityItem
drop
=
(
EntityItem
)
entity
;
GenshinItem
item
=
new
GenshinItem
(
drop
.
getItemData
(),
drop
.
getCount
());
// Add to inventory
boolean
success
=
getInventory
().
addItem
(
item
);
if
(
success
)
{
this
.
sendPacket
(
new
PacketGadgetInteractRsp
(
drop
,
InteractType
.
InteractPickItem
));
this
.
sendPacket
(
new
PacketItemAddHintNotify
(
item
,
ActionReason
.
SubfieldDrop
));
}
}
return
;
}
public
void
onPause
()
{
}
public
void
onUnpause
()
{
}
public
void
sendPacket
(
GenshinPacket
packet
)
{
if
(
this
.
hasSentAvatarDataNotify
)
{
this
.
getSession
().
send
(
packet
);
}
}
public
OnlinePlayerInfo
getOnlinePlayerInfo
()
{
OnlinePlayerInfo
.
Builder
onlineInfo
=
OnlinePlayerInfo
.
newBuilder
()
.
setUid
(
this
.
getId
())
.
setNickname
(
this
.
getNickname
())
.
setPlayerLevel
(
this
.
getLevel
())
.
setMpSettingType
(
this
.
getMpSetting
())
.
setNameCardId
(
this
.
getNameCardId
())
.
setSignature
(
this
.
getSignature
())
.
setAvatar
(
HeadImage
.
newBuilder
().
setAvatarId
(
this
.
getHeadImage
()));
if
(
this
.
getWorld
()
!=
null
)
{
onlineInfo
.
setCurPlayerNumInWorld
(
this
.
getWorld
().
getPlayers
().
indexOf
(
this
)
+
1
);
}
else
{
onlineInfo
.
setCurPlayerNumInWorld
(
1
);
}
return
onlineInfo
.
build
();
}
public
SocialDetail
.
Builder
getSocialDetail
()
{
SocialDetail
.
Builder
social
=
SocialDetail
.
newBuilder
()
.
setUid
(
this
.
getId
())
.
setAvatar
(
HeadImage
.
newBuilder
().
setAvatarId
(
this
.
getHeadImage
()))
.
setNickname
(
this
.
getNickname
())
.
setSignature
(
this
.
getSignature
())
.
setLevel
(
this
.
getLevel
())
.
setBirthday
(
Birthday
.
newBuilder
())
.
setWorldLevel
(
this
.
getWorldLevel
())
.
setUnk1
(
1
)
.
setUnk3
(
1
)
.
setNameCardId
(
this
.
getNameCardId
())
.
setFinishAchievementNum
(
0
);
return
social
;
}
public
PlayerLocationInfo
getPlayerLocationInfo
()
{
return
PlayerLocationInfo
.
newBuilder
()
.
setUid
(
this
.
getId
())
.
setPos
(
this
.
getPos
().
toProto
())
.
setRot
(
this
.
getRotation
().
toProto
())
.
build
();
}
public
synchronized
void
onTick
()
{
// Check ping
if
(
this
.
getLastPingTime
()
>
System
.
currentTimeMillis
()
+
60000
)
{
this
.
getSession
().
close
();
return
;
}
// Check co-op requests
Iterator
<
CoopRequest
>
it
=
this
.
getCoopRequests
().
values
().
iterator
();
while
(
it
.
hasNext
())
{
CoopRequest
req
=
it
.
next
();
if
(
req
.
isExpired
())
{
req
.
getRequester
().
sendPacket
(
new
PacketPlayerApplyEnterMpResultNotify
(
this
,
false
,
PlayerApplyEnterMpReason
.
SystemJudge
));
it
.
remove
();
}
}
// Ping
if
(
this
.
getWorld
()
!=
null
)
{
this
.
sendPacket
(
new
PacketWorldPlayerRTTNotify
(
this
.
getWorld
()));
// Player ping
}
}
@PostLoad
private
void
onLoad
()
{
this
.
getTeamManager
().
setPlayer
(
this
);
}
public
void
save
()
{
DatabaseHelper
.
savePlayer
(
this
);
}
public
void
onLogin
()
{
// 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
<>();
}
// Check if player object exists in server
// TODO - optimize
GenshinPlayer
exists
=
this
.
getServer
().
getPlayerById
(
getId
());
if
(
exists
!=
null
)
{
exists
.
getSession
().
close
();
}
// Load from db
this
.
getAvatars
().
loadFromDatabase
();
this
.
getInventory
().
loadFromDatabase
();
this
.
getAvatars
().
postLoad
();
this
.
getFriendsList
().
loadFromDatabase
();
// Create world
World
world
=
new
World
(
this
);
world
.
addPlayer
(
this
);
// Add to gameserver
if
(
getSession
().
isActive
())
{
getServer
().
registerPlayer
(
this
);
getProfile
().
setPlayer
(
this
);
// Set online
}
// Multiplayer setting
this
.
setProperty
(
PlayerProperty
.
PROP_PLAYER_MP_SETTING_TYPE
,
this
.
getMpSetting
().
getNumber
());
this
.
setProperty
(
PlayerProperty
.
PROP_IS_MP_MODE_AVAILABLE
,
1
);
// Packets
session
.
send
(
new
PacketPlayerDataNotify
(
this
));
// Player data
session
.
send
(
new
PacketStoreWeightLimitNotify
());
session
.
send
(
new
PacketPlayerStoreNotify
(
this
));
session
.
send
(
new
PacketAvatarDataNotify
(
this
));
session
.
send
(
new
PacketPlayerEnterSceneNotify
(
this
));
// Enter game world
session
.
send
(
new
PacketOpenStateUpdateNotify
());
// First notify packets sent
this
.
setHasSentAvatarDataNotify
(
true
);
}
public
void
onLogout
()
{
// Leave world
if
(
this
.
getWorld
()
!=
null
)
{
this
.
getWorld
().
removePlayer
(
this
);
}
// Status stuff
this
.
getProfile
().
syncWithCharacter
(
this
);
this
.
getProfile
().
setPlayer
(
null
);
// Set offline
this
.
getCoopRequests
().
clear
();
// Save to db
this
.
save
();
this
.
getTeamManager
().
saveAvatars
();
this
.
getFriendsList
().
save
();
}
public
enum
SceneLoadState
{
NONE
(
0
),
LOADING
(
1
),
INIT
(
2
),
LOADED
(
3
);
private
final
int
value
;
private
SceneLoadState
(
int
value
)
{
this
.
value
=
value
;
}
public
int
getValue
()
{
return
this
.
value
;
}
}
}
src/main/java/emu/grasscutter/game/InvokeHandler.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game
;
import
java.util.ArrayList
;
import
java.util.List
;
import
emu.grasscutter.net.packet.GenshinPacket
;
import
emu.grasscutter.net.proto.ForwardTypeOuterClass.ForwardType
;
public
class
InvokeHandler
<
T
>
{
private
final
List
<
T
>
entryListForwardAll
;
private
final
List
<
T
>
entryListForwardAllExceptCur
;
private
final
List
<
T
>
entryListForwardHost
;
private
final
Class
<?
extends
GenshinPacket
>
packetClass
;
public
InvokeHandler
(
Class
<?
extends
GenshinPacket
>
packetClass
)
{
this
.
entryListForwardAll
=
new
ArrayList
<>();
this
.
entryListForwardAllExceptCur
=
new
ArrayList
<>();
this
.
entryListForwardHost
=
new
ArrayList
<>();
this
.
packetClass
=
packetClass
;
}
public
synchronized
void
addEntry
(
ForwardType
forward
,
T
entry
)
{
switch
(
forward
)
{
case
ForwardToAll:
entryListForwardAll
.
add
(
entry
);
break
;
case
ForwardToAllExceptCur:
case
ForwardToAllExistExceptCur:
entryListForwardAllExceptCur
.
add
(
entry
);
break
;
case
ForwardToHost:
entryListForwardHost
.
add
(
entry
);
break
;
default
:
break
;
}
}
public
synchronized
void
update
(
GenshinPlayer
player
)
{
if
(
player
.
getWorld
()
==
null
)
{
this
.
entryListForwardAll
.
clear
();
this
.
entryListForwardAllExceptCur
.
clear
();
this
.
entryListForwardHost
.
clear
();
return
;
}
try
{
if
(
entryListForwardAll
.
size
()
>
0
)
{
GenshinPacket
packet
=
packetClass
.
getDeclaredConstructor
(
List
.
class
).
newInstance
(
this
.
entryListForwardAll
);
player
.
getWorld
().
broadcastPacket
(
packet
);
this
.
entryListForwardAll
.
clear
();
}
if
(
entryListForwardAllExceptCur
.
size
()
>
0
)
{
GenshinPacket
packet
=
packetClass
.
getDeclaredConstructor
(
List
.
class
).
newInstance
(
this
.
entryListForwardAllExceptCur
);
player
.
getWorld
().
broadcastPacketToOthers
(
player
,
packet
);
this
.
entryListForwardAllExceptCur
.
clear
();
}
if
(
entryListForwardHost
.
size
()
>
0
)
{
GenshinPacket
packet
=
packetClass
.
getDeclaredConstructor
(
List
.
class
).
newInstance
(
this
.
entryListForwardHost
);
player
.
getWorld
().
getHost
().
sendPacket
(
packet
);
this
.
entryListForwardHost
.
clear
();
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
}
src/main/java/emu/grasscutter/game/TeamInfo.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game
;
import
java.util.ArrayList
;
import
java.util.List
;
import
emu.grasscutter.GenshinConstants
;
import
emu.grasscutter.game.avatar.GenshinAvatar
;
public
class
TeamInfo
{
private
String
name
;
private
List
<
Integer
>
avatars
;
public
TeamInfo
()
{
this
.
name
=
""
;
this
.
avatars
=
new
ArrayList
<>(
GenshinConstants
.
MAX_AVATARS_IN_TEAM
);
}
public
String
getName
()
{
return
name
;
}
public
void
setName
(
String
name
)
{
this
.
name
=
name
;
}
public
List
<
Integer
>
getAvatars
()
{
return
avatars
;
}
public
int
size
()
{
return
avatars
.
size
();
}
public
boolean
contains
(
GenshinAvatar
avatar
)
{
return
getAvatars
().
contains
(
avatar
.
getAvatarId
());
}
public
boolean
addAvatar
(
GenshinAvatar
avatar
)
{
if
(
size
()
>=
GenshinConstants
.
MAX_AVATARS_IN_TEAM
||
contains
(
avatar
))
{
return
false
;
}
getAvatars
().
add
(
avatar
.
getAvatarId
());
return
true
;
}
public
boolean
removeAvatar
(
int
slot
)
{
if
(
size
()
<=
1
)
{
return
false
;
}
getAvatars
().
remove
(
slot
);
return
true
;
}
public
void
copyFrom
(
TeamInfo
team
)
{
copyFrom
(
team
,
GenshinConstants
.
MAX_AVATARS_IN_TEAM
);
}
public
void
copyFrom
(
TeamInfo
team
,
int
maxTeamSize
)
{
// Clear
this
.
getAvatars
().
clear
();
// Copy from team
int
len
=
Math
.
min
(
team
.
getAvatars
().
size
(),
maxTeamSize
);
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
int
id
=
team
.
getAvatars
().
get
(
i
);
this
.
getAvatars
().
add
(
id
);
}
}
}
src/main/java/emu/grasscutter/game/TeamManager.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.LinkedHashSet
;
import
java.util.List
;
import
java.util.Map
;
import
dev.morphia.annotations.Transient
;
import
emu.grasscutter.GenshinConstants
;
import
emu.grasscutter.data.def.AvatarSkillDepotData
;
import
emu.grasscutter.game.avatar.GenshinAvatar
;
import
emu.grasscutter.game.entity.EntityAvatar
;
import
emu.grasscutter.game.entity.EntityGadget
;
import
emu.grasscutter.game.props.ElementType
;
import
emu.grasscutter.game.props.EnterReason
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.net.packet.GenshinPacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType
;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.server.packet.send.PacketAvatarDieAnimationEndRsp
;
import
emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketAvatarLifeStateChangeNotify
;
import
emu.grasscutter.server.packet.send.PacketAvatarTeamUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketChangeAvatarRsp
;
import
emu.grasscutter.server.packet.send.PacketChangeMpTeamAvatarRsp
;
import
emu.grasscutter.server.packet.send.PacketChangeTeamNameRsp
;
import
emu.grasscutter.server.packet.send.PacketChooseCurAvatarTeamRsp
;
import
emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify
;
import
emu.grasscutter.server.packet.send.PacketSceneTeamUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketSetUpAvatarTeamRsp
;
import
emu.grasscutter.server.packet.send.PacketWorldPlayerDieNotify
;
import
it.unimi.dsi.fastutil.ints.Int2IntMap
;
import
it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.IntOpenHashSet
;
import
it.unimi.dsi.fastutil.ints.IntSet
;
public
class
TeamManager
{
@Transient
private
GenshinPlayer
player
;
private
Map
<
Integer
,
TeamInfo
>
teams
;
private
int
currentTeamIndex
;
private
int
currentCharacterIndex
;
@Transient
private
TeamInfo
mpTeam
;
@Transient
private
int
entityId
;
@Transient
private
final
List
<
EntityAvatar
>
avatars
;
@Transient
private
final
List
<
EntityGadget
>
gadgets
;
@Transient
private
final
IntSet
teamResonances
;
@Transient
private
final
IntSet
teamResonancesConfig
;
public
TeamManager
()
{
this
.
mpTeam
=
new
TeamInfo
();
this
.
avatars
=
new
ArrayList
<>();
this
.
gadgets
=
new
ArrayList
<>();
this
.
teamResonances
=
new
IntOpenHashSet
();
this
.
teamResonancesConfig
=
new
IntOpenHashSet
();
}
public
TeamManager
(
GenshinPlayer
player
)
{
this
();
this
.
player
=
player
;
this
.
teams
=
new
HashMap
<>();
this
.
currentTeamIndex
=
1
;
for
(
int
i
=
1
;
i
<=
GenshinConstants
.
MAX_TEAMS
;
i
++)
{
this
.
teams
.
put
(
i
,
new
TeamInfo
());
}
}
public
GenshinPlayer
getPlayer
()
{
return
player
;
}
public
World
getWorld
()
{
return
player
.
getWorld
();
}
public
void
setPlayer
(
GenshinPlayer
player
)
{
this
.
player
=
player
;
}
public
Map
<
Integer
,
TeamInfo
>
getTeams
()
{
return
this
.
teams
;
}
public
TeamInfo
getMpTeam
()
{
return
mpTeam
;
}
public
void
setMpTeam
(
TeamInfo
mpTeam
)
{
this
.
mpTeam
=
mpTeam
;
}
public
int
getCurrentTeamId
()
{
// Starts from 1
return
currentTeamIndex
;
}
private
void
setCurrentTeamId
(
int
currentTeamIndex
)
{
this
.
currentTeamIndex
=
currentTeamIndex
;
}
public
int
getCurrentCharacterIndex
()
{
return
currentCharacterIndex
;
}
public
void
setCurrentCharacterIndex
(
int
currentCharacterIndex
)
{
this
.
currentCharacterIndex
=
currentCharacterIndex
;
}
public
long
getCurrentCharacterGuid
()
{
return
getCurrentAvatarEntity
().
getAvatar
().
getGuid
();
}
public
TeamInfo
getCurrentTeamInfo
()
{
if
(
this
.
getPlayer
().
isInMultiplayer
())
{
return
this
.
getMpTeam
();
}
return
this
.
getTeams
().
get
(
this
.
currentTeamIndex
);
}
public
TeamInfo
getCurrentSinglePlayerTeamInfo
()
{
return
this
.
getTeams
().
get
(
this
.
currentTeamIndex
);
}
public
int
getEntityId
()
{
return
entityId
;
}
public
void
setEntityId
(
int
entityId
)
{
this
.
entityId
=
entityId
;
}
public
IntSet
getTeamResonances
()
{
return
teamResonances
;
}
public
IntSet
getTeamResonancesConfig
()
{
return
teamResonancesConfig
;
}
public
List
<
EntityAvatar
>
getActiveTeam
()
{
return
avatars
;
}
public
EntityAvatar
getCurrentAvatarEntity
()
{
return
getActiveTeam
().
get
(
currentCharacterIndex
);
}
public
boolean
isSpawned
()
{
return
getPlayer
().
getWorld
()
!=
null
&&
getPlayer
().
getWorld
().
getEntities
().
containsKey
(
getCurrentAvatarEntity
().
getId
());
}
public
int
getMaxTeamSize
()
{
if
(
getPlayer
().
isInMultiplayer
())
{
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
.
floor
(
GenshinConstants
.
MAX_AVATARS_IN_TEAM
/
(
double
)
getWorld
().
getPlayerCount
()));
}
return
GenshinConstants
.
MAX_AVATARS_IN_TEAM
;
}
// Methods
public
void
updateTeamResonances
()
{
Int2IntOpenHashMap
map
=
new
Int2IntOpenHashMap
();
this
.
getTeamResonances
().
clear
();
this
.
getTeamResonancesConfig
().
clear
();
for
(
EntityAvatar
entity
:
getActiveTeam
())
{
AvatarSkillDepotData
skillData
=
entity
.
getAvatar
().
getAvatarData
().
getSkillDepot
();
if
(
skillData
!=
null
)
{
map
.
addTo
(
skillData
.
getElementType
().
getValue
(),
1
);
}
}
for
(
Int2IntMap
.
Entry
e
:
map
.
int2IntEntrySet
())
{
if
(
e
.
getIntValue
()
>=
2
)
{
ElementType
element
=
ElementType
.
getTypeByValue
(
e
.
getIntKey
());
if
(
element
.
getTeamResonanceId
()
!=
0
)
{
this
.
getTeamResonances
().
add
(
element
.
getTeamResonanceId
());
this
.
getTeamResonancesConfig
().
add
(
element
.
getConfigHash
());
}
}
}
// No resonances
if
(
this
.
getTeamResonances
().
size
()
==
0
)
{
this
.
getTeamResonances
().
add
(
ElementType
.
Default
.
getTeamResonanceId
());
this
.
getTeamResonancesConfig
().
add
(
ElementType
.
Default
.
getTeamResonanceId
());
}
}
private
void
updateTeamEntities
(
GenshinPacket
responsePacket
)
{
// Sanity check - Should never happen
if
(
this
.
getCurrentTeamInfo
().
getAvatars
().
size
()
<=
0
)
{
return
;
}
// If current team has changed
EntityAvatar
currentEntity
=
this
.
getCurrentAvatarEntity
();
Int2ObjectMap
<
EntityAvatar
>
existingAvatars
=
new
Int2ObjectOpenHashMap
<>();
int
prevSelectedAvatarIndex
=
-
1
;
for
(
EntityAvatar
entity
:
getActiveTeam
())
{
existingAvatars
.
put
(
entity
.
getAvatar
().
getAvatarId
(),
entity
);
}
// Clear active team entity list
this
.
getActiveTeam
().
clear
();
// Add back entities into team
for
(
int
i
=
0
;
i
<
this
.
getCurrentTeamInfo
().
getAvatars
().
size
();
i
++)
{
int
avatarId
=
this
.
getCurrentTeamInfo
().
getAvatars
().
get
(
i
);
EntityAvatar
entity
=
null
;
if
(
existingAvatars
.
containsKey
(
avatarId
))
{
entity
=
existingAvatars
.
get
(
avatarId
);
existingAvatars
.
remove
(
avatarId
);
if
(
entity
==
currentEntity
)
{
prevSelectedAvatarIndex
=
i
;
}
}
else
{
entity
=
new
EntityAvatar
(
getPlayer
().
getWorld
(),
getPlayer
().
getAvatars
().
getAvatarById
(
avatarId
));
}
this
.
getActiveTeam
().
add
(
entity
);
}
// Unload removed entities
for
(
EntityAvatar
entity
:
existingAvatars
.
values
())
{
getPlayer
().
getWorld
().
removeEntity
(
entity
);
entity
.
getAvatar
().
save
();
}
// Set new selected character index
if
(
prevSelectedAvatarIndex
==
-
1
)
{
// Previous selected avatar is not in the same spot, we will select the current one in the prev slot
prevSelectedAvatarIndex
=
Math
.
min
(
this
.
currentCharacterIndex
,
getCurrentTeamInfo
().
getAvatars
().
size
()
-
1
);
}
this
.
currentCharacterIndex
=
prevSelectedAvatarIndex
;
// Update team resonances
updateTeamResonances
();
// Packets
getPlayer
().
getWorld
().
broadcastPacket
(
new
PacketSceneTeamUpdateNotify
(
getPlayer
()));
// Run callback
if
(
responsePacket
!=
null
)
{
getPlayer
().
sendPacket
(
responsePacket
);
}
// Check if character changed
if
(
currentEntity
!=
getCurrentAvatarEntity
())
{
// Remove and Add
getWorld
().
replaceEntity
(
currentEntity
,
getCurrentAvatarEntity
());
}
}
public
synchronized
void
setupAvatarTeam
(
int
teamId
,
List
<
Long
>
list
)
{
// Sanity checks
if
(
list
.
size
()
==
0
||
list
.
size
()
>
getMaxTeamSize
()
||
getPlayer
().
isInMultiplayer
())
{
return
;
}
// Get team
TeamInfo
teamInfo
=
this
.
getTeams
().
get
(
teamId
);
if
(
teamInfo
==
null
)
{
return
;
}
// Set team data
LinkedHashSet
<
GenshinAvatar
>
newTeam
=
new
LinkedHashSet
<>();
for
(
int
i
=
0
;
i
<
list
.
size
();
i
++)
{
GenshinAvatar
avatar
=
getPlayer
().
getAvatars
().
getAvatarByGuid
(
list
.
get
(
i
));
if
(
avatar
==
null
||
newTeam
.
contains
(
avatar
))
{
// Should never happen
return
;
}
newTeam
.
add
(
avatar
);
}
// Clear current team info and add avatars from our new team
teamInfo
.
getAvatars
().
clear
();
for
(
GenshinAvatar
avatar
:
newTeam
)
{
teamInfo
.
addAvatar
(
avatar
);
}
// Update packet
getPlayer
().
sendPacket
(
new
PacketAvatarTeamUpdateNotify
(
getPlayer
()));
// Update entites
if
(
teamId
==
this
.
getCurrentTeamId
())
{
this
.
updateTeamEntities
(
new
PacketSetUpAvatarTeamRsp
(
getPlayer
(),
teamId
,
teamInfo
));
}
else
{
getPlayer
().
sendPacket
(
new
PacketSetUpAvatarTeamRsp
(
getPlayer
(),
teamId
,
teamInfo
));
}
}
public
void
setupMpTeam
(
List
<
Long
>
list
)
{
// Sanity checks
if
(
list
.
size
()
==
0
||
list
.
size
()
>
getMaxTeamSize
()
||
!
getPlayer
().
isInMultiplayer
())
{
return
;
}
TeamInfo
teamInfo
=
this
.
getMpTeam
();
// Set team data
LinkedHashSet
<
GenshinAvatar
>
newTeam
=
new
LinkedHashSet
<>();
for
(
int
i
=
0
;
i
<
list
.
size
();
i
++)
{
GenshinAvatar
avatar
=
getPlayer
().
getAvatars
().
getAvatarByGuid
(
list
.
get
(
i
));
if
(
avatar
==
null
||
newTeam
.
contains
(
avatar
))
{
// Should never happen
return
;
}
newTeam
.
add
(
avatar
);
}
// Clear current team info and add avatars from our new team
teamInfo
.
getAvatars
().
clear
();
for
(
GenshinAvatar
avatar
:
newTeam
)
{
teamInfo
.
addAvatar
(
avatar
);
}
// Packet
this
.
updateTeamEntities
(
new
PacketChangeMpTeamAvatarRsp
(
getPlayer
(),
teamInfo
));
}
public
synchronized
void
setCurrentTeam
(
int
teamId
)
{
//
if
(
getPlayer
().
isInMultiplayer
())
{
return
;
}
// Get team
TeamInfo
teamInfo
=
this
.
getTeams
().
get
(
teamId
);
if
(
teamInfo
==
null
||
teamInfo
.
getAvatars
().
size
()
==
0
)
{
return
;
}
// Set
this
.
setCurrentTeamId
(
teamId
);
this
.
updateTeamEntities
(
new
PacketChooseCurAvatarTeamRsp
(
teamId
));
}
public
synchronized
void
setTeamName
(
int
teamId
,
String
teamName
)
{
// Get team
TeamInfo
teamInfo
=
this
.
getTeams
().
get
(
teamId
);
if
(
teamInfo
==
null
)
{
return
;
}
teamInfo
.
setName
(
teamName
);
// Packet
getPlayer
().
sendPacket
(
new
PacketChangeTeamNameRsp
(
teamId
,
teamName
));
}
public
synchronized
void
changeAvatar
(
long
guid
)
{
EntityAvatar
oldEntity
=
this
.
getCurrentAvatarEntity
();
if
(
guid
==
oldEntity
.
getAvatar
().
getGuid
())
{
return
;
}
EntityAvatar
newEntity
=
null
;
int
index
=
-
1
;
for
(
int
i
=
0
;
i
<
getActiveTeam
().
size
();
i
++)
{
if
(
guid
==
getActiveTeam
().
get
(
i
).
getAvatar
().
getGuid
())
{
index
=
i
;
newEntity
=
getActiveTeam
().
get
(
i
);
}
}
if
(
index
<
0
||
newEntity
==
oldEntity
)
{
return
;
}
// Set index
this
.
setCurrentCharacterIndex
(
index
);
// Old entity motion state
oldEntity
.
setMotionState
(
MotionState
.
MotionStandby
);
// Remove and Add
getWorld
().
replaceEntity
(
oldEntity
,
newEntity
);
getPlayer
().
sendPacket
(
new
PacketChangeAvatarRsp
(
guid
));
}
public
void
onAvatarDie
(
long
dieGuid
)
{
EntityAvatar
deadAvatar
=
this
.
getCurrentAvatarEntity
();
if
(
deadAvatar
.
isAlive
()
||
deadAvatar
.
getId
()
!=
dieGuid
)
{
return
;
}
// Replacement avatar
EntityAvatar
replacement
=
null
;
int
replaceIndex
=
-
1
;
for
(
int
i
=
0
;
i
<
this
.
getActiveTeam
().
size
();
i
++)
{
EntityAvatar
entity
=
this
.
getActiveTeam
().
get
(
i
);
if
(
entity
.
isAlive
())
{
replaceIndex
=
i
;
replacement
=
entity
;
break
;
}
}
if
(
replacement
==
null
)
{
// No more living team members...
getPlayer
().
sendPacket
(
new
PacketWorldPlayerDieNotify
(
deadAvatar
.
getKilledType
(),
deadAvatar
.
getKilledBy
()));
}
else
{
// Set index and spawn replacement member
this
.
setCurrentCharacterIndex
(
replaceIndex
);
getWorld
().
addEntity
(
replacement
);
}
// Response packet
getPlayer
().
sendPacket
(
new
PacketAvatarDieAnimationEndRsp
(
deadAvatar
.
getId
(),
0
));
}
public
boolean
reviveAvatar
(
GenshinAvatar
avatar
)
{
for
(
EntityAvatar
entity
:
getActiveTeam
())
{
if
(
entity
.
getAvatar
()
==
avatar
)
{
if
(
entity
.
isAlive
())
{
return
false
;
}
entity
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
)
*
.
1
f
);
getPlayer
().
sendPacket
(
new
PacketAvatarFightPropUpdateNotify
(
entity
.
getAvatar
(),
FightProperty
.
FIGHT_PROP_CUR_HP
));
getPlayer
().
sendPacket
(
new
PacketAvatarLifeStateChangeNotify
(
entity
.
getAvatar
()));
return
true
;
}
}
return
false
;
}
public
void
respawnTeam
()
{
// Make sure all team members are dead
for
(
EntityAvatar
entity
:
getActiveTeam
())
{
if
(
entity
.
isAlive
())
{
return
;
}
}
// Revive all team members
for
(
EntityAvatar
entity
:
getActiveTeam
())
{
entity
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
entity
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
)
*
.
4
f
);
getPlayer
().
sendPacket
(
new
PacketAvatarFightPropUpdateNotify
(
entity
.
getAvatar
(),
FightProperty
.
FIGHT_PROP_CUR_HP
));
getPlayer
().
sendPacket
(
new
PacketAvatarLifeStateChangeNotify
(
entity
.
getAvatar
()));
}
// Teleport player
getPlayer
().
sendPacket
(
new
PacketPlayerEnterSceneNotify
(
getPlayer
(),
EnterType
.
EnterSelf
,
EnterReason
.
Revival
,
3
,
GenshinConstants
.
START_POSITION
));
// Set player position
player
.
setSceneId
(
3
);
player
.
getPos
().
set
(
GenshinConstants
.
START_POSITION
);
// Packets
getPlayer
().
sendPacket
(
new
GenshinPacket
(
PacketOpcodes
.
WorldPlayerReviveRsp
));
}
public
void
saveAvatars
()
{
// Save all avatars from active team
for
(
EntityAvatar
entity
:
getActiveTeam
())
{
entity
.
getAvatar
().
save
();
}
}
}
src/main/java/emu/grasscutter/game/World.java
0 → 100644
View file @
7925d1cd
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
java.util.stream.Collectors
;
import
emu.grasscutter.game.entity.GenshinEntity
;
import
emu.grasscutter.game.props.ClimateType
;
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.game.GenshinPlayer.SceneLoadState
;
import
emu.grasscutter.game.entity.EntityAvatar
;
import
emu.grasscutter.game.entity.EntityClientGadget
;
import
emu.grasscutter.net.packet.GenshinPacket
;
import
emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult
;
import
emu.grasscutter.net.proto.EnterTypeOuterClass.EnterType
;
import
emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType
;
import
emu.grasscutter.server.packet.send.PacketDelTeamEntityNotify
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify
;
import
emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify
;
import
emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify
;
import
emu.grasscutter.server.packet.send.PacketSceneEntityDisappearNotify
;
import
emu.grasscutter.server.packet.send.PacketScenePlayerInfoNotify
;
import
emu.grasscutter.server.packet.send.PacketSceneTeamUpdateNotify
;
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
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
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
);
}
public
World
(
GenshinPlayer
player
,
boolean
isMultiplayer
)
{
this
.
owner
=
player
;
this
.
players
=
Collections
.
synchronizedList
(
new
ArrayList
<>());
this
.
entities
=
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
;
}
public
GenshinPlayer
getHost
()
{
return
owner
;
}
public
int
getLevelEntityId
()
{
return
levelEntityId
;
}
public
int
getHostPeerId
()
{
if
(
this
.
getHost
()
==
null
)
{
return
0
;
}
return
this
.
getHost
().
getPeerId
();
}
public
int
getNextPeerId
()
{
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
;
}
public
void
setWorldLevel
(
int
worldLevel
)
{
this
.
worldLevel
=
worldLevel
;
}
public
ClimateType
getClimate
()
{
return
climate
;
}
public
void
setClimate
(
ClimateType
climate
)
{
this
.
climate
=
climate
;
}
public
List
<
GenshinPlayer
>
getPlayers
()
{
return
players
;
}
public
int
getPlayerCount
()
{
return
getPlayers
().
size
();
}
public
Int2ObjectMap
<
GenshinEntity
>
getEntities
()
{
return
this
.
entities
;
}
public
boolean
isInWorld
(
GenshinEntity
entity
)
{
return
this
.
entities
.
containsKey
(
entity
.
getId
());
}
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
))
{
return
;
}
// Remove player from prev world
if
(
player
.
getWorld
()
!=
null
)
{
player
.
getWorld
().
removePlayer
(
player
);
}
// Register
player
.
setWorld
(
this
);
getPlayers
().
add
(
player
);
player
.
setPeerId
(
this
.
getNextPeerId
());
player
.
getTeamManager
().
setEntityId
(
getNextEntityId
(
EntityIdType
.
TEAM
));
// TODO Update team of all players
this
.
setupPlayerAvatars
(
player
);
// Info packet for other players
if
(
this
.
getPlayers
().
size
()
>
1
)
{
this
.
updatePlayerInfos
(
player
);
}
}
public
synchronized
void
removePlayer
(
GenshinPlayer
player
)
{
// Remove team entities
player
.
sendPacket
(
new
PacketDelTeamEntityNotify
(
player
.
getSceneId
(),
getPlayers
().
stream
().
map
(
p
->
p
.
getTeamManager
().
getEntityId
()).
collect
(
Collectors
.
toList
())
)
);
// Deregister
getPlayers
().
remove
(
player
);
player
.
setWorld
(
null
);
this
.
removePlayerAvatars
(
player
);
// Info packet for other players
if
(
this
.
getPlayers
().
size
()
>
0
)
{
this
.
updatePlayerInfos
(
player
);
}
// Disband world if host leaves
if
(
getHost
()
==
player
)
{
List
<
GenshinPlayer
>
kicked
=
new
ArrayList
<>(
this
.
getPlayers
());
for
(
GenshinPlayer
victim
:
kicked
)
{
World
world
=
new
World
(
victim
);
world
.
addPlayer
(
victim
);
victim
.
sendPacket
(
new
PacketPlayerEnterSceneNotify
(
victim
,
EnterType
.
EnterSelf
,
EnterReason
.
TeamKick
,
victim
.
getWorld
().
getSceneId
(),
victim
.
getPos
()));
}
}
}
private
void
updatePlayerInfos
(
GenshinPlayer
paramPlayer
)
{
for
(
GenshinPlayer
player
:
getPlayers
())
{
// Dont send packets if player is loading in
if
(!
player
.
hasSentAvatarDataNotify
()
||
player
.
getSceneLoadState
().
getValue
()
<
SceneLoadState
.
INIT
.
getValue
()
||
player
==
paramPlayer
)
{
continue
;
}
// World player info packets
player
.
getSession
().
send
(
new
PacketWorldPlayerInfoNotify
(
this
));
player
.
getSession
().
send
(
new
PacketScenePlayerInfoNotify
(
this
));
player
.
getSession
().
send
(
new
PacketWorldPlayerRTTNotify
(
this
));
// Team packets
player
.
getSession
().
send
(
new
PacketSceneTeamUpdateNotify
(
player
));
player
.
getSession
().
send
(
new
PacketSyncTeamEntityNotify
(
player
));
player
.
getSession
().
send
(
new
PacketSyncScenePlayTeamEntityNotify
(
player
));
}
}
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
);
}
}
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
().
hasGodmode
())
{
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 TODO
// 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 TODO
// 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
);
}
}
public
void
close
()
{
}
@Override
public
Iterator
<
GenshinPlayer
>
iterator
()
{
return
getPlayers
().
iterator
();
}
}
src/main/java/emu/grasscutter/game/avatar/AvatarProfileData.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.avatar
;
public
class
AvatarProfileData
{
private
int
avatarId
;
private
int
level
;
public
AvatarProfileData
(
GenshinAvatar
avatar
)
{
this
.
update
(
avatar
);
}
public
int
getAvatarId
()
{
return
avatarId
;
}
public
int
getLevel
()
{
return
level
;
}
public
void
update
(
GenshinAvatar
avatar
)
{
this
.
avatarId
=
avatar
.
getAvatarId
();
this
.
level
=
avatar
.
getLevel
();
}
}
src/main/java/emu/grasscutter/game/avatar/AvatarStat.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.avatar
;
import
java.util.stream.Stream
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
public
enum
AvatarStat
{
FIGHT_PROP_NONE
(
0
),
FIGHT_PROP_BASE_HP
(
1
),
FIGHT_PROP_HP
(
2
),
FIGHT_PROP_HP_PERCENT
(
3
),
FIGHT_PROP_BASE_ATTACK
(
4
),
FIGHT_PROP_ATTACK
(
5
),
FIGHT_PROP_ATTACK_PERCENT
(
6
),
FIGHT_PROP_BASE_DEFENSE
(
7
),
FIGHT_PROP_DEFENSE
(
8
),
FIGHT_PROP_DEFENSE_PERCENT
(
9
),
FIGHT_PROP_BASE_SPEED
(
10
),
FIGHT_PROP_SPEED_PERCENT
(
11
),
FIGHT_PROP_HP_MP_PERCENT
(
12
),
FIGHT_PROP_ATTACK_MP_PERCENT
(
13
),
FIGHT_PROP_CRITICAL
(
20
),
FIGHT_PROP_ANTI_CRITICAL
(
21
),
FIGHT_PROP_CRITICAL_HURT
(
22
),
FIGHT_PROP_CHARGE_EFFICIENCY
(
23
),
FIGHT_PROP_ADD_HURT
(
24
),
FIGHT_PROP_SUB_HURT
(
25
),
FIGHT_PROP_HEAL_ADD
(
26
),
FIGHT_PROP_HEALED_ADD
(
27
),
FIGHT_PROP_ELEMENT_MASTERY
(
28
),
FIGHT_PROP_PHYSICAL_SUB_HURT
(
29
),
FIGHT_PROP_PHYSICAL_ADD_HURT
(
30
),
FIGHT_PROP_DEFENCE_IGNORE_RATIO
(
31
),
FIGHT_PROP_DEFENCE_IGNORE_DELTA
(
32
),
FIGHT_PROP_FIRE_ADD_HURT
(
40
),
FIGHT_PROP_ELEC_ADD_HURT
(
41
),
FIGHT_PROP_WATER_ADD_HURT
(
42
),
FIGHT_PROP_GRASS_ADD_HURT
(
43
),
FIGHT_PROP_WIND_ADD_HURT
(
44
),
FIGHT_PROP_ROCK_ADD_HURT
(
45
),
FIGHT_PROP_ICE_ADD_HURT
(
46
),
FIGHT_PROP_HIT_HEAD_ADD_HURT
(
47
),
FIGHT_PROP_FIRE_SUB_HURT
(
50
),
FIGHT_PROP_ELEC_SUB_HURT
(
51
),
FIGHT_PROP_WATER_SUB_HURT
(
52
),
FIGHT_PROP_GRASS_SUB_HURT
(
53
),
FIGHT_PROP_WIND_SUB_HURT
(
54
),
FIGHT_PROP_ROCK_SUB_HURT
(
55
),
FIGHT_PROP_ICE_SUB_HURT
(
56
),
FIGHT_PROP_EFFECT_HIT
(
60
),
FIGHT_PROP_EFFECT_RESIST
(
61
),
FIGHT_PROP_FREEZE_RESIST
(
62
),
FIGHT_PROP_TORPOR_RESIST
(
63
),
FIGHT_PROP_DIZZY_RESIST
(
64
),
FIGHT_PROP_FREEZE_SHORTEN
(
65
),
FIGHT_PROP_TORPOR_SHORTEN
(
66
),
FIGHT_PROP_DIZZY_SHORTEN
(
67
),
FIGHT_PROP_MAX_FIRE_ENERGY
(
70
),
FIGHT_PROP_MAX_ELEC_ENERGY
(
71
),
FIGHT_PROP_MAX_WATER_ENERGY
(
72
),
FIGHT_PROP_MAX_GRASS_ENERGY
(
73
),
FIGHT_PROP_MAX_WIND_ENERGY
(
74
),
FIGHT_PROP_MAX_ICE_ENERGY
(
75
),
FIGHT_PROP_MAX_ROCK_ENERGY
(
76
),
FIGHT_PROP_SKILL_CD_MINUS_RATIO
(
80
),
FIGHT_PROP_SHIELD_COST_MINUS_RATIO
(
81
),
FIGHT_PROP_CUR_FIRE_ENERGY
(
1000
),
FIGHT_PROP_CUR_ELEC_ENERGY
(
1001
),
FIGHT_PROP_CUR_WATER_ENERGY
(
1002
),
FIGHT_PROP_CUR_GRASS_ENERGY
(
1003
),
FIGHT_PROP_CUR_WIND_ENERGY
(
1004
),
FIGHT_PROP_CUR_ICE_ENERGY
(
1005
),
FIGHT_PROP_CUR_ROCK_ENERGY
(
1006
),
FIGHT_PROP_CUR_HP
(
1010
),
FIGHT_PROP_MAX_HP
(
2000
),
FIGHT_PROP_CUR_ATTACK
(
2001
),
FIGHT_PROP_CUR_DEFENSE
(
2002
),
FIGHT_PROP_CUR_SPEED
(
2003
),
FIGHT_PROP_NONEXTRA_ATTACK
(
3000
),
FIGHT_PROP_NONEXTRA_DEFENSE
(
3001
),
FIGHT_PROP_NONEXTRA_CRITICAL
(
3002
),
FIGHT_PROP_NONEXTRA_ANTI_CRITICAL
(
3003
),
FIGHT_PROP_NONEXTRA_CRITICAL_HURT
(
3004
),
FIGHT_PROP_NONEXTRA_CHARGE_EFFICIENCY
(
3005
),
FIGHT_PROP_NONEXTRA_ELEMENT_MASTERY
(
3006
),
FIGHT_PROP_NONEXTRA_PHYSICAL_SUB_HURT
(
3007
),
FIGHT_PROP_NONEXTRA_FIRE_ADD_HURT
(
3008
),
FIGHT_PROP_NONEXTRA_ELEC_ADD_HURT
(
3009
),
FIGHT_PROP_NONEXTRA_WATER_ADD_HURT
(
3010
),
FIGHT_PROP_NONEXTRA_GRASS_ADD_HURT
(
3011
),
FIGHT_PROP_NONEXTRA_WIND_ADD_HURT
(
3012
),
FIGHT_PROP_NONEXTRA_ROCK_ADD_HURT
(
3013
),
FIGHT_PROP_NONEXTRA_ICE_ADD_HURT
(
3014
),
FIGHT_PROP_NONEXTRA_FIRE_SUB_HURT
(
3015
),
FIGHT_PROP_NONEXTRA_ELEC_SUB_HURT
(
3016
),
FIGHT_PROP_NONEXTRA_WATER_SUB_HURT
(
3017
),
FIGHT_PROP_NONEXTRA_GRASS_SUB_HURT
(
3018
),
FIGHT_PROP_NONEXTRA_WIND_SUB_HURT
(
3019
),
FIGHT_PROP_NONEXTRA_ROCK_SUB_HURT
(
3020
),
FIGHT_PROP_NONEXTRA_ICE_SUB_HURT
(
3021
),
FIGHT_PROP_NONEXTRA_SKILL_CD_MINUS_RATIO
(
3022
),
FIGHT_PROP_NONEXTRA_SHIELD_COST_MINUS_RATIO
(
3023
),
FIGHT_PROP_NONEXTRA_PHYSICAL_ADD_HURT
(
3024
);
private
final
int
id
;
private
static
final
Int2ObjectMap
<
AvatarStat
>
map
=
new
Int2ObjectOpenHashMap
<>();
static
{
Stream
.
of
(
values
()).
forEach
(
e
->
map
.
put
(
e
.
getId
(),
e
));
}
private
AvatarStat
(
int
id
)
{
this
.
id
=
id
;
}
public
int
getId
()
{
return
id
;
}
public
static
AvatarStat
getStatById
(
int
value
)
{
return
map
.
getOrDefault
(
value
,
FIGHT_PROP_NONE
);
}
}
src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.avatar
;
import
java.util.Iterator
;
import
java.util.List
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.def.AvatarData
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.entity.EntityAvatar
;
import
emu.grasscutter.game.inventory.GenshinItem
;
import
emu.grasscutter.server.packet.send.PacketAvatarChangeCostumeNotify
;
import
emu.grasscutter.server.packet.send.PacketAvatarFlycloakChangeNotify
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
it.unimi.dsi.fastutil.longs.Long2ObjectMap
;
import
it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
;
public
class
AvatarStorage
implements
Iterable
<
GenshinAvatar
>
{
private
final
GenshinPlayer
player
;
private
final
Int2ObjectMap
<
GenshinAvatar
>
avatars
;
private
final
Long2ObjectMap
<
GenshinAvatar
>
avatarsGuid
;
public
AvatarStorage
(
GenshinPlayer
player
)
{
this
.
player
=
player
;
this
.
avatars
=
new
Int2ObjectOpenHashMap
<>();
this
.
avatarsGuid
=
new
Long2ObjectOpenHashMap
<>();
}
public
GenshinPlayer
getPlayer
()
{
return
player
;
}
public
Int2ObjectMap
<
GenshinAvatar
>
getAvatars
()
{
return
avatars
;
}
public
int
getAvatarCount
()
{
return
this
.
avatars
.
size
();
}
public
GenshinAvatar
getAvatarById
(
int
id
)
{
return
getAvatars
().
get
(
id
);
}
public
GenshinAvatar
getAvatarByGuid
(
long
id
)
{
return
avatarsGuid
.
get
(
id
);
}
public
boolean
hasAvatar
(
int
id
)
{
return
getAvatars
().
containsKey
(
id
);
}
public
boolean
addAvatar
(
GenshinAvatar
avatar
)
{
if
(
avatar
.
getAvatarData
()
==
null
||
this
.
hasAvatar
(
avatar
.
getAvatarId
()))
{
return
false
;
}
// Set owner first
avatar
.
setOwner
(
getPlayer
());
// Put into maps
this
.
avatars
.
put
(
avatar
.
getAvatarId
(),
avatar
);
this
.
avatarsGuid
.
put
(
avatar
.
getGuid
(),
avatar
);
avatar
.
save
();
return
true
;
}
public
void
addStartingWeapon
(
GenshinAvatar
avatar
)
{
// Make sure avatar owner is this player
if
(
avatar
.
getPlayer
()
!=
this
.
getPlayer
())
{
return
;
}
// Create weapon
GenshinItem
weapon
=
new
GenshinItem
(
avatar
.
getAvatarData
().
getInitialWeapon
());
if
(
weapon
.
getItemData
()
!=
null
)
{
this
.
getPlayer
().
getInventory
().
addItem
(
weapon
);
avatar
.
equipItem
(
weapon
,
true
);
}
}
public
boolean
wearFlycloak
(
long
avatarGuid
,
int
flycloakId
)
{
GenshinAvatar
avatar
=
this
.
getAvatarByGuid
(
avatarGuid
);
if
(
avatar
==
null
||
!
getPlayer
().
getFlyCloakList
().
contains
(
flycloakId
))
{
return
false
;
}
avatar
.
setFlyCloak
(
flycloakId
);
avatar
.
save
();
// Update
getPlayer
().
sendPacket
(
new
PacketAvatarFlycloakChangeNotify
(
avatar
));
return
true
;
}
public
boolean
changeCostume
(
long
avatarGuid
,
int
costumeId
)
{
GenshinAvatar
avatar
=
this
.
getAvatarByGuid
(
avatarGuid
);
if
(
avatar
==
null
)
{
return
false
;
}
if
(
costumeId
!=
0
&&
!
getPlayer
().
getCostumeList
().
contains
(
costumeId
))
{
return
false
;
}
// TODO make sure avatar can wear costume
avatar
.
setCostume
(
costumeId
);
avatar
.
save
();
// Update entity
EntityAvatar
entity
=
avatar
.
getAsEntity
();
if
(
entity
==
null
)
{
entity
=
new
EntityAvatar
(
avatar
);
getPlayer
().
sendPacket
(
new
PacketAvatarChangeCostumeNotify
(
entity
));
}
else
{
getPlayer
().
getWorld
().
broadcastPacket
(
new
PacketAvatarChangeCostumeNotify
(
entity
));
}
// Done
return
true
;
}
public
void
loadFromDatabase
()
{
List
<
GenshinAvatar
>
avatars
=
DatabaseHelper
.
getAvatars
(
getPlayer
());
for
(
GenshinAvatar
avatar
:
avatars
)
{
// Should never happen
if
(
avatar
.
getObjectId
()
==
null
)
{
continue
;
}
AvatarData
avatarData
=
GenshinData
.
getAvatarDataMap
().
get
(
avatar
.
getAvatarId
());
if
(
avatarData
==
null
)
{
continue
;
}
// Set ownerships
avatar
.
setAvatarData
(
avatarData
);
avatar
.
setOwner
(
getPlayer
());
// Force recalc of const boosted skills
avatar
.
recalcProudSkillBonusMap
();
// Add to avatar storage
this
.
avatars
.
put
(
avatar
.
getAvatarId
(),
avatar
);
this
.
avatarsGuid
.
put
(
avatar
.
getGuid
(),
avatar
);
}
}
public
void
postLoad
()
{
for
(
GenshinAvatar
avatar
:
this
)
{
// Weapon check
if
(
avatar
.
getWeapon
()
==
null
)
{
this
.
addStartingWeapon
(
avatar
);
}
// Recalc stats
avatar
.
recalcStats
();
}
}
@Override
public
Iterator
<
GenshinAvatar
>
iterator
()
{
return
getAvatars
().
values
().
iterator
();
}
}
src/main/java/emu/grasscutter/game/avatar/GenshinAvatar.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.avatar
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Set
;
import
org.bson.types.ObjectId
;
import
dev.morphia.annotations.Entity
;
import
dev.morphia.annotations.Id
;
import
dev.morphia.annotations.Indexed
;
import
dev.morphia.annotations.PostLoad
;
import
dev.morphia.annotations.PrePersist
;
import
dev.morphia.annotations.Transient
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.common.FightPropData
;
import
emu.grasscutter.data.custom.OpenConfigEntry
;
import
emu.grasscutter.data.def.AvatarData
;
import
emu.grasscutter.data.def.AvatarPromoteData
;
import
emu.grasscutter.data.def.AvatarSkillData
;
import
emu.grasscutter.data.def.AvatarSkillDepotData
;
import
emu.grasscutter.data.def.AvatarSkillDepotData.InherentProudSkillOpens
;
import
emu.grasscutter.data.def.AvatarTalentData
;
import
emu.grasscutter.data.def.EquipAffixData
;
import
emu.grasscutter.data.def.ReliquaryAffixData
;
import
emu.grasscutter.data.def.ReliquaryLevelData
;
import
emu.grasscutter.data.def.ReliquaryMainPropData
;
import
emu.grasscutter.data.def.ReliquarySetData
;
import
emu.grasscutter.data.def.WeaponCurveData
;
import
emu.grasscutter.data.def.WeaponPromoteData
;
import
emu.grasscutter.data.def.ItemData.WeaponProperty
;
import
emu.grasscutter.data.def.ProudSkillData
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.entity.EntityAvatar
;
import
emu.grasscutter.game.inventory.EquipType
;
import
emu.grasscutter.game.inventory.GenshinItem
;
import
emu.grasscutter.game.props.ElementType
;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.net.proto.AvatarFetterInfoOuterClass.AvatarFetterInfo
;
import
emu.grasscutter.net.proto.AvatarInfoOuterClass.AvatarInfo
;
import
emu.grasscutter.server.packet.send.PacketAvatarEquipChangeNotify
;
import
emu.grasscutter.server.packet.send.PacketAvatarFightPropNotify
;
import
emu.grasscutter.utils.ProtoHelper
;
import
it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
@Entity
(
value
=
"avatars"
,
noClassnameStored
=
true
)
public
class
GenshinAvatar
{
@Id
private
ObjectId
id
;
@Indexed
private
int
ownerId
;
// Id of player that this avatar belongs to
@Transient
private
GenshinPlayer
owner
;
@Transient
private
AvatarData
data
;
@Transient
private
long
guid
;
// Player unique id
private
int
avatarId
;
// Id of avatar
private
int
level
=
1
;
private
int
exp
;
private
int
promoteLevel
;
private
int
satiation
;
// ?
private
int
satiationPenalty
;
// ?
private
float
currentHp
;
@Transient
private
final
Int2ObjectMap
<
GenshinItem
>
equips
;
@Transient
private
final
Int2FloatOpenHashMap
fightProp
;
@Transient
private
final
Set
<
String
>
bonusAbilityList
;
private
Map
<
Integer
,
Integer
>
skillLevelMap
;
// Talent levels
private
Map
<
Integer
,
Integer
>
proudSkillBonusMap
;
// Talent bonus levels (from const)
private
int
skillDepotId
;
private
int
coreProudSkillLevel
;
// Constellation level
private
Set
<
Integer
>
talentIdList
;
// Constellation id list
private
Set
<
Integer
>
proudSkillList
;
// Character passives
private
int
flyCloak
;
private
int
costume
;
private
int
bornTime
;
public
GenshinAvatar
()
{
// Morhpia only!
this
.
equips
=
new
Int2ObjectOpenHashMap
<>();
this
.
fightProp
=
new
Int2FloatOpenHashMap
();
this
.
bonusAbilityList
=
new
HashSet
<>();
this
.
proudSkillBonusMap
=
new
HashMap
<>();
// TODO Move to genshin avatar
}
// On creation
public
GenshinAvatar
(
int
avatarId
)
{
this
(
GenshinData
.
getAvatarDataMap
().
get
(
avatarId
));
}
public
GenshinAvatar
(
AvatarData
data
)
{
this
();
this
.
avatarId
=
data
.
getId
();
this
.
data
=
data
;
this
.
bornTime
=
(
int
)
(
System
.
currentTimeMillis
()
/
1000
);
this
.
flyCloak
=
140001
;
this
.
skillLevelMap
=
new
HashMap
<>();
this
.
talentIdList
=
new
HashSet
<>();
this
.
proudSkillList
=
new
HashSet
<>();
// Combat properties
for
(
FightProperty
prop
:
FightProperty
.
values
())
{
if
(
prop
.
getId
()
<=
0
||
prop
.
getId
()
>=
3000
)
{
continue
;
}
this
.
setFightProperty
(
prop
,
0
f
);
}
// Skill depot
this
.
setSkillDepot
(
getAvatarData
().
getSkillDepot
());
// Set stats
this
.
recalcStats
();
this
.
currentHp
=
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
);
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
this
.
currentHp
);
// Load handler
this
.
onLoad
();
}
public
GenshinPlayer
getPlayer
()
{
return
this
.
owner
;
}
public
ObjectId
getObjectId
()
{
return
id
;
}
public
AvatarData
getAvatarData
()
{
return
data
;
}
protected
void
setAvatarData
(
AvatarData
data
)
{
this
.
data
=
data
;
}
public
int
getOwnerId
()
{
return
ownerId
;
}
public
void
setOwner
(
GenshinPlayer
player
)
{
this
.
owner
=
player
;
this
.
ownerId
=
player
.
getId
();
this
.
guid
=
player
.
getNextGuid
();
}
public
int
getSatiation
()
{
return
satiation
;
}
public
void
setSatiation
(
int
satiation
)
{
this
.
satiation
=
satiation
;
}
public
int
getSatiationPenalty
()
{
return
satiationPenalty
;
}
public
void
setSatiationPenalty
(
int
satiationPenalty
)
{
this
.
satiationPenalty
=
satiationPenalty
;
}
public
AvatarData
getData
()
{
return
data
;
}
public
long
getGuid
()
{
return
guid
;
}
public
int
getAvatarId
()
{
return
avatarId
;
}
public
int
getLevel
()
{
return
level
;
}
public
void
setLevel
(
int
level
)
{
this
.
level
=
level
;
}
public
int
getExp
()
{
return
exp
;
}
public
void
setExp
(
int
exp
)
{
this
.
exp
=
exp
;
}
public
int
getPromoteLevel
()
{
return
promoteLevel
;
}
public
void
setPromoteLevel
(
int
promoteLevel
)
{
this
.
promoteLevel
=
promoteLevel
;
}
public
Int2ObjectMap
<
GenshinItem
>
getEquips
()
{
return
equips
;
}
public
GenshinItem
getEquipBySlot
(
EquipType
slot
)
{
return
this
.
getEquips
().
get
(
slot
.
getValue
());
}
private
GenshinItem
getEquipBySlot
(
int
slotId
)
{
return
this
.
getEquips
().
get
(
slotId
);
}
public
GenshinItem
getWeapon
()
{
return
this
.
getEquipBySlot
(
EquipType
.
EQUIP_WEAPON
);
}
public
int
getSkillDepotId
()
{
return
skillDepotId
;
}
public
void
setSkillDepot
(
AvatarSkillDepotData
skillDepot
)
{
// Set id
this
.
skillDepotId
=
skillDepot
.
getId
();
// Clear, then add skills
getSkillLevelMap
().
clear
();
if
(
skillDepot
.
getEnergySkill
()
>
0
)
{
getSkillLevelMap
().
put
(
skillDepot
.
getEnergySkill
(),
1
);
}
for
(
int
skillId
:
skillDepot
.
getSkills
())
{
if
(
skillId
>
0
)
{
getSkillLevelMap
().
put
(
skillId
,
1
);
}
}
// Add proud skills
this
.
getProudSkillList
().
clear
();
for
(
InherentProudSkillOpens
openData
:
skillDepot
.
getInherentProudSkillOpens
())
{
if
(
openData
.
getProudSkillGroupId
()
==
0
)
{
continue
;
}
if
(
openData
.
getNeedAvatarPromoteLevel
()
<=
this
.
getPromoteLevel
())
{
int
proudSkillId
=
(
openData
.
getProudSkillGroupId
()
*
100
)
+
1
;
if
(
GenshinData
.
getProudSkillDataMap
().
containsKey
(
proudSkillId
))
{
this
.
getProudSkillList
().
add
(
proudSkillId
);
}
}
}
}
public
Map
<
Integer
,
Integer
>
getSkillLevelMap
()
{
return
skillLevelMap
;
}
public
Map
<
Integer
,
Integer
>
getProudSkillBonusMap
()
{
return
proudSkillBonusMap
;
}
public
Set
<
String
>
getBonusAbilityList
()
{
return
bonusAbilityList
;
}
public
float
getCurrentHp
()
{
return
currentHp
;
}
public
void
setCurrentHp
(
float
currentHp
)
{
this
.
currentHp
=
currentHp
;
}
public
Int2FloatOpenHashMap
getFightProperties
()
{
return
fightProp
;
}
public
void
setFightProperty
(
FightProperty
prop
,
float
value
)
{
this
.
getFightProperties
().
put
(
prop
.
getId
(),
value
);
}
private
void
setFightProperty
(
int
id
,
float
value
)
{
this
.
getFightProperties
().
put
(
id
,
value
);
}
public
void
addFightProperty
(
FightProperty
prop
,
float
value
)
{
this
.
getFightProperties
().
put
(
prop
.
getId
(),
getFightProperty
(
prop
)
+
value
);
}
public
float
getFightProperty
(
FightProperty
prop
)
{
return
getFightProperties
().
getOrDefault
(
prop
.
getId
(),
0
f
);
}
public
Set
<
Integer
>
getTalentIdList
()
{
return
talentIdList
;
}
public
int
getCoreProudSkillLevel
()
{
return
coreProudSkillLevel
;
}
public
void
setCoreProudSkillLevel
(
int
constLevel
)
{
this
.
coreProudSkillLevel
=
constLevel
;
}
public
Set
<
Integer
>
getProudSkillList
()
{
return
proudSkillList
;
}
public
int
getFlyCloak
()
{
return
flyCloak
;
}
public
void
setFlyCloak
(
int
flyCloak
)
{
this
.
flyCloak
=
flyCloak
;
}
public
int
getCostume
()
{
return
costume
;
}
public
void
setCostume
(
int
costume
)
{
this
.
costume
=
costume
;
}
public
int
getBornTime
()
{
return
bornTime
;
}
public
boolean
equipItem
(
GenshinItem
item
,
boolean
shouldRecalc
)
{
EquipType
itemEquipType
=
item
.
getItemData
().
getEquipType
();
if
(
itemEquipType
==
EquipType
.
EQUIP_NONE
)
{
return
false
;
}
if
(
getEquips
().
containsKey
(
itemEquipType
.
getValue
()))
{
unequipItem
(
itemEquipType
);
}
getEquips
().
put
(
itemEquipType
.
getValue
(),
item
);
if
(
itemEquipType
==
EquipType
.
EQUIP_WEAPON
&&
getPlayer
().
getWorld
()
!=
null
)
{
item
.
setWeaponEntityId
(
this
.
getPlayer
().
getWorld
().
getNextEntityId
(
EntityIdType
.
WEAPON
));
}
item
.
setEquipCharacter
(
this
.
getAvatarId
());
item
.
save
();
if
(
shouldRecalc
)
{
this
.
recalcStats
();
}
if
(
this
.
getPlayer
().
hasSentAvatarDataNotify
())
{
this
.
getPlayer
().
sendPacket
(
new
PacketAvatarEquipChangeNotify
(
this
,
item
));
}
return
true
;
}
public
boolean
unequipItem
(
EquipType
slot
)
{
GenshinItem
item
=
getEquips
().
remove
(
slot
.
getValue
());
if
(
item
!=
null
)
{
item
.
setEquipCharacter
(
0
);
item
.
save
();
return
true
;
}
return
false
;
}
public
void
recalcStats
()
{
// Setup
AvatarData
data
=
this
.
getAvatarData
();
AvatarPromoteData
promoteData
=
GenshinData
.
getAvatarPromoteData
(
data
.
getAvatarPromoteId
(),
this
.
getPromoteLevel
());
Int2IntOpenHashMap
setMap
=
new
Int2IntOpenHashMap
();
this
.
getBonusAbilityList
().
clear
();
// Get hp percent, set to 100% if none
float
hpPercent
=
this
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
)
<=
0
?
1
f
:
this
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
)
/
this
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
);
// Clear properties
this
.
getFightProperties
().
clear
();
// Base stats
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_BASE_HP
,
data
.
getBaseHp
(
this
.
getLevel
()));
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_BASE_ATTACK
,
data
.
getBaseAttack
(
this
.
getLevel
()));
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_BASE_DEFENSE
,
data
.
getBaseDefense
(
this
.
getLevel
()));
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CRITICAL
,
data
.
getBaseCritical
());
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CRITICAL_HURT
,
data
.
getBaseCriticalHurt
());
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CHARGE_EFFICIENCY
,
1
f
);
if
(
promoteData
!=
null
)
{
for
(
FightPropData
fightPropData
:
promoteData
.
getAddProps
())
{
this
.
addFightProperty
(
fightPropData
.
getProp
(),
fightPropData
.
getValue
());
}
}
// Set energy usage
if
(
data
.
getSkillDepot
()
!=
null
&&
data
.
getSkillDepot
().
getEnergySkillData
()
!=
null
)
{
ElementType
element
=
data
.
getSkillDepot
().
getElementType
();
this
.
setFightProperty
(
element
.
getEnergyProperty
(),
data
.
getSkillDepot
().
getEnergySkillData
().
getCostElemVal
());
this
.
setFightProperty
((
element
.
getEnergyProperty
().
getId
()
%
70
)
+
1000
,
data
.
getSkillDepot
().
getEnergySkillData
().
getCostElemVal
());
}
// Artifacts
for
(
int
slotId
=
1
;
slotId
<=
5
;
slotId
++)
{
// Get artifact
GenshinItem
equip
=
this
.
getEquipBySlot
(
slotId
);
if
(
equip
==
null
)
{
continue
;
}
// Artifact main stat
ReliquaryMainPropData
mainPropData
=
GenshinData
.
getReliquaryMainPropDataMap
().
get
(
equip
.
getMainPropId
());
if
(
mainPropData
!=
null
)
{
ReliquaryLevelData
levelData
=
GenshinData
.
getRelicLevelData
(
equip
.
getItemData
().
getRankLevel
(),
equip
.
getLevel
());
if
(
levelData
!=
null
)
{
this
.
addFightProperty
(
mainPropData
.
getFightProp
(),
levelData
.
getPropValue
(
mainPropData
.
getFightProp
()));
}
}
// Artifact sub stats
for
(
int
appendPropId
:
equip
.
getAppendPropIdList
())
{
ReliquaryAffixData
affixData
=
GenshinData
.
getReliquaryAffixDataMap
().
get
(
appendPropId
);
if
(
affixData
!=
null
)
{
this
.
addFightProperty
(
affixData
.
getFightProp
(),
affixData
.
getPropValue
());
}
}
// Set bonus
if
(
equip
.
getItemData
().
getSetId
()
>
0
)
{
setMap
.
addTo
(
equip
.
getItemData
().
getSetId
(),
1
);
}
}
// Set stuff
for
(
Int2IntOpenHashMap
.
Entry
e
:
setMap
.
int2IntEntrySet
())
{
ReliquarySetData
setData
=
GenshinData
.
getReliquarySetDataMap
().
get
(
e
.
getIntKey
());
if
(
setData
==
null
)
{
continue
;
}
// Calculate how many items are from the set
int
amount
=
e
.
getIntValue
();
// Add affix data from set bonus
for
(
int
setIndex
=
0
;
setIndex
<
setData
.
getSetNeedNum
().
length
;
setIndex
++)
{
if
(
amount
>=
setData
.
getSetNeedNum
()[
setIndex
])
{
int
affixId
=
(
setData
.
getEquipAffixId
()
*
10
)
+
setIndex
;
EquipAffixData
affix
=
GenshinData
.
getEquipAffixDataMap
().
get
(
affixId
);
if
(
affix
==
null
)
{
continue
;
}
// Add properties from this affix to our avatar
for
(
FightPropData
prop
:
affix
.
getAddProps
())
{
this
.
addFightProperty
(
prop
.
getProp
(),
prop
.
getValue
());
}
// Add any skill strings from this affix
this
.
addToAbilityList
(
affix
.
getOpenConfig
(),
true
);
}
else
{
break
;
}
}
}
// Weapon
GenshinItem
weapon
=
this
.
getWeapon
();
if
(
weapon
!=
null
)
{
// Add stats
WeaponCurveData
curveData
=
GenshinData
.
getWeaponCurveDataMap
().
get
(
weapon
.
getLevel
());
if
(
curveData
!=
null
)
{
for
(
WeaponProperty
weaponProperty
:
weapon
.
getItemData
().
getWeaponProperties
())
{
this
.
addFightProperty
(
weaponProperty
.
getFightProp
(),
weaponProperty
.
getInitValue
()
*
curveData
.
getMultByProp
(
weaponProperty
.
getType
()));
}
}
// Weapon promotion stats
WeaponPromoteData
wepPromoteData
=
GenshinData
.
getWeaponPromoteData
(
weapon
.
getItemData
().
getWeaponPromoteId
(),
weapon
.
getPromoteLevel
());
if
(
wepPromoteData
!=
null
)
{
for
(
FightPropData
prop
:
wepPromoteData
.
getAddProps
())
{
if
(
prop
.
getValue
()
==
0
f
||
prop
.
getProp
()
==
null
)
{
continue
;
}
this
.
addFightProperty
(
prop
.
getProp
(),
prop
.
getValue
());
}
}
// Add weapon skill from affixes
if
(
weapon
.
getAffixes
()
!=
null
&&
weapon
.
getAffixes
().
size
()
>
0
)
{
// Weapons usually dont have more than one affix but just in case...
for
(
int
af
:
weapon
.
getAffixes
())
{
if
(
af
==
0
)
{
continue
;
}
// Calculate affix id
int
affixId
=
(
af
*
10
)
+
weapon
.
getRefinement
();
EquipAffixData
affix
=
GenshinData
.
getEquipAffixDataMap
().
get
(
affixId
);
if
(
affix
==
null
)
{
continue
;
}
// Add properties from this affix to our avatar
for
(
FightPropData
prop
:
affix
.
getAddProps
())
{
this
.
addFightProperty
(
prop
.
getProp
(),
prop
.
getValue
());
}
// Add any skill strings from this affix
this
.
addToAbilityList
(
affix
.
getOpenConfig
(),
true
);
}
}
}
// Proud skills
for
(
int
proudSkillId
:
this
.
getProudSkillList
())
{
ProudSkillData
proudSkillData
=
GenshinData
.
getProudSkillDataMap
().
get
(
proudSkillId
);
if
(
proudSkillData
==
null
)
{
continue
;
}
// Add properties from this proud skill to our avatar
for
(
FightPropData
prop
:
proudSkillData
.
getAddProps
())
{
this
.
addFightProperty
(
prop
.
getProp
(),
prop
.
getValue
());
}
// Add any skill strings from this proud skill
this
.
addToAbilityList
(
proudSkillData
.
getOpenConfig
(),
true
);
}
// Constellations
if
(
this
.
getTalentIdList
().
size
()
>
0
)
{
for
(
int
talentId
:
this
.
getTalentIdList
())
{
AvatarTalentData
avatarTalentData
=
GenshinData
.
getAvatarTalentDataMap
().
get
(
talentId
);
if
(
avatarTalentData
==
null
)
{
return
;
}
// Add any skill strings from this constellation
this
.
addToAbilityList
(
avatarTalentData
.
getOpenConfig
(),
false
);
}
}
// Set % stats
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
,
(
getFightProperty
(
FightProperty
.
FIGHT_PROP_BASE_HP
)
*
(
1
f
+
getFightProperty
(
FightProperty
.
FIGHT_PROP_HP_PERCENT
)))
+
getFightProperty
(
FightProperty
.
FIGHT_PROP_HP
)
);
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_ATTACK
,
(
getFightProperty
(
FightProperty
.
FIGHT_PROP_BASE_ATTACK
)
*
(
1
f
+
getFightProperty
(
FightProperty
.
FIGHT_PROP_ATTACK_PERCENT
)))
+
getFightProperty
(
FightProperty
.
FIGHT_PROP_ATTACK
)
);
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_DEFENSE
,
(
getFightProperty
(
FightProperty
.
FIGHT_PROP_BASE_DEFENSE
)
*
(
1
f
+
getFightProperty
(
FightProperty
.
FIGHT_PROP_DEFENSE_PERCENT
)))
+
getFightProperty
(
FightProperty
.
FIGHT_PROP_DEFENSE
)
);
// Set current hp
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
this
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
)
*
hpPercent
);
// Packet
if
(
getPlayer
()
!=
null
&&
getPlayer
().
hasSentAvatarDataNotify
())
{
getPlayer
().
sendPacket
(
new
PacketAvatarFightPropNotify
(
this
));
}
}
public
void
addToAbilityList
(
String
openConfig
,
boolean
forceAdd
)
{
if
(
openConfig
==
null
||
openConfig
.
length
()
==
0
)
{
return
;
}
OpenConfigEntry
entry
=
GenshinData
.
getOpenConfigEntries
().
get
(
openConfig
);
if
(
entry
==
null
)
{
if
(
forceAdd
)
{
// Add config string to ability skill list anyways
this
.
getBonusAbilityList
().
add
(
openConfig
);
}
return
;
}
if
(
entry
.
getAddAbilities
()
!=
null
)
{
for
(
String
ability
:
entry
.
getAddAbilities
())
{
this
.
getBonusAbilityList
().
add
(
ability
);
}
}
}
public
void
recalcProudSkillBonusMap
()
{
// Clear first
this
.
getProudSkillBonusMap
().
clear
();
// Sanity checks
if
(
getData
()
==
null
||
getData
().
getSkillDepot
()
==
null
)
{
return
;
}
if
(
this
.
getTalentIdList
().
size
()
>
0
)
{
for
(
int
talentId
:
this
.
getTalentIdList
())
{
AvatarTalentData
avatarTalentData
=
GenshinData
.
getAvatarTalentDataMap
().
get
(
talentId
);
if
(
avatarTalentData
==
null
||
avatarTalentData
.
getOpenConfig
()
==
null
||
avatarTalentData
.
getOpenConfig
().
length
()
==
0
)
{
continue
;
}
// Get open config to find which skill should be boosted
OpenConfigEntry
entry
=
GenshinData
.
getOpenConfigEntries
().
get
(
avatarTalentData
.
getOpenConfig
());
if
(
entry
==
null
)
{
continue
;
}
int
skillId
=
0
;
if
(
entry
.
getExtraTalentIndex
()
==
2
&&
this
.
getData
().
getSkillDepot
().
getSkills
().
size
()
>=
2
)
{
// E skill
skillId
=
this
.
getData
().
getSkillDepot
().
getSkills
().
get
(
1
);
}
else
if
(
entry
.
getExtraTalentIndex
()
==
9
)
{
// Ult skill
skillId
=
this
.
getData
().
getSkillDepot
().
getEnergySkill
();
}
// Sanity check
if
(
skillId
==
0
)
{
continue
;
}
// Get proud skill group id
AvatarSkillData
skillData
=
GenshinData
.
getAvatarSkillDataMap
().
get
(
skillId
);
if
(
skillData
==
null
)
{
continue
;
}
// Add to bonus list
this
.
getProudSkillBonusMap
().
put
(
skillData
.
getProudSkillGroupId
(),
3
);
}
}
}
public
EntityAvatar
getAsEntity
()
{
for
(
EntityAvatar
entity
:
getPlayer
().
getTeamManager
().
getActiveTeam
())
{
if
(
entity
.
getAvatar
()
==
this
)
{
return
entity
;
}
}
return
null
;
}
public
int
getEntityId
()
{
EntityAvatar
entity
=
getAsEntity
();
return
entity
!=
null
?
entity
.
getId
()
:
0
;
}
public
void
save
()
{
DatabaseHelper
.
saveAvatar
(
this
);
}
public
AvatarInfo
toProto
()
{
AvatarInfo
.
Builder
avatarInfo
=
AvatarInfo
.
newBuilder
()
.
setAvatarId
(
this
.
getAvatarId
())
.
setGuid
(
this
.
getGuid
())
.
setLifeState
(
1
)
.
addAllTalentIdList
(
this
.
getTalentIdList
())
.
putAllFightPropMap
(
this
.
getFightProperties
())
.
setSkillDepotId
(
this
.
getSkillDepotId
())
.
setCoreProudSkillLevel
(
this
.
getCoreProudSkillLevel
())
.
putAllSkillLevelMap
(
this
.
getSkillLevelMap
())
.
addAllInherentProudSkillList
(
this
.
getProudSkillList
())
.
putAllProudSkillExtraLevel
(
getProudSkillBonusMap
())
.
setAvatarType
(
1
)
.
setBornTime
(
this
.
getBornTime
())
.
setFetterInfo
(
AvatarFetterInfo
.
newBuilder
().
setExpLevel
(
1
))
.
setWearingFlycloakId
(
this
.
getFlyCloak
())
.
setCostumeId
(
this
.
getCostume
());
for
(
GenshinItem
item
:
this
.
getEquips
().
values
())
{
avatarInfo
.
addEquipGuidList
(
item
.
getGuid
());
}
avatarInfo
.
putPropMap
(
PlayerProperty
.
PROP_LEVEL
.
getId
(),
ProtoHelper
.
newPropValue
(
PlayerProperty
.
PROP_LEVEL
,
this
.
getLevel
()));
avatarInfo
.
putPropMap
(
PlayerProperty
.
PROP_EXP
.
getId
(),
ProtoHelper
.
newPropValue
(
PlayerProperty
.
PROP_EXP
,
this
.
getExp
()));
avatarInfo
.
putPropMap
(
PlayerProperty
.
PROP_BREAK_LEVEL
.
getId
(),
ProtoHelper
.
newPropValue
(
PlayerProperty
.
PROP_BREAK_LEVEL
,
this
.
getPromoteLevel
()));
avatarInfo
.
putPropMap
(
PlayerProperty
.
PROP_SATIATION_VAL
.
getId
(),
ProtoHelper
.
newPropValue
(
PlayerProperty
.
PROP_SATIATION_VAL
,
0
));
avatarInfo
.
putPropMap
(
PlayerProperty
.
PROP_SATIATION_PENALTY_TIME
.
getId
(),
ProtoHelper
.
newPropValue
(
PlayerProperty
.
PROP_SATIATION_PENALTY_TIME
,
0
));
return
avatarInfo
.
build
();
}
@PostLoad
private
void
onLoad
()
{
}
@PrePersist
private
void
prePersist
()
{
this
.
currentHp
=
this
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
);
}
}
src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.dungeons
;
import
emu.grasscutter.server.game.GameServer
;
public
class
DungeonManager
{
private
final
GameServer
server
;
public
DungeonManager
(
GameServer
server
)
{
this
.
server
=
server
;
}
public
GameServer
getServer
()
{
return
server
;
}
}
src/main/java/emu/grasscutter/game/entity/EntityAvatar.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.entity
;
import
emu.grasscutter.GenshinConstants
;
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.World
;
import
emu.grasscutter.game.avatar.GenshinAvatar
;
import
emu.grasscutter.game.inventory.EquipType
;
import
emu.grasscutter.game.inventory.GenshinItem
;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.net.proto.AbilityControlBlockOuterClass.AbilityControlBlock
;
import
emu.grasscutter.net.proto.AbilityEmbryoOuterClass.AbilityEmbryo
;
import
emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo
;
import
emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair
;
import
emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo
;
import
emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData
;
import
emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo
;
import
emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair
;
import
emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType
;
import
emu.grasscutter.net.proto.PropPairOuterClass.PropPair
;
import
emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType
;
import
emu.grasscutter.net.proto.SceneAvatarInfoOuterClass.SceneAvatarInfo
;
import
emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo
;
import
emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.utils.Position
;
import
emu.grasscutter.utils.ProtoHelper
;
import
emu.grasscutter.utils.Utils
;
import
it.unimi.dsi.fastutil.ints.Int2FloatMap
;
import
it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap
;
public
class
EntityAvatar
extends
GenshinEntity
{
private
final
GenshinAvatar
avatar
;
private
PlayerDieType
killedType
;
private
int
killedBy
;
public
EntityAvatar
(
World
world
,
GenshinAvatar
avatar
)
{
super
(
world
);
this
.
avatar
=
avatar
;
this
.
id
=
world
.
getNextEntityId
(
EntityIdType
.
AVATAR
);
GenshinItem
weapon
=
this
.
getAvatar
().
getWeapon
();
if
(
weapon
!=
null
)
{
weapon
.
setWeaponEntityId
(
world
.
getNextEntityId
(
EntityIdType
.
WEAPON
));
}
}
public
EntityAvatar
(
GenshinAvatar
avatar
)
{
super
(
null
);
this
.
avatar
=
avatar
;
}
public
GenshinPlayer
getPlayer
()
{
return
avatar
.
getPlayer
();
}
@Override
public
Position
getPosition
()
{
return
getPlayer
().
getPos
();
}
@Override
public
Position
getRotation
()
{
return
getPlayer
().
getRotation
();
}
public
GenshinAvatar
getAvatar
()
{
return
avatar
;
}
public
int
getKilledBy
()
{
return
killedBy
;
}
public
PlayerDieType
getKilledType
()
{
return
killedType
;
}
@Override
public
boolean
isAlive
()
{
return
this
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
)
>
0
f
;
}
@Override
public
Int2FloatOpenHashMap
getFightProperties
()
{
return
getAvatar
().
getFightProperties
();
}
public
int
getWeaponEntityId
()
{
if
(
getAvatar
().
getWeapon
()
!=
null
)
{
return
getAvatar
().
getWeapon
().
getWeaponEntityId
();
}
return
0
;
}
@Override
public
void
onDeath
(
int
killerId
)
{
this
.
killedType
=
PlayerDieType
.
PlayerDieKillByMonster
;
this
.
killedBy
=
killerId
;
}
public
SceneAvatarInfo
getSceneAvatarInfo
()
{
SceneAvatarInfo
.
Builder
avatarInfo
=
SceneAvatarInfo
.
newBuilder
()
.
setPlayerId
(
this
.
getPlayer
().
getId
())
.
setAvatarId
(
this
.
getAvatar
().
getAvatarId
())
.
setGuid
(
this
.
getAvatar
().
getGuid
())
.
setPeerId
(
this
.
getPlayer
().
getPeerId
())
.
addAllTalentIdList
(
this
.
getAvatar
().
getTalentIdList
())
.
setCoreProudSkillLevel
(
this
.
getAvatar
().
getCoreProudSkillLevel
())
.
putAllSkillLevelMap
(
this
.
getAvatar
().
getSkillLevelMap
())
.
setSkillDepotId
(
this
.
getAvatar
().
getSkillDepotId
())
.
addAllInherentProudSkillList
(
this
.
getAvatar
().
getProudSkillList
())
.
putAllProudSkillExtraLevelMap
(
this
.
getAvatar
().
getProudSkillBonusMap
())
.
addAllTeamResonanceList
(
this
.
getAvatar
().
getPlayer
().
getTeamManager
().
getTeamResonances
())
.
setWearingFlycloakId
(
this
.
getAvatar
().
getFlyCloak
())
.
setCostumeId
(
this
.
getAvatar
().
getCostume
())
.
setBornTime
(
this
.
getAvatar
().
getBornTime
());
for
(
GenshinItem
item
:
avatar
.
getEquips
().
values
())
{
if
(
item
.
getItemData
().
getEquipType
()
==
EquipType
.
EQUIP_WEAPON
)
{
avatarInfo
.
setWeapon
(
item
.
createSceneWeaponInfo
());
}
else
{
avatarInfo
.
addReliquaryList
(
item
.
createSceneReliquaryInfo
());
}
avatarInfo
.
addEquipIdList
(
item
.
getItemId
());
}
return
avatarInfo
.
build
();
}
@Override
public
SceneEntityInfo
toProto
()
{
EntityAuthorityInfo
authority
=
EntityAuthorityInfo
.
newBuilder
()
.
setAbilityInfo
(
AbilitySyncStateInfo
.
newBuilder
())
.
setRendererChangedInfo
(
EntityRendererChangedInfo
.
newBuilder
())
.
setAiInfo
(
SceneEntityAiInfo
.
newBuilder
().
setIsAiOpen
(
true
).
setBornPos
(
Vector
.
newBuilder
()))
.
setBornPos
(
Vector
.
newBuilder
())
.
build
();
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
.
setEntityId
(
getId
())
.
setEntityType
(
ProtEntityType
.
ProtEntityAvatar
)
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
.
setEntityAuthorityInfo
(
authority
)
.
setLastMoveSceneTimeMs
(
this
.
getLastMoveSceneTimeMs
())
.
setLastMoveReliableSeq
(
this
.
getLastMoveReliableSeq
())
.
setLifeState
(
this
.
getLifeState
().
getValue
());
if
(
this
.
getWorld
()
!=
null
)
{
entityInfo
.
setMotionInfo
(
this
.
getMotionInfo
());
}
for
(
Int2FloatMap
.
Entry
entry
:
getFightProperties
().
int2FloatEntrySet
())
{
if
(
entry
.
getIntKey
()
==
0
)
{
continue
;
}
FightPropPair
fightProp
=
FightPropPair
.
newBuilder
().
setType
(
entry
.
getIntKey
()).
setPropValue
(
entry
.
getFloatValue
()).
build
();
entityInfo
.
addFightPropList
(
fightProp
);
}
PropPair
pair
=
PropPair
.
newBuilder
()
.
setType
(
PlayerProperty
.
PROP_LEVEL
.
getId
())
.
setPropValue
(
ProtoHelper
.
newPropValue
(
PlayerProperty
.
PROP_LEVEL
,
getAvatar
().
getLevel
()))
.
build
();
entityInfo
.
addPropList
(
pair
);
entityInfo
.
setAvatar
(
this
.
getSceneAvatarInfo
());
return
entityInfo
.
build
();
}
public
AbilityControlBlock
getAbilityControlBlock
()
{
AvatarData
data
=
this
.
getAvatar
().
getAvatarData
();
AbilityControlBlock
.
Builder
abilityControlBlock
=
AbilityControlBlock
.
newBuilder
();
int
embryoId
=
0
;
// Add avatar abilities
if
(
data
.
getAbilities
()
!=
null
)
{
for
(
int
id
:
data
.
getAbilities
())
{
AbilityEmbryo
emb
=
AbilityEmbryo
.
newBuilder
()
.
setAbilityId
(++
embryoId
)
.
setAbilityNameHash
(
id
)
.
setAbilityOverrideNameHash
(
GenshinConstants
.
DEFAULT_ABILITY_NAME
)
.
build
();
abilityControlBlock
.
addAbilityEmbryoList
(
emb
);
}
}
// Add default abilities
for
(
int
id
:
GenshinConstants
.
DEFAULT_ABILITY_HASHES
)
{
AbilityEmbryo
emb
=
AbilityEmbryo
.
newBuilder
()
.
setAbilityId
(++
embryoId
)
.
setAbilityNameHash
(
id
)
.
setAbilityOverrideNameHash
(
GenshinConstants
.
DEFAULT_ABILITY_NAME
)
.
build
();
abilityControlBlock
.
addAbilityEmbryoList
(
emb
);
}
// Add team resonances
for
(
int
id
:
this
.
getPlayer
().
getTeamManager
().
getTeamResonancesConfig
())
{
AbilityEmbryo
emb
=
AbilityEmbryo
.
newBuilder
()
.
setAbilityId
(++
embryoId
)
.
setAbilityNameHash
(
id
)
.
setAbilityOverrideNameHash
(
GenshinConstants
.
DEFAULT_ABILITY_NAME
)
.
build
();
abilityControlBlock
.
addAbilityEmbryoList
(
emb
);
}
// Add skill depot abilities
AvatarSkillDepotData
skillDepot
=
GenshinData
.
getAvatarSkillDepotDataMap
().
get
(
this
.
getAvatar
().
getSkillDepotId
());
if
(
skillDepot
!=
null
&&
skillDepot
.
getAbilities
()
!=
null
)
{
for
(
int
id
:
skillDepot
.
getAbilities
())
{
AbilityEmbryo
emb
=
AbilityEmbryo
.
newBuilder
()
.
setAbilityId
(++
embryoId
)
.
setAbilityNameHash
(
id
)
.
setAbilityOverrideNameHash
(
GenshinConstants
.
DEFAULT_ABILITY_NAME
)
.
build
();
abilityControlBlock
.
addAbilityEmbryoList
(
emb
);
}
}
// Add equip abilities
if
(
this
.
getAvatar
().
getBonusAbilityList
().
size
()
>
0
)
{
for
(
String
skill
:
this
.
getAvatar
().
getBonusAbilityList
())
{
AbilityEmbryo
emb
=
AbilityEmbryo
.
newBuilder
()
.
setAbilityId
(++
embryoId
)
.
setAbilityNameHash
(
Utils
.
abilityHash
(
skill
))
.
setAbilityOverrideNameHash
(
GenshinConstants
.
DEFAULT_ABILITY_NAME
)
.
build
();
abilityControlBlock
.
addAbilityEmbryoList
(
emb
);
}
}
//
return
abilityControlBlock
.
build
();
}
}
src/main/java/emu/grasscutter/game/entity/EntityClientGadget.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.entity
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.World
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo
;
import
emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair
;
import
emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo
;
import
emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData
;
import
emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo
;
import
emu.grasscutter.net.proto.EvtCreateGadgetNotifyOuterClass.EvtCreateGadgetNotify
;
import
emu.grasscutter.net.proto.GadgetClientParamOuterClass.GadgetClientParam
;
import
emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo
;
import
emu.grasscutter.net.proto.PropPairOuterClass.PropPair
;
import
emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType
;
import
emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo
;
import
emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo
;
import
emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.utils.Position
;
import
emu.grasscutter.utils.ProtoHelper
;
import
it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap
;
public
class
EntityClientGadget
extends
EntityGadget
{
private
final
GenshinPlayer
owner
;
private
final
Position
pos
;
private
final
Position
rot
;
private
int
configId
;
private
int
campId
;
private
int
campType
;
private
int
ownerEntityId
;
private
int
targetEntityId
;
private
boolean
asyncLoad
;
public
EntityClientGadget
(
World
world
,
GenshinPlayer
player
,
EvtCreateGadgetNotify
notify
)
{
super
(
world
);
this
.
owner
=
player
;
this
.
id
=
notify
.
getEntityId
();
this
.
pos
=
new
Position
(
notify
.
getInitPos
());
this
.
rot
=
new
Position
(
notify
.
getInitEulerAngles
());
this
.
configId
=
notify
.
getConfigId
();
this
.
campId
=
notify
.
getCampId
();
this
.
campType
=
notify
.
getCampType
();
this
.
ownerEntityId
=
notify
.
getPropOwnerEntityId
();
this
.
targetEntityId
=
notify
.
getTargetEntityId
();
this
.
asyncLoad
=
notify
.
getIsAsyncLoad
();
}
@Override
public
int
getGadgetId
()
{
return
configId
;
}
public
GenshinPlayer
getOwner
()
{
return
owner
;
}
public
int
getCampId
()
{
return
campId
;
}
public
int
getCampType
()
{
return
campType
;
}
public
int
getOwnerEntityId
()
{
return
ownerEntityId
;
}
public
int
getTargetEntityId
()
{
return
targetEntityId
;
}
public
boolean
isAsyncLoad
()
{
return
this
.
asyncLoad
;
}
@Override
public
void
onDeath
(
int
killerId
)
{
}
@Override
public
Int2FloatOpenHashMap
getFightProperties
()
{
// TODO Auto-generated method stub
return
null
;
}
@Override
public
Position
getPosition
()
{
// TODO Auto-generated method stub
return
this
.
pos
;
}
@Override
public
Position
getRotation
()
{
// TODO Auto-generated method stub
return
this
.
rot
;
}
@Override
public
SceneEntityInfo
toProto
()
{
EntityAuthorityInfo
authority
=
EntityAuthorityInfo
.
newBuilder
()
.
setAbilityInfo
(
AbilitySyncStateInfo
.
newBuilder
())
.
setRendererChangedInfo
(
EntityRendererChangedInfo
.
newBuilder
())
.
setAiInfo
(
SceneEntityAiInfo
.
newBuilder
().
setIsAiOpen
(
true
).
setBornPos
(
Vector
.
newBuilder
()))
.
setBornPos
(
Vector
.
newBuilder
())
.
build
();
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
.
setEntityId
(
getId
())
.
setEntityType
(
ProtEntityType
.
ProtEntityGadget
)
.
setMotionInfo
(
MotionInfo
.
newBuilder
().
setPos
(
getPosition
().
toProto
()).
setRot
(
getRotation
().
toProto
()).
setSpeed
(
Vector
.
newBuilder
()))
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
.
setEntityAuthorityInfo
(
authority
)
.
setLifeState
(
1
);
PropPair
pair
=
PropPair
.
newBuilder
()
.
setType
(
PlayerProperty
.
PROP_LEVEL
.
getId
())
.
setPropValue
(
ProtoHelper
.
newPropValue
(
PlayerProperty
.
PROP_LEVEL
,
1
))
.
build
();
entityInfo
.
addPropList
(
pair
);
GadgetClientParam
clientGadget
=
GadgetClientParam
.
newBuilder
()
.
setCampId
(
this
.
getCampId
())
.
setCampType
(
this
.
getCampType
())
.
setOwnerEntityId
(
this
.
getOwnerEntityId
())
.
setTargetEntityId
(
this
.
getTargetEntityId
())
.
setAsyncLoad
(
this
.
isAsyncLoad
())
.
build
();
SceneGadgetInfo
.
Builder
gadgetInfo
=
SceneGadgetInfo
.
newBuilder
()
.
setGadgetId
(
this
.
getGadgetId
())
.
setOwnerEntityId
(
this
.
getOwnerEntityId
())
.
setIsEnableInteract
(
true
)
.
setClientGadget
(
clientGadget
)
.
setPropOwnerEntityId
(
this
.
getOwnerEntityId
())
.
setAuthorityPeerId
(
this
.
getOwner
().
getPeerId
());
entityInfo
.
setGadget
(
gadgetInfo
);
return
entityInfo
.
build
();
}
}
src/main/java/emu/grasscutter/game/entity/EntityGadget.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.entity
;
import
emu.grasscutter.game.World
;
public
abstract
class
EntityGadget
extends
GenshinEntity
{
public
EntityGadget
(
World
world
)
{
super
(
world
);
}
public
abstract
int
getGadgetId
();
@Override
public
void
onDeath
(
int
killerId
)
{
}
}
src/main/java/emu/grasscutter/game/entity/EntityItem.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.entity
;
import
emu.grasscutter.data.def.ItemData
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.World
;
import
emu.grasscutter.game.inventory.GenshinItem
;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo
;
import
emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair
;
import
emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo
;
import
emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData
;
import
emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo
;
import
emu.grasscutter.net.proto.GadgetBornTypeOuterClass.GadgetBornType
;
import
emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo
;
import
emu.grasscutter.net.proto.PropPairOuterClass.PropPair
;
import
emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType
;
import
emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo
;
import
emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo
;
import
emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.utils.Position
;
import
emu.grasscutter.utils.ProtoHelper
;
import
it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap
;
public
class
EntityItem
extends
EntityGadget
{
private
final
Position
pos
;
private
final
Position
rot
;
private
final
GenshinItem
item
;
private
final
long
guid
;
public
EntityItem
(
World
world
,
GenshinPlayer
player
,
ItemData
itemData
,
Position
pos
,
int
count
)
{
super
(
world
);
this
.
id
=
world
.
getNextEntityId
(
EntityIdType
.
GADGET
);
this
.
pos
=
new
Position
(
pos
);
this
.
rot
=
new
Position
();
this
.
guid
=
player
.
getNextGuid
();
this
.
item
=
new
GenshinItem
(
itemData
,
count
);
}
@Override
public
int
getId
()
{
return
this
.
id
;
}
private
GenshinItem
getItem
()
{
return
this
.
item
;
}
public
ItemData
getItemData
()
{
return
this
.
getItem
().
getItemData
();
}
public
long
getGuid
()
{
return
guid
;
}
public
int
getCount
()
{
return
this
.
getItem
().
getCount
();
}
@Override
public
int
getGadgetId
()
{
return
this
.
getItemData
().
getGadgetId
();
}
@Override
public
Position
getPosition
()
{
return
this
.
pos
;
}
@Override
public
Position
getRotation
()
{
return
this
.
rot
;
}
@Override
public
Int2FloatOpenHashMap
getFightProperties
()
{
return
null
;
}
@Override
public
SceneEntityInfo
toProto
()
{
EntityAuthorityInfo
authority
=
EntityAuthorityInfo
.
newBuilder
()
.
setAbilityInfo
(
AbilitySyncStateInfo
.
newBuilder
())
.
setRendererChangedInfo
(
EntityRendererChangedInfo
.
newBuilder
())
.
setAiInfo
(
SceneEntityAiInfo
.
newBuilder
().
setIsAiOpen
(
true
).
setBornPos
(
Vector
.
newBuilder
()))
.
setBornPos
(
Vector
.
newBuilder
())
.
build
();
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
.
setEntityId
(
getId
())
.
setEntityType
(
ProtEntityType
.
ProtEntityGadget
)
.
setMotionInfo
(
MotionInfo
.
newBuilder
().
setPos
(
getPosition
().
toProto
()).
setRot
(
getRotation
().
toProto
()).
setSpeed
(
Vector
.
newBuilder
()))
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
.
setEntityAuthorityInfo
(
authority
)
.
setLifeState
(
1
);
PropPair
pair
=
PropPair
.
newBuilder
()
.
setType
(
PlayerProperty
.
PROP_LEVEL
.
getId
())
.
setPropValue
(
ProtoHelper
.
newPropValue
(
PlayerProperty
.
PROP_LEVEL
,
1
))
.
build
();
entityInfo
.
addPropList
(
pair
);
SceneGadgetInfo
.
Builder
gadgetInfo
=
SceneGadgetInfo
.
newBuilder
()
.
setGadgetId
(
this
.
getItemData
().
getGadgetId
())
.
setTrifleItem
(
this
.
getItem
().
toProto
())
.
setBornType
(
GadgetBornType
.
GadgetBornInAir
)
.
setAuthorityPeerId
(
this
.
getWorld
().
getHostPeerId
())
.
setIsEnableInteract
(
true
);
entityInfo
.
setGadget
(
gadgetInfo
);
return
entityInfo
.
build
();
}
}
Prev
1
2
3
4
5
6
7
8
…
18
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