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/game/entity/EntityMonster.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.entity
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.common.PropGrowCurve
;
import
emu.grasscutter.data.def.MonsterCurveData
;
import
emu.grasscutter.data.def.MonsterData
;
import
emu.grasscutter.game.World
;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.props.FightProperty
;
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.FightPropPairOuterClass.FightPropPair
;
import
emu.grasscutter.net.proto.MonsterBornTypeOuterClass.MonsterBornType
;
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.SceneMonsterInfoOuterClass.SceneMonsterInfo
;
import
emu.grasscutter.net.proto.SceneWeaponInfoOuterClass.SceneWeaponInfo
;
import
emu.grasscutter.utils.Position
;
import
emu.grasscutter.utils.ProtoHelper
;
import
it.unimi.dsi.fastutil.ints.Int2FloatMap
;
import
it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap
;
public
class
EntityMonster
extends
GenshinEntity
{
private
final
MonsterData
monsterData
;
private
final
Int2FloatOpenHashMap
fightProp
;
private
final
Position
pos
;
private
final
Position
rot
;
private
final
Position
bornPos
;
private
final
int
level
;
private
int
weaponEntityId
;
public
EntityMonster
(
World
world
,
MonsterData
monsterData
,
Position
pos
,
int
level
)
{
super
(
world
);
this
.
id
=
world
.
getNextEntityId
(
EntityIdType
.
MONSTER
);
this
.
monsterData
=
monsterData
;
this
.
fightProp
=
new
Int2FloatOpenHashMap
();
this
.
pos
=
new
Position
(
pos
);
this
.
rot
=
new
Position
();
this
.
bornPos
=
getPosition
().
clone
();
this
.
level
=
level
;
// Monster weapon
if
(
getMonsterWeaponId
()
>
0
)
{
this
.
weaponEntityId
=
world
.
getNextEntityId
(
EntityIdType
.
WEAPON
);
}
this
.
recalcStats
();
}
@Override
public
int
getId
()
{
return
this
.
id
;
}
public
MonsterData
getMonsterData
()
{
return
monsterData
;
}
public
int
getMonsterWeaponId
()
{
return
getMonsterData
().
getWeaponId
();
}
private
int
getMonsterId
()
{
return
this
.
getMonsterData
().
getId
();
}
public
int
getLevel
()
{
return
level
;
}
@Override
public
Position
getPosition
()
{
return
this
.
pos
;
}
@Override
public
Position
getRotation
()
{
return
this
.
rot
;
}
public
Position
getBornPos
()
{
return
bornPos
;
}
@Override
public
Int2FloatOpenHashMap
getFightProperties
()
{
return
fightProp
;
}
@Override
public
boolean
isAlive
()
{
return
this
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
)
>
0
f
;
}
@Override
public
void
onDeath
(
int
killerId
)
{
}
public
void
recalcStats
()
{
// Monster data
MonsterData
data
=
this
.
getMonsterData
();
// 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
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_BASE_ATTACK
,
data
.
getBaseAttack
());
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_BASE_DEFENSE
,
data
.
getBaseDefense
());
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_PHYSICAL_SUB_HURT
,
data
.
getPhysicalSubHurt
());
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_FIRE_SUB_HURT
,
.
1
f
);
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_ELEC_SUB_HURT
,
data
.
getElecSubHurt
());
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_WATER_SUB_HURT
,
data
.
getWaterSubHurt
());
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_GRASS_SUB_HURT
,
data
.
getGrassSubHurt
());
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_WIND_SUB_HURT
,
data
.
getWindSubHurt
());
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_ROCK_SUB_HURT
,
.
1
f
);
this
.
setFightProperty
(
FightProperty
.
FIGHT_PROP_ICE_SUB_HURT
,
data
.
getIceSubHurt
());
// Level curve
MonsterCurveData
curve
=
GenshinData
.
getMonsterCurveDataMap
().
get
(
this
.
getLevel
());
if
(
curve
!=
null
)
{
for
(
PropGrowCurve
growCurve
:
data
.
getPropGrowCurves
())
{
FightProperty
prop
=
FightProperty
.
getPropByName
(
growCurve
.
getType
());
this
.
setFightProperty
(
prop
,
this
.
getFightProperty
(
prop
)
*
curve
.
getMultByProp
(
growCurve
.
getGrowCurve
()));
}
}
// 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
);
}
@Override
public
SceneEntityInfo
toProto
()
{
EntityAuthorityInfo
authority
=
EntityAuthorityInfo
.
newBuilder
()
.
setAbilityInfo
(
AbilitySyncStateInfo
.
newBuilder
())
.
setRendererChangedInfo
(
EntityRendererChangedInfo
.
newBuilder
())
.
setAiInfo
(
SceneEntityAiInfo
.
newBuilder
().
setIsAiOpen
(
true
).
setBornPos
(
this
.
getBornPos
().
toProto
()))
.
setBornPos
(
this
.
getBornPos
().
toProto
())
.
build
();
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
.
setEntityId
(
getId
())
.
setEntityType
(
ProtEntityType
.
ProtEntityMonster
)
.
setMotionInfo
(
this
.
getMotionInfo
())
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
.
setEntityAuthorityInfo
(
authority
)
.
setLifeState
(
this
.
getLifeState
().
getValue
());
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
,
getLevel
()))
.
build
();
entityInfo
.
addPropList
(
pair
);
SceneMonsterInfo
.
Builder
monsterInfo
=
SceneMonsterInfo
.
newBuilder
()
.
setMonsterId
(
getMonsterId
())
.
setGroupId
(
133003095
)
.
setConfigId
(
95001
)
.
addAllAffixList
(
getMonsterData
().
getAffix
())
.
setAuthorityPeerId
(
getWorld
().
getHostPeerId
())
.
setPoseId
(
0
)
.
setBlockId
(
3001
)
.
setBornType
(
MonsterBornType
.
MonsterBornDefault
)
.
setSpecialNameId
(
40
);
if
(
getMonsterData
().
getDescribeData
()
!=
null
)
{
monsterInfo
.
setTitleId
(
getMonsterData
().
getDescribeData
().
getTitleID
());
}
if
(
this
.
getMonsterWeaponId
()
>
0
)
{
SceneWeaponInfo
weaponInfo
=
SceneWeaponInfo
.
newBuilder
()
.
setEntityId
(
this
.
weaponEntityId
)
.
setGadgetId
(
this
.
getMonsterWeaponId
())
.
setAbilityInfo
(
AbilitySyncStateInfo
.
newBuilder
())
.
build
();
monsterInfo
.
setWeaponList
(
weaponInfo
);
}
entityInfo
.
setMonster
(
monsterInfo
);
return
entityInfo
.
build
();
}
}
src/main/java/emu/grasscutter/game/entity/GenshinEntity.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.entity
;
import
emu.grasscutter.game.World
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo
;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.utils.Position
;
import
it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap
;
public
abstract
class
GenshinEntity
{
protected
int
id
;
private
final
World
world
;
private
MotionState
moveState
;
private
int
lastMoveSceneTimeMs
;
private
int
lastMoveReliableSeq
;
public
GenshinEntity
(
World
world
)
{
this
.
world
=
world
;
this
.
moveState
=
MotionState
.
MotionNone
;
}
public
int
getId
()
{
return
this
.
id
;
}
public
World
getWorld
()
{
return
world
;
}
public
boolean
isAlive
()
{
return
true
;
}
public
LifeState
getLifeState
()
{
return
isAlive
()
?
LifeState
.
LIFE_ALIVE
:
LifeState
.
LIFE_DEAD
;
}
public
abstract
Int2FloatOpenHashMap
getFightProperties
();
public
abstract
Position
getPosition
();
public
abstract
Position
getRotation
();
public
MotionState
getMotionState
()
{
return
moveState
;
}
public
void
setMotionState
(
MotionState
moveState
)
{
this
.
moveState
=
moveState
;
}
public
int
getLastMoveSceneTimeMs
()
{
return
lastMoveSceneTimeMs
;
}
public
void
setLastMoveSceneTimeMs
(
int
lastMoveSceneTimeMs
)
{
this
.
lastMoveSceneTimeMs
=
lastMoveSceneTimeMs
;
}
public
int
getLastMoveReliableSeq
()
{
return
lastMoveReliableSeq
;
}
public
void
setLastMoveReliableSeq
(
int
lastMoveReliableSeq
)
{
this
.
lastMoveReliableSeq
=
lastMoveReliableSeq
;
}
public
abstract
SceneEntityInfo
toProto
();
public
abstract
void
onDeath
(
int
killerId
);
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
);
}
protected
MotionInfo
getMotionInfo
()
{
MotionInfo
proto
=
MotionInfo
.
newBuilder
()
.
setPos
(
getPosition
().
toProto
())
.
setRot
(
getRotation
().
toProto
())
.
setSpeed
(
Vector
.
newBuilder
())
.
setState
(
this
.
getMotionState
())
.
build
();
return
proto
;
}
}
src/main/java/emu/grasscutter/game/friends/FriendsList.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.friends
;
import
java.util.List
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.net.proto.DealAddFriendResultTypeOuterClass.DealAddFriendResultType
;
import
emu.grasscutter.server.packet.send.PacketAskAddFriendNotify
;
import
emu.grasscutter.server.packet.send.PacketAskAddFriendRsp
;
import
emu.grasscutter.server.packet.send.PacketDealAddFriendRsp
;
import
emu.grasscutter.server.packet.send.PacketDeleteFriendNotify
;
import
emu.grasscutter.server.packet.send.PacketDeleteFriendRsp
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
public
class
FriendsList
{
private
final
GenshinPlayer
player
;
private
final
Int2ObjectMap
<
Friendship
>
friends
;
private
final
Int2ObjectMap
<
Friendship
>
pendingFriends
;
private
boolean
loaded
=
false
;
public
FriendsList
(
GenshinPlayer
player
)
{
this
.
player
=
player
;
this
.
friends
=
new
Int2ObjectOpenHashMap
<
Friendship
>();
this
.
pendingFriends
=
new
Int2ObjectOpenHashMap
<
Friendship
>();
}
public
GenshinPlayer
getPlayer
()
{
return
player
;
}
public
boolean
hasLoaded
()
{
return
loaded
;
}
public
synchronized
Int2ObjectMap
<
Friendship
>
getFriends
()
{
return
friends
;
}
public
synchronized
Int2ObjectMap
<
Friendship
>
getPendingFriends
()
{
return
this
.
pendingFriends
;
}
public
synchronized
boolean
isFriendsWith
(
int
uid
)
{
return
this
.
getFriends
().
containsKey
(
uid
);
}
private
synchronized
Friendship
getFriendshipById
(
int
id
)
{
Friendship
friendship
=
this
.
getFriends
().
get
(
id
);
if
(
friendship
==
null
)
{
friendship
=
this
.
getPendingFriendById
(
id
);
}
return
friendship
;
}
private
synchronized
Friendship
getFriendById
(
int
id
)
{
return
this
.
getFriends
().
get
(
id
);
}
private
synchronized
Friendship
getPendingFriendById
(
int
id
)
{
return
this
.
getPendingFriends
().
get
(
id
);
}
public
void
addFriend
(
Friendship
friendship
)
{
getFriends
().
put
(
friendship
.
getFriendId
(),
friendship
);
}
public
void
addPendingFriend
(
Friendship
friendship
)
{
getPendingFriends
().
put
(
friendship
.
getFriendId
(),
friendship
);
}
public
synchronized
void
handleFriendRequest
(
int
targetUid
,
DealAddFriendResultType
result
)
{
// Check if player has sent friend request
Friendship
myFriendship
=
this
.
getPendingFriendById
(
targetUid
);
if
(
myFriendship
==
null
)
{
return
;
}
// Make sure asker cant do anything
if
(
myFriendship
.
getAskerId
()
==
this
.
getPlayer
().
getId
())
{
return
;
}
GenshinPlayer
target
=
getPlayer
().
getSession
().
getServer
().
forceGetPlayerById
(
targetUid
);
if
(
target
==
null
)
{
return
;
// Should never happen
}
// Get target's friendship
Friendship
theirFriendship
=
null
;
if
(
target
.
isOnline
())
{
theirFriendship
=
target
.
getFriendsList
().
getPendingFriendById
(
this
.
getPlayer
().
getId
());
}
else
{
theirFriendship
=
DatabaseHelper
.
getReverseFriendship
(
myFriendship
);
}
if
(
theirFriendship
==
null
)
{
// They dont have us on their friends list anymore, rip
this
.
getPendingFriends
().
remove
(
myFriendship
.
getOwnerId
());
myFriendship
.
delete
();
return
;
}
// Handle
if
(
result
==
DealAddFriendResultType
.
DealAddFriendAccept
)
{
// Request accepted
myFriendship
.
setIsFriend
(
true
);
theirFriendship
.
setIsFriend
(
true
);
this
.
getPendingFriends
().
remove
(
myFriendship
.
getOwnerId
());
this
.
addFriend
(
myFriendship
);
if
(
target
.
isOnline
())
{
target
.
getFriendsList
().
getPendingFriends
().
remove
(
this
.
getPlayer
().
getId
());
target
.
getFriendsList
().
addFriend
(
theirFriendship
);
}
myFriendship
.
save
();
theirFriendship
.
save
();
}
else
{
// Request declined
// Delete from my pending friends
this
.
getPendingFriends
().
remove
(
myFriendship
.
getOwnerId
());
myFriendship
.
delete
();
// Delete from target uid
if
(
target
.
isOnline
())
{
theirFriendship
=
target
.
getFriendsList
().
getPendingFriendById
(
this
.
getPlayer
().
getId
());
}
theirFriendship
.
delete
();
}
// Packet
this
.
getPlayer
().
sendPacket
(
new
PacketDealAddFriendRsp
(
targetUid
,
result
));
}
public
synchronized
void
deleteFriend
(
int
targetUid
)
{
Friendship
myFriendship
=
this
.
getFriendById
(
targetUid
);
if
(
myFriendship
==
null
)
{
return
;
}
this
.
getFriends
().
remove
(
targetUid
);
myFriendship
.
delete
();
Friendship
theirFriendship
=
null
;
GenshinPlayer
friend
=
myFriendship
.
getFriendProfile
().
getPlayer
();
if
(
friend
!=
null
)
{
// Friend online
theirFriendship
=
friend
.
getFriendsList
().
getFriendById
(
this
.
getPlayer
().
getId
());
if
(
theirFriendship
!=
null
)
{
friend
.
getFriendsList
().
getFriends
().
remove
(
theirFriendship
.
getFriendId
());
theirFriendship
.
delete
();
friend
.
sendPacket
(
new
PacketDeleteFriendNotify
(
theirFriendship
.
getFriendId
()));
}
}
else
{
// Friend offline
theirFriendship
=
DatabaseHelper
.
getReverseFriendship
(
myFriendship
);
if
(
theirFriendship
!=
null
)
{
theirFriendship
.
delete
();
}
}
// Packet
this
.
getPlayer
().
sendPacket
(
new
PacketDeleteFriendRsp
(
targetUid
));
}
public
synchronized
void
sendFriendRequest
(
int
targetUid
)
{
GenshinPlayer
target
=
getPlayer
().
getSession
().
getServer
().
forceGetPlayerById
(
targetUid
);
if
(
target
==
null
||
target
==
this
.
getPlayer
())
{
return
;
}
// Check if friend already exists
if
(
this
.
getPendingFriends
().
containsKey
(
targetUid
)
||
this
.
getFriends
().
containsKey
(
targetUid
))
{
return
;
}
// Create friendships
Friendship
myFriendship
=
new
Friendship
(
getPlayer
(),
target
,
getPlayer
());
Friendship
theirFriendship
=
new
Friendship
(
target
,
getPlayer
(),
getPlayer
());
// Add pending lists
this
.
addPendingFriend
(
myFriendship
);
if
(
target
.
isOnline
()
&&
target
.
getFriendsList
().
hasLoaded
())
{
target
.
getFriendsList
().
addPendingFriend
(
theirFriendship
);
target
.
sendPacket
(
new
PacketAskAddFriendNotify
(
theirFriendship
));
}
// Save
myFriendship
.
save
();
theirFriendship
.
save
();
// Packets
this
.
getPlayer
().
sendPacket
(
new
PacketAskAddFriendRsp
(
targetUid
));
}
/** Gets total amount of potential friends
* */
public
int
getFullFriendCount
()
{
return
this
.
getPendingFriends
().
size
()
+
this
.
getFriends
().
size
();
}
public
synchronized
void
loadFromDatabase
()
{
if
(
this
.
hasLoaded
())
{
return
;
}
// Get friendships from the db
List
<
Friendship
>
friendships
=
DatabaseHelper
.
getFriends
(
player
);
friendships
.
forEach
(
this
::
loadFriendFromDatabase
);
// Set loaded flag
this
.
loaded
=
true
;
}
private
void
loadFriendFromDatabase
(
Friendship
friendship
)
{
// Set friendship owner
friendship
.
setOwner
(
getPlayer
());
// Check if friend is online
GenshinPlayer
friend
=
getPlayer
().
getSession
().
getServer
().
getPlayerById
(
friendship
.
getFriendProfile
().
getId
());
if
(
friend
!=
null
)
{
// Set friend to online mode
friendship
.
setFriendProfile
(
friend
);
// Update our status on friend's client if theyre online
if
(
friend
.
getFriendsList
().
hasLoaded
())
{
Friendship
theirFriendship
=
friend
.
getFriendsList
().
getFriendshipById
(
getPlayer
().
getId
());
if
(
theirFriendship
!=
null
)
{
// Update friend profile
theirFriendship
.
setFriendProfile
(
getPlayer
());
}
else
{
// They dont have us on their friends list anymore, rip
friendship
.
delete
();
return
;
}
}
}
// Finally, load to our friends list
if
(
friendship
.
isFriend
())
{
getFriends
().
put
(
friendship
.
getFriendId
(),
friendship
);
}
else
{
getPendingFriends
().
put
(
friendship
.
getFriendId
(),
friendship
);
// TODO - Hacky fix to force client to see a notification for a friendship
if
(
getPendingFriends
().
size
()
==
1
)
{
getPlayer
().
getSession
().
send
(
new
PacketAskAddFriendNotify
(
friendship
));
}
}
}
public
void
save
()
{
// Update all our friends
List
<
Friendship
>
friendships
=
DatabaseHelper
.
getReverseFriends
(
getPlayer
());
for
(
Friendship
friend
:
friendships
)
{
friend
.
setFriendProfile
(
this
.
getPlayer
());
friend
.
save
();
}
}
}
src/main/java/emu/grasscutter/game/friends/Friendship.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.friends
;
import
org.bson.types.ObjectId
;
import
dev.morphia.annotations.*
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.net.proto.FriendBriefOuterClass.FriendBrief
;
import
emu.grasscutter.net.proto.FriendOnlineStateOuterClass.FriendOnlineState
;
import
emu.grasscutter.net.proto.HeadImageOuterClass.HeadImage
;
@Entity
(
value
=
"friendships"
,
noClassnameStored
=
true
)
public
class
Friendship
{
@Id
private
ObjectId
id
;
@Transient
private
GenshinPlayer
owner
;
@Indexed
private
int
ownerId
;
@Indexed
private
int
friendId
;
private
boolean
isFriend
;
private
int
askerId
;
private
PlayerProfile
profile
;
@Deprecated
// Morphia use only
public
Friendship
()
{
}
public
Friendship
(
GenshinPlayer
owner
,
GenshinPlayer
friend
,
GenshinPlayer
asker
)
{
this
.
setOwner
(
owner
);
this
.
ownerId
=
owner
.
getId
();
this
.
friendId
=
friend
.
getId
();
this
.
profile
=
friend
.
getProfile
();
this
.
askerId
=
asker
.
getId
();
}
public
GenshinPlayer
getOwner
()
{
return
owner
;
}
public
void
setOwner
(
GenshinPlayer
owner
)
{
this
.
owner
=
owner
;
}
public
boolean
isFriend
()
{
return
isFriend
;
}
public
void
setIsFriend
(
boolean
b
)
{
this
.
isFriend
=
b
;
}
public
int
getOwnerId
()
{
return
ownerId
;
}
public
int
getFriendId
()
{
return
friendId
;
}
public
int
getAskerId
()
{
return
askerId
;
}
public
void
setAskerId
(
int
askerId
)
{
this
.
askerId
=
askerId
;
}
public
PlayerProfile
getFriendProfile
()
{
return
profile
;
}
public
void
setFriendProfile
(
GenshinPlayer
character
)
{
if
(
character
==
null
||
this
.
friendId
!=
character
.
getId
())
return
;
this
.
profile
=
character
.
getProfile
();
}
public
boolean
isOnline
()
{
return
getFriendProfile
().
getPlayer
()
!=
null
;
}
public
void
save
()
{
DatabaseHelper
.
saveFriendship
(
this
);
}
public
void
delete
()
{
DatabaseHelper
.
deleteFriendship
(
this
);
}
public
FriendBrief
toProto
()
{
FriendBrief
proto
=
FriendBrief
.
newBuilder
()
.
setUid
(
getFriendProfile
().
getId
())
.
setNickname
(
getFriendProfile
().
getName
())
.
setLevel
(
getFriendProfile
().
getPlayerLevel
())
.
setAvatar
(
HeadImage
.
newBuilder
().
setAvatarId
(
getFriendProfile
().
getAvatarId
()))
.
setWorldLevel
(
getFriendProfile
().
getWorldLevel
())
.
setSignature
(
getFriendProfile
().
getSignature
())
.
setOnlineState
(
getFriendProfile
().
isOnline
()
?
FriendOnlineState
.
FRIEND_ONLINE
:
FriendOnlineState
.
FRIEND_DISCONNECT
)
.
setIsMpModeAvailable
(
true
)
.
setLastActiveTime
(
getFriendProfile
().
getLastActiveTime
())
.
setNameCardId
(
getFriendProfile
().
getNameCard
())
.
setParam
(
getFriendProfile
().
getDaysSinceLogin
())
.
setUnk1
(
1
)
.
setUnk2
(
3
)
.
build
();
return
proto
;
}
}
src/main/java/emu/grasscutter/game/friends/PlayerProfile.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.friends
;
import
dev.morphia.annotations.*
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.utils.Utils
;
public
class
PlayerProfile
{
@Transient
private
GenshinPlayer
player
;
private
int
id
;
private
int
nameCard
;
private
int
avatarId
;
private
String
name
;
private
String
signature
;
private
int
achievements
;
private
int
playerLevel
;
private
int
worldLevel
;
private
int
lastActiveTime
;
@Deprecated
// Morphia only
public
PlayerProfile
()
{
}
public
PlayerProfile
(
GenshinPlayer
player
)
{
this
.
id
=
player
.
getId
();
this
.
syncWithCharacter
(
player
);
}
public
int
getId
()
{
return
id
;
}
public
GenshinPlayer
getPlayer
()
{
return
player
;
}
public
synchronized
void
setPlayer
(
GenshinPlayer
player
)
{
this
.
player
=
player
;
}
public
String
getName
()
{
return
name
;
}
public
int
getNameCard
()
{
return
nameCard
;
}
public
int
getAvatarId
()
{
return
avatarId
;
}
public
String
getSignature
()
{
return
signature
;
}
public
int
getAchievements
()
{
return
achievements
;
}
public
int
getPlayerLevel
()
{
return
playerLevel
;
}
public
int
getWorldLevel
()
{
return
worldLevel
;
}
public
int
getLastActiveTime
()
{
return
lastActiveTime
;
}
public
void
updateLastActiveTime
()
{
this
.
lastActiveTime
=
Utils
.
getCurrentSeconds
();
}
public
int
getDaysSinceLogin
()
{
return
(
int
)
Math
.
floor
((
Utils
.
getCurrentSeconds
()
-
getLastActiveTime
())
/
86400.0
);
}
public
boolean
isOnline
()
{
return
this
.
getPlayer
()
!=
null
;
}
public
void
syncWithCharacter
(
GenshinPlayer
player
)
{
if
(
player
==
null
)
{
return
;
}
this
.
name
=
player
.
getNickname
();
this
.
avatarId
=
player
.
getHeadImage
();
this
.
signature
=
player
.
getSignature
();
this
.
nameCard
=
player
.
getNameCardId
();
this
.
playerLevel
=
player
.
getLevel
();
this
.
worldLevel
=
player
.
getWorldLevel
();
//this.achievements = 0;
this
.
updateLastActiveTime
();
}
}
src/main/java/emu/grasscutter/game/gacha/GachaBanner.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.gacha
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo
;
import
emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo
;
public
class
GachaBanner
{
private
int
gachaType
;
private
int
scheduleId
;
private
String
prefabPath
;
private
String
previewPrefabPath
;
private
String
titlePath
;
private
int
costItem
;
private
int
beginTime
;
private
int
endTime
;
private
int
sortId
;
private
int
[]
rateUpItems1
;
private
int
[]
rateUpItems2
;
private
int
minItemType
=
1
;
private
int
maxItemType
=
2
;
private
int
eventChance
=
50
;
// Chance to win a featured event item
private
int
softPity
=
75
;
private
int
hardPity
=
90
;
private
BannerType
bannerType
=
BannerType
.
STANDARD
;
public
int
getGachaType
()
{
return
gachaType
;
}
public
BannerType
getBannerType
()
{
return
bannerType
;
}
public
int
getScheduleId
()
{
return
scheduleId
;
}
public
String
getPrefabPath
()
{
return
prefabPath
;
}
public
String
getPreviewPrefabPath
()
{
return
previewPrefabPath
;
}
public
String
getTitlePath
()
{
return
titlePath
;
}
public
int
getCostItem
()
{
return
costItem
;
}
public
int
getBeginTime
()
{
return
beginTime
;
}
public
int
getEndTime
()
{
return
endTime
;
}
public
int
getSortId
()
{
return
sortId
;
}
public
int
[]
getRateUpItems1
()
{
return
rateUpItems1
;
}
public
int
[]
getRateUpItems2
()
{
return
rateUpItems2
;
}
public
int
getMinItemType
()
{
return
minItemType
;
}
public
int
getMaxItemType
()
{
return
maxItemType
;
}
public
int
getSoftPity
()
{
return
softPity
-
1
;
}
public
int
getHardPity
()
{
return
hardPity
-
1
;
}
public
int
getEventChance
()
{
return
eventChance
;
}
public
GachaInfo
toProto
()
{
String
record
=
"http://"
+
Grasscutter
.
getConfig
().
DispatchServerIp
+
"/gacha"
;
GachaInfo
.
Builder
info
=
GachaInfo
.
newBuilder
()
.
setGachaType
(
this
.
getGachaType
())
.
setScheduleId
(
this
.
getScheduleId
())
.
setBeginTime
(
this
.
getBeginTime
())
.
setEndTime
(
this
.
getEndTime
())
.
setCostItemId
(
this
.
getCostItem
())
.
setCostItemNum
(
1
)
.
setGachaPrefabPath
(
this
.
getPrefabPath
())
.
setGachaPreviewPrefabPath
(
this
.
getPreviewPrefabPath
())
.
setGachaProbUrl
(
record
)
.
setGachaProbUrlOversea
(
record
)
.
setGachaRecordUrl
(
record
)
.
setGachaRecordUrlOversea
(
record
)
.
setTenCostItemId
(
this
.
getCostItem
())
.
setTenCostItemNum
(
10
)
.
setLeftGachaTimes
(
Integer
.
MAX_VALUE
)
.
setGachaTimesLimit
(
Integer
.
MAX_VALUE
)
.
setGachaSortId
(
this
.
getSortId
());
if
(
this
.
getTitlePath
()
!=
null
)
{
info
.
setGachaTitlePath
(
this
.
getTitlePath
());
}
if
(
this
.
getRateUpItems1
().
length
>
0
)
{
GachaUpInfo
.
Builder
upInfo
=
GachaUpInfo
.
newBuilder
().
setItemParentType
(
1
);
for
(
int
id
:
getRateUpItems1
())
{
upInfo
.
addItemIdList
(
id
);
info
.
addMainNameId
(
id
);
}
info
.
addGachaUpInfoList
(
upInfo
);
}
if
(
this
.
getRateUpItems2
().
length
>
0
)
{
GachaUpInfo
.
Builder
upInfo
=
GachaUpInfo
.
newBuilder
().
setItemParentType
(
2
);
for
(
int
id
:
getRateUpItems2
())
{
upInfo
.
addItemIdList
(
id
);
if
(
info
.
getSubNameIdCount
()
==
0
)
{
info
.
addSubNameId
(
id
);
}
}
info
.
addGachaUpInfoList
(
upInfo
);
}
return
info
.
build
();
}
public
enum
BannerType
{
STANDARD
,
EVENT
,
WEAPON
;
}
}
src/main/java/emu/grasscutter/game/gacha/GachaManager.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.gacha
;
import
java.io.FileReader
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.List
;
import
java.util.concurrent.ThreadLocalRandom
;
import
com.google.gson.reflect.TypeToken
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.def.ItemData
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.avatar.GenshinAvatar
;
import
emu.grasscutter.game.inventory.GenshinItem
;
import
emu.grasscutter.game.inventory.ItemType
;
import
emu.grasscutter.game.inventory.MaterialType
;
import
emu.grasscutter.net.proto.GachaItemOuterClass.GachaItem
;
import
emu.grasscutter.net.proto.GachaTransferItemOuterClass.GachaTransferItem
;
import
emu.grasscutter.net.proto.GetGachaInfoRspOuterClass.GetGachaInfoRsp
;
import
emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.packet.send.PacketDoGachaRsp
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.IntArrayList
;
import
it.unimi.dsi.fastutil.ints.IntList
;
public
class
GachaManager
{
private
final
GameServer
server
;
private
final
Int2ObjectMap
<
GachaBanner
>
gachaBanners
;
private
GetGachaInfoRsp
cachedProto
;
private
int
[]
yellowAvatars
=
new
int
[]
{
1003
,
1016
,
1042
,
1035
,
1041
};
private
int
[]
yellowWeapons
=
new
int
[]
{
11501
,
11502
,
12501
,
12502
,
13502
,
13505
,
14501
,
14502
,
15501
,
15502
};
private
int
[]
purpleAvatars
=
new
int
[]
{
1006
,
1014
,
1015
,
1020
,
1021
,
1023
,
1024
,
1025
,
1027
,
1031
,
1032
,
1034
,
1036
,
1039
,
1043
,
1044
,
1045
,
1048
,
1053
,
1055
,
1056
,
1064
};
private
int
[]
purpleWeapons
=
new
int
[]
{
11401
,
11402
,
11403
,
11405
,
12401
,
12402
,
12403
,
12405
,
13401
,
13407
,
14401
,
14402
,
14403
,
14409
,
15401
,
15402
,
15403
,
15405
};
private
int
[]
blueWeapons
=
new
int
[]
{
11301
,
11302
,
11306
,
12301
,
12302
,
12305
,
13303
,
14301
,
14302
,
14304
,
15301
,
15302
,
15304
};
private
static
int
starglitterId
=
221
;
private
static
int
stardustId
=
222
;
public
GachaManager
(
GameServer
server
)
{
this
.
server
=
server
;
this
.
gachaBanners
=
new
Int2ObjectOpenHashMap
<>();
this
.
load
();
}
public
GameServer
getServer
()
{
return
server
;
}
public
Int2ObjectMap
<
GachaBanner
>
getGachaBanners
()
{
return
gachaBanners
;
}
public
int
randomRange
(
int
min
,
int
max
)
{
return
ThreadLocalRandom
.
current
().
nextInt
(
max
-
min
+
1
)
+
min
;
}
public
int
getRandom
(
int
[]
array
)
{
return
array
[
randomRange
(
0
,
array
.
length
-
1
)];
}
public
synchronized
void
load
()
{
try
(
FileReader
fileReader
=
new
FileReader
(
Grasscutter
.
getConfig
().
DATA_FOLDER
+
"Banners.json"
))
{
List
<
GachaBanner
>
banners
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
TypeToken
.
getParameterized
(
Collection
.
class
,
GachaBanner
.
class
).
getType
());
for
(
GachaBanner
banner
:
banners
)
{
getGachaBanners
().
put
(
banner
.
getGachaType
(),
banner
);
}
}
catch
(
Exception
e
)
{
// TODO Auto-generated catch block
e
.
printStackTrace
();
}
}
public
synchronized
void
doPulls
(
GenshinPlayer
player
,
int
gachaType
,
int
times
)
{
// Sanity check
if
(
times
!=
10
&&
times
!=
1
)
{
return
;
}
if
(
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_WEAPON
).
getSize
()
+
times
>
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_WEAPON
).
getMaxCapacity
())
{
player
.
sendPacket
(
new
PacketDoGachaRsp
());
return
;
}
// Get banner
GachaBanner
banner
=
this
.
getGachaBanners
().
get
(
gachaType
);
if
(
banner
==
null
)
{
player
.
sendPacket
(
new
PacketDoGachaRsp
());
return
;
}
// Spend currency
if
(
banner
.
getCostItem
()
>
0
)
{
GenshinItem
costItem
=
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
banner
.
getCostItem
());
if
(
costItem
==
null
||
costItem
.
getCount
()
<
times
)
{
return
;
}
player
.
getInventory
().
removeItem
(
costItem
,
times
);
}
// Roll
PlayerGachaBannerInfo
gachaInfo
=
player
.
getGachaInfo
().
getBannerInfo
(
banner
);
IntList
wonItems
=
new
IntArrayList
(
times
);
for
(
int
i
=
0
;
i
<
times
;
i
++)
{
int
random
=
this
.
randomRange
(
1
,
10000
);
int
itemId
=
0
;
int
bonusYellowChance
=
gachaInfo
.
getPity5
()
>=
banner
.
getSoftPity
()
?
100
*
(
gachaInfo
.
getPity5
()
-
banner
.
getSoftPity
()
-
1
):
0
;
int
yellowChance
=
60
+
(
int
)
Math
.
floor
(
100
f
*
(
gachaInfo
.
getPity5
()
/
(
banner
.
getSoftPity
()
-
1
D
)))
+
bonusYellowChance
;
int
purpleChance
=
10000
-
(
510
+
(
int
)
Math
.
floor
(
790
f
*
(
gachaInfo
.
getPity4
()
/
8
f
)));
if
(
random
<=
yellowChance
||
gachaInfo
.
getPity5
()
>=
banner
.
getHardPity
())
{
if
(
banner
.
getRateUpItems1
().
length
>
0
)
{
int
eventChance
=
this
.
randomRange
(
1
,
100
);
if
(
eventChance
>=
banner
.
getEventChance
()
||
gachaInfo
.
getFailedFeaturedItemPulls
()
>=
1
)
{
itemId
=
getRandom
(
banner
.
getRateUpItems1
());
gachaInfo
.
setFailedFeaturedItemPulls
(
0
);
}
else
{
// Lost the 50/50... rip
gachaInfo
.
addFailedFeaturedItemPulls
(
1
);
}
}
if
(
itemId
==
0
)
{
int
typeChance
=
this
.
randomRange
(
banner
.
getMinItemType
(),
banner
.
getMaxItemType
());
if
(
typeChance
==
1
)
{
itemId
=
getRandom
(
this
.
yellowAvatars
);
}
else
{
itemId
=
getRandom
(
this
.
yellowWeapons
);
}
}
// Pity
gachaInfo
.
addPity4
(
1
);
gachaInfo
.
setPity5
(
0
);
}
else
if
(
random
>=
purpleChance
||
gachaInfo
.
getPity4
()
>=
9
)
{
if
(
banner
.
getRateUpItems2
().
length
>
0
)
{
int
eventChance
=
this
.
randomRange
(
1
,
100
);
if
(
eventChance
>=
50
)
{
itemId
=
getRandom
(
banner
.
getRateUpItems2
());
}
}
if
(
itemId
==
0
)
{
int
typeChance
=
this
.
randomRange
(
banner
.
getMinItemType
(),
banner
.
getMaxItemType
());
if
(
typeChance
==
1
)
{
itemId
=
getRandom
(
this
.
purpleAvatars
);
}
else
{
itemId
=
getRandom
(
this
.
purpleWeapons
);
}
}
// Pity
gachaInfo
.
addPity5
(
1
);
gachaInfo
.
setPity4
(
0
);
}
else
{
itemId
=
getRandom
(
this
.
blueWeapons
);
// Pity
gachaInfo
.
addPity4
(
1
);
gachaInfo
.
addPity5
(
1
);
}
// Add winning item
wonItems
.
add
(
itemId
);
}
// Add to character
List
<
GachaItem
>
list
=
new
ArrayList
<>();
int
stardust
=
0
,
starglitter
=
0
;
for
(
int
itemId
:
wonItems
)
{
ItemData
itemData
=
GenshinData
.
getItemDataMap
().
get
(
itemId
);
if
(
itemData
==
null
)
{
continue
;
}
// Create gacha item
GachaItem
.
Builder
gachaItem
=
GachaItem
.
newBuilder
();
int
addStardust
=
0
,
addStarglitter
=
0
;
boolean
isTransferItem
=
false
;
// Const check
if
(
itemData
.
getMaterialType
()
==
MaterialType
.
MATERIAL_AVATAR
)
{
int
avatarId
=
(
itemData
.
getId
()
%
1000
)
+
10000000
;
GenshinAvatar
avatar
=
player
.
getAvatars
().
getAvatarById
(
avatarId
);
if
(
avatar
!=
null
)
{
int
constLevel
=
avatar
.
getCoreProudSkillLevel
();
int
constItemId
=
itemData
.
getId
()
+
100
;
GenshinItem
constItem
=
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
constItemId
);
if
(
constItem
!=
null
)
{
constLevel
+=
constItem
.
getCount
();
}
if
(
constLevel
<
6
)
{
// Not max const
addStarglitter
=
2
;
// Add 1 const
gachaItem
.
addTransferItems
(
GachaTransferItem
.
newBuilder
().
setItem
(
ItemParam
.
newBuilder
().
setItemId
(
constItemId
).
setCount
(
1
)).
setIsTransferItemNew
(
constItem
==
null
));
gachaItem
.
addTokenItemList
(
ItemParam
.
newBuilder
().
setItemId
(
constItemId
).
setCount
(
1
));
player
.
getInventory
().
addItem
(
constItemId
,
1
);
}
else
{
// Is max const
addStarglitter
=
5
;
}
if
(
itemData
.
getRankLevel
()
==
5
)
{
addStarglitter
*=
5
;
}
isTransferItem
=
true
;
}
else
{
// New
gachaItem
.
setIsGachaItemNew
(
true
);
}
}
else
{
// Is weapon
switch
(
itemData
.
getRankLevel
())
{
case
5
:
addStarglitter
=
10
;
break
;
case
4
:
addStarglitter
=
2
;
break
;
case
3
:
addStardust
=
15
;
break
;
}
}
// Create item
GenshinItem
item
=
new
GenshinItem
(
itemData
);
gachaItem
.
setGachaItem
(
item
.
toItemParam
());
player
.
getInventory
().
addItem
(
item
);
stardust
+=
addStardust
;
starglitter
+=
addStarglitter
;
if
(
addStardust
>
0
)
{
gachaItem
.
addTokenItemList
(
ItemParam
.
newBuilder
().
setItemId
(
stardustId
).
setCount
(
addStardust
));
}
if
(
addStarglitter
>
0
)
{
ItemParam
starglitterParam
=
ItemParam
.
newBuilder
().
setItemId
(
starglitterId
).
setCount
(
addStarglitter
).
build
();
if
(
isTransferItem
)
{
gachaItem
.
addTransferItems
(
GachaTransferItem
.
newBuilder
().
setItem
(
starglitterParam
));
}
gachaItem
.
addTokenItemList
(
starglitterParam
);
}
list
.
add
(
gachaItem
.
build
());
}
// Add stardust/starglitter
if
(
stardust
>
0
)
{
player
.
getInventory
().
addItem
(
stardustId
,
stardust
);
}
if
(
starglitter
>
0
)
{
player
.
getInventory
().
addItem
(
starglitterId
,
starglitter
);
}
// Packets
player
.
sendPacket
(
new
PacketDoGachaRsp
(
banner
,
list
));
}
private
synchronized
GetGachaInfoRsp
createProto
()
{
GetGachaInfoRsp
.
Builder
proto
=
GetGachaInfoRsp
.
newBuilder
().
setGachaRandom
(
12345
);
for
(
GachaBanner
banner
:
getGachaBanners
().
values
())
{
proto
.
addGachaInfoList
(
banner
.
toProto
());
}
return
proto
.
build
();
}
public
GetGachaInfoRsp
toProto
()
{
if
(
this
.
cachedProto
==
null
)
{
this
.
cachedProto
=
createProto
();
}
return
this
.
cachedProto
;
}
}
src/main/java/emu/grasscutter/game/gacha/PlayerGachaBannerInfo.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.gacha
;
public
class
PlayerGachaBannerInfo
{
private
int
pity5
=
0
;
private
int
pity4
=
0
;
private
int
failedFeaturedItemPulls
=
0
;
public
int
getPity5
()
{
return
pity5
;
}
public
void
setPity5
(
int
pity5
)
{
this
.
pity5
=
pity5
;
}
public
void
addPity5
(
int
amount
)
{
this
.
pity5
+=
amount
;
}
public
int
getPity4
()
{
return
pity4
;
}
public
void
setPity4
(
int
pity4
)
{
this
.
pity4
=
pity4
;
}
public
void
addPity4
(
int
amount
)
{
this
.
pity4
+=
amount
;
}
public
int
getFailedFeaturedItemPulls
()
{
return
failedFeaturedItemPulls
;
}
public
void
setFailedFeaturedItemPulls
(
int
failedEventCharacterPulls
)
{
this
.
failedFeaturedItemPulls
=
failedEventCharacterPulls
;
}
public
void
addFailedFeaturedItemPulls
(
int
amount
)
{
failedFeaturedItemPulls
+=
amount
;
}
}
src/main/java/emu/grasscutter/game/gacha/PlayerGachaInfo.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.gacha
;
public
class
PlayerGachaInfo
{
private
PlayerGachaBannerInfo
standardBanner
;
private
PlayerGachaBannerInfo
eventCharacterBanner
;
private
PlayerGachaBannerInfo
eventWeaponBanner
;
public
PlayerGachaInfo
()
{
this
.
standardBanner
=
new
PlayerGachaBannerInfo
();
this
.
eventCharacterBanner
=
new
PlayerGachaBannerInfo
();
this
.
eventWeaponBanner
=
new
PlayerGachaBannerInfo
();
}
public
PlayerGachaBannerInfo
getStandardBanner
()
{
return
standardBanner
;
}
public
PlayerGachaBannerInfo
getEventCharacterBanner
()
{
return
eventCharacterBanner
;
}
public
PlayerGachaBannerInfo
getEventWeaponBanner
()
{
return
eventWeaponBanner
;
}
public
PlayerGachaBannerInfo
getBannerInfo
(
GachaBanner
banner
)
{
switch
(
banner
.
getBannerType
())
{
case
EVENT:
return
this
.
eventCharacterBanner
;
case
WEAPON:
return
this
.
eventWeaponBanner
;
case
STANDARD:
default
:
return
this
.
standardBanner
;
}
}
}
src/main/java/emu/grasscutter/game/inventory/EquipInventoryTab.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.inventory
;
import
java.util.HashSet
;
import
java.util.Set
;
public
class
EquipInventoryTab
implements
InventoryTab
{
private
final
Set
<
GenshinItem
>
items
;
private
final
int
maxCapacity
;
public
EquipInventoryTab
(
int
maxCapacity
)
{
this
.
items
=
new
HashSet
<
GenshinItem
>();
this
.
maxCapacity
=
maxCapacity
;
}
@Override
public
GenshinItem
getItemById
(
int
id
)
{
return
null
;
}
@Override
public
void
onAddItem
(
GenshinItem
item
)
{
this
.
items
.
add
(
item
);
}
@Override
public
void
onRemoveItem
(
GenshinItem
item
)
{
this
.
items
.
remove
(
item
);
}
@Override
public
int
getSize
()
{
return
this
.
items
.
size
();
}
@Override
public
int
getMaxCapacity
()
{
return
this
.
maxCapacity
;
}
}
src/main/java/emu/grasscutter/game/inventory/EquipType.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.inventory
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.stream.Stream
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
public
enum
EquipType
{
EQUIP_NONE
(
0
),
EQUIP_BRACER
(
1
),
EQUIP_NECKLACE
(
2
),
EQUIP_SHOES
(
3
),
EQUIP_RING
(
4
),
EQUIP_DRESS
(
5
),
EQUIP_WEAPON
(
6
);
private
final
int
value
;
private
static
final
Int2ObjectMap
<
EquipType
>
map
=
new
Int2ObjectOpenHashMap
<>();
private
static
final
Map
<
String
,
EquipType
>
stringMap
=
new
HashMap
<>();
static
{
Stream
.
of
(
values
()).
forEach
(
e
->
{
map
.
put
(
e
.
getValue
(),
e
);
stringMap
.
put
(
e
.
name
(),
e
);
});
}
private
EquipType
(
int
value
)
{
this
.
value
=
value
;
}
public
int
getValue
()
{
return
value
;
}
public
static
EquipType
getTypeByValue
(
int
value
)
{
return
map
.
getOrDefault
(
value
,
EQUIP_NONE
);
}
public
static
EquipType
getTypeByName
(
String
name
)
{
return
stringMap
.
getOrDefault
(
name
,
EQUIP_NONE
);
}
}
src/main/java/emu/grasscutter/game/inventory/GenshinItem.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.inventory
;
import
java.util.ArrayList
;
import
java.util.HashSet
;
import
java.util.List
;
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.Transient
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.GenshinDepot
;
import
emu.grasscutter.data.def.ItemData
;
import
emu.grasscutter.data.def.ReliquaryAffixData
;
import
emu.grasscutter.data.def.ReliquaryMainPropData
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo
;
import
emu.grasscutter.net.proto.EquipOuterClass.Equip
;
import
emu.grasscutter.net.proto.FurnitureOuterClass.Furniture
;
import
emu.grasscutter.net.proto.ItemHintOuterClass.ItemHint
;
import
emu.grasscutter.net.proto.ItemOuterClass.Item
;
import
emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam
;
import
emu.grasscutter.net.proto.MaterialOuterClass.Material
;
import
emu.grasscutter.net.proto.ReliquaryOuterClass.Reliquary
;
import
emu.grasscutter.net.proto.SceneReliquaryInfoOuterClass.SceneReliquaryInfo
;
import
emu.grasscutter.net.proto.SceneWeaponInfoOuterClass.SceneWeaponInfo
;
import
emu.grasscutter.net.proto.WeaponOuterClass.Weapon
;
import
emu.grasscutter.utils.WeightedList
;
@Entity
(
value
=
"items"
,
noClassnameStored
=
true
)
public
class
GenshinItem
{
@Id
private
ObjectId
id
;
@Indexed
private
int
ownerId
;
private
int
itemId
;
private
int
count
;
@Transient
private
long
guid
;
// Player unique id
@Transient
private
ItemData
itemData
;
// Equips
private
int
level
;
private
int
exp
;
private
int
totalExp
;
private
int
promoteLevel
;
private
boolean
locked
;
// Weapon
private
List
<
Integer
>
affixes
;
private
int
refinement
=
0
;
// Relic
private
int
mainPropId
;
private
List
<
Integer
>
appendPropIdList
;
private
int
equipCharacter
;
@Transient
private
int
weaponEntityId
;
public
GenshinItem
()
{
// Morphia only
}
public
GenshinItem
(
int
itemId
)
{
this
(
GenshinData
.
getItemDataMap
().
get
(
itemId
));
}
public
GenshinItem
(
int
itemId
,
int
count
)
{
this
(
GenshinData
.
getItemDataMap
().
get
(
itemId
),
count
);
}
public
GenshinItem
(
ItemData
data
)
{
this
(
data
,
1
);
}
public
GenshinItem
(
ItemData
data
,
int
count
)
{
this
.
itemId
=
data
.
getId
();
this
.
itemData
=
data
;
if
(
data
.
getItemType
()
==
ItemType
.
ITEM_VIRTUAL
)
{
this
.
count
=
count
;
}
else
{
this
.
count
=
Math
.
min
(
count
,
data
.
getStackLimit
());
}
// Equip data
if
(
getItemType
()
==
ItemType
.
ITEM_WEAPON
)
{
this
.
level
=
1
;
this
.
affixes
=
new
ArrayList
<>(
2
);
if
(
getItemData
().
getSkillAffix
()
!=
null
)
{
for
(
int
skillAffix
:
getItemData
().
getSkillAffix
())
{
if
(
skillAffix
>
0
)
{
this
.
affixes
.
add
(
skillAffix
);
}
}
}
}
else
if
(
getItemType
()
==
ItemType
.
ITEM_RELIQUARY
)
{
this
.
level
=
1
;
this
.
appendPropIdList
=
new
ArrayList
<>();
// Create main property
ReliquaryMainPropData
mainPropData
=
GenshinDepot
.
getRandomRelicMainProp
(
getItemData
().
getMainPropDepotId
());
if
(
mainPropData
!=
null
)
{
this
.
mainPropId
=
mainPropData
.
getId
();
}
// Create extra stats
if
(
getItemData
().
getAppendPropNum
()
>
0
)
{
for
(
int
i
=
0
;
i
<
getItemData
().
getAppendPropNum
();
i
++)
{
this
.
addAppendProp
();
}
}
}
}
public
ObjectId
getObjectId
()
{
return
id
;
}
public
int
getOwnerId
()
{
return
ownerId
;
}
public
void
setOwner
(
GenshinPlayer
player
)
{
this
.
ownerId
=
player
.
getId
();
this
.
guid
=
player
.
getNextGuid
();
}
public
int
getItemId
()
{
return
itemId
;
}
public
void
setItemId
(
int
itemId
)
{
this
.
itemId
=
itemId
;
}
public
long
getGuid
()
{
return
guid
;
}
public
ItemType
getItemType
()
{
return
this
.
itemData
.
getItemType
();
}
public
ItemData
getItemData
()
{
return
itemData
;
}
public
void
setItemData
(
ItemData
materialData
)
{
this
.
itemData
=
materialData
;
}
public
int
getCount
()
{
return
count
;
}
public
void
setCount
(
int
count
)
{
this
.
count
=
count
;
}
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
getTotalExp
()
{
return
totalExp
;
}
public
void
setTotalExp
(
int
totalExp
)
{
this
.
totalExp
=
totalExp
;
}
public
int
getPromoteLevel
()
{
return
promoteLevel
;
}
public
void
setPromoteLevel
(
int
promoteLevel
)
{
this
.
promoteLevel
=
promoteLevel
;
}
public
int
getEquipSlot
()
{
return
this
.
getItemData
().
getEquipType
().
getValue
();
}
public
int
getEquipCharacter
()
{
return
equipCharacter
;
}
public
void
setEquipCharacter
(
int
equipCharacter
)
{
this
.
equipCharacter
=
equipCharacter
;
}
public
boolean
isEquipped
()
{
return
this
.
getEquipCharacter
()
>
0
;
}
public
boolean
isLocked
()
{
return
locked
;
}
public
void
setLocked
(
boolean
locked
)
{
this
.
locked
=
locked
;
}
public
boolean
isDestroyable
()
{
return
!
this
.
isLocked
()
&&
!
this
.
isEquipped
();
}
public
int
getWeaponEntityId
()
{
return
weaponEntityId
;
}
public
void
setWeaponEntityId
(
int
weaponEntityId
)
{
this
.
weaponEntityId
=
weaponEntityId
;
}
public
List
<
Integer
>
getAffixes
()
{
return
affixes
;
}
public
int
getRefinement
()
{
return
refinement
;
}
public
void
setRefinement
(
int
refinement
)
{
this
.
refinement
=
refinement
;
}
public
int
getMainPropId
()
{
return
mainPropId
;
}
public
List
<
Integer
>
getAppendPropIdList
()
{
return
appendPropIdList
;
}
public
void
addAppendProp
()
{
if
(
this
.
getAppendPropIdList
()
==
null
)
{
this
.
appendPropIdList
=
new
ArrayList
<>();
}
if
(
this
.
getAppendPropIdList
().
size
()
<
4
)
{
addNewAppendProp
();
}
else
{
upgradeRandomAppendProp
();
}
}
private
void
addNewAppendProp
()
{
List
<
ReliquaryAffixData
>
affixList
=
GenshinDepot
.
getRandomRelicAffixList
(
getItemData
().
getAppendPropDepotId
());
if
(
affixList
==
null
)
{
return
;
}
// Build blacklist - Dont add same stat as main/sub stat
Set
<
FightProperty
>
blacklist
=
new
HashSet
<>();
ReliquaryMainPropData
mainPropData
=
GenshinData
.
getReliquaryMainPropDataMap
().
get
(
this
.
getMainPropId
());
if
(
mainPropData
!=
null
)
{
blacklist
.
add
(
mainPropData
.
getFightProp
());
}
int
len
=
Math
.
min
(
4
,
this
.
getAppendPropIdList
().
size
());
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
ReliquaryAffixData
affixData
=
GenshinData
.
getReliquaryAffixDataMap
().
get
((
int
)
this
.
getAppendPropIdList
().
get
(
i
));
if
(
affixData
!=
null
)
{
blacklist
.
add
(
affixData
.
getFightProp
());
}
}
// Build random list
WeightedList
<
ReliquaryAffixData
>
randomList
=
new
WeightedList
<>();
for
(
ReliquaryAffixData
affix
:
affixList
)
{
if
(!
blacklist
.
contains
(
affix
.
getFightProp
()))
{
randomList
.
add
(
affix
.
getWeight
(),
affix
);
}
}
if
(
randomList
.
size
()
==
0
)
{
return
;
}
// Add random stat
ReliquaryAffixData
affixData
=
randomList
.
next
();
this
.
getAppendPropIdList
().
add
(
affixData
.
getId
());
}
private
void
upgradeRandomAppendProp
()
{
List
<
ReliquaryAffixData
>
affixList
=
GenshinDepot
.
getRandomRelicAffixList
(
getItemData
().
getAppendPropDepotId
());
if
(
affixList
==
null
)
{
return
;
}
// Build whitelist
Set
<
FightProperty
>
whitelist
=
new
HashSet
<>();
int
len
=
Math
.
min
(
4
,
this
.
getAppendPropIdList
().
size
());
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
ReliquaryAffixData
affixData
=
GenshinData
.
getReliquaryAffixDataMap
().
get
((
int
)
this
.
getAppendPropIdList
().
get
(
i
));
if
(
affixData
!=
null
)
{
whitelist
.
add
(
affixData
.
getFightProp
());
}
}
// Build random list
WeightedList
<
ReliquaryAffixData
>
randomList
=
new
WeightedList
<>();
for
(
ReliquaryAffixData
affix
:
affixList
)
{
if
(
whitelist
.
contains
(
affix
.
getFightProp
()))
{
randomList
.
add
(
affix
.
getUpgradeWeight
(),
affix
);
}
}
// Add random stat
ReliquaryAffixData
affixData
=
randomList
.
next
();
this
.
getAppendPropIdList
().
add
(
affixData
.
getId
());
}
@PostLoad
public
void
onLoad
()
{
if
(
this
.
itemData
==
null
)
{
this
.
itemData
=
GenshinData
.
getItemDataMap
().
get
(
getItemId
());
}
}
public
void
save
()
{
if
(
this
.
count
>
0
&&
this
.
ownerId
>
0
)
{
DatabaseHelper
.
saveItem
(
this
);
}
else
if
(
this
.
getObjectId
()
!=
null
)
{
DatabaseHelper
.
deleteItem
(
this
);
}
}
public
SceneWeaponInfo
createSceneWeaponInfo
()
{
SceneWeaponInfo
.
Builder
weaponInfo
=
SceneWeaponInfo
.
newBuilder
()
.
setEntityId
(
this
.
getWeaponEntityId
())
.
setItemId
(
this
.
getItemId
())
.
setGuid
(
this
.
getGuid
())
.
setLevel
(
this
.
getLevel
())
.
setGadgetId
(
this
.
getItemData
().
getGadgetId
())
.
setAbilityInfo
(
AbilitySyncStateInfo
.
newBuilder
().
setIsInited
(
getAffixes
().
size
()
>
0
));
if
(
this
.
getAffixes
()
!=
null
&&
this
.
getAffixes
().
size
()
>
0
)
{
for
(
int
affix
:
this
.
getAffixes
())
{
weaponInfo
.
putAffixMap
(
affix
,
this
.
getRefinement
());
}
}
return
weaponInfo
.
build
();
}
public
SceneReliquaryInfo
createSceneReliquaryInfo
()
{
SceneReliquaryInfo
relicInfo
=
SceneReliquaryInfo
.
newBuilder
()
.
setItemId
(
this
.
getItemId
())
.
setGuid
(
this
.
getGuid
())
.
setLevel
(
this
.
getLevel
())
.
build
();
return
relicInfo
;
}
public
Item
toProto
()
{
Item
.
Builder
proto
=
Item
.
newBuilder
()
.
setGuid
(
this
.
getGuid
())
.
setItemId
(
this
.
getItemId
());
switch
(
getItemType
())
{
case
ITEM_WEAPON:
Weapon
.
Builder
weapon
=
Weapon
.
newBuilder
()
.
setLevel
(
this
.
getLevel
())
.
setExp
(
this
.
getExp
())
.
setPromoteLevel
(
this
.
getPromoteLevel
());
if
(
this
.
getAffixes
()
!=
null
&&
this
.
getAffixes
().
size
()
>
0
)
{
for
(
int
affix
:
this
.
getAffixes
())
{
weapon
.
putAffixMap
(
affix
,
this
.
getRefinement
());
}
}
proto
.
setEquip
(
Equip
.
newBuilder
().
setWeapon
(
weapon
).
setIsLocked
(
this
.
isLocked
()).
build
());
break
;
case
ITEM_RELIQUARY:
Reliquary
relic
=
Reliquary
.
newBuilder
()
.
setLevel
(
this
.
getLevel
())
.
setExp
(
this
.
getExp
())
.
setPromoteLevel
(
this
.
getPromoteLevel
())
.
setMainPropId
(
this
.
getMainPropId
())
.
addAllAppendPropIdList
(
this
.
getAppendPropIdList
())
.
build
();
proto
.
setEquip
(
Equip
.
newBuilder
().
setReliquary
(
relic
).
setIsLocked
(
this
.
isLocked
()).
build
());
break
;
case
ITEM_MATERIAL:
Material
material
=
Material
.
newBuilder
()
.
setCount
(
getCount
())
.
build
();
proto
.
setMaterial
(
material
);
break
;
case
ITEM_FURNITURE:
Furniture
furniture
=
Furniture
.
newBuilder
()
.
setCount
(
getCount
())
.
build
();
proto
.
setFurniture
(
furniture
);
break
;
default
:
break
;
}
return
proto
.
build
();
}
public
ItemHint
toItemHintProto
()
{
return
ItemHint
.
newBuilder
().
setItemId
(
getItemId
()).
setCount
(
getCount
()).
setIsNew
(
false
).
build
();
}
public
ItemParam
toItemParam
()
{
return
ItemParam
.
newBuilder
().
setItemId
(
this
.
getItemId
()).
setCount
(
this
.
getCount
()).
build
();
}
}
src/main/java/emu/grasscutter/game/inventory/Inventory.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.inventory
;
import
java.util.Collection
;
import
java.util.Iterator
;
import
java.util.LinkedList
;
import
java.util.List
;
import
emu.grasscutter.GenshinConstants
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.def.AvatarCostumeData
;
import
emu.grasscutter.data.def.AvatarData
;
import
emu.grasscutter.data.def.AvatarFlycloakData
;
import
emu.grasscutter.data.def.ItemData
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.GenshinPlayer
;
import
emu.grasscutter.game.avatar.AvatarStorage
;
import
emu.grasscutter.game.avatar.GenshinAvatar
;
import
emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam
;
import
emu.grasscutter.server.packet.send.PacketAvatarEquipChangeNotify
;
import
emu.grasscutter.server.packet.send.PacketStoreItemChangeNotify
;
import
emu.grasscutter.server.packet.send.PacketStoreItemDelNotify
;
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
Inventory
implements
Iterable
<
GenshinItem
>
{
private
final
GenshinPlayer
player
;
private
final
Long2ObjectMap
<
GenshinItem
>
store
;
private
final
Int2ObjectMap
<
InventoryTab
>
inventoryTypes
;
public
Inventory
(
GenshinPlayer
player
)
{
this
.
player
=
player
;
this
.
store
=
new
Long2ObjectOpenHashMap
<>();
this
.
inventoryTypes
=
new
Int2ObjectOpenHashMap
<>();
this
.
createInventoryTab
(
ItemType
.
ITEM_WEAPON
,
new
EquipInventoryTab
(
GenshinConstants
.
LIMIT_WEAPON
));
this
.
createInventoryTab
(
ItemType
.
ITEM_RELIQUARY
,
new
EquipInventoryTab
(
GenshinConstants
.
LIMIT_RELIC
));
this
.
createInventoryTab
(
ItemType
.
ITEM_MATERIAL
,
new
MaterialInventoryTab
(
GenshinConstants
.
LIMIT_MATERIAL
));
this
.
createInventoryTab
(
ItemType
.
ITEM_FURNITURE
,
new
MaterialInventoryTab
(
GenshinConstants
.
LIMIT_FURNITURE
));
}
public
GenshinPlayer
getPlayer
()
{
return
player
;
}
public
AvatarStorage
getAvatarStorage
()
{
return
this
.
getPlayer
().
getAvatars
();
}
public
Long2ObjectMap
<
GenshinItem
>
getItems
()
{
return
store
;
}
public
Int2ObjectMap
<
InventoryTab
>
getInventoryTypes
()
{
return
inventoryTypes
;
}
public
InventoryTab
getInventoryTab
(
ItemType
type
)
{
return
getInventoryTypes
().
get
(
type
.
getValue
());
}
public
void
createInventoryTab
(
ItemType
type
,
InventoryTab
tab
)
{
this
.
getInventoryTypes
().
put
(
type
.
getValue
(),
tab
);
}
public
GenshinItem
getItemByGuid
(
long
id
)
{
return
this
.
getItems
().
get
(
id
);
}
public
boolean
addItem
(
int
itemId
)
{
return
addItem
(
itemId
,
1
);
}
public
boolean
addItem
(
int
itemId
,
int
count
)
{
ItemData
itemData
=
GenshinData
.
getItemDataMap
().
get
(
itemId
);
if
(
itemData
==
null
)
{
return
false
;
}
GenshinItem
item
=
new
GenshinItem
(
itemData
,
count
);
return
addItem
(
item
);
}
public
boolean
addItem
(
GenshinItem
item
)
{
GenshinItem
result
=
putItem
(
item
);
if
(
result
!=
null
)
{
getPlayer
().
sendPacket
(
new
PacketStoreItemChangeNotify
(
result
));
return
true
;
}
return
false
;
}
public
void
addItems
(
Collection
<
GenshinItem
>
items
)
{
List
<
GenshinItem
>
changedItems
=
new
LinkedList
<>();
for
(
GenshinItem
item
:
items
)
{
GenshinItem
result
=
putItem
(
item
);
if
(
result
!=
null
)
{
changedItems
.
add
(
result
);
}
}
getPlayer
().
sendPacket
(
new
PacketStoreItemChangeNotify
(
changedItems
));
}
public
void
addItemParams
(
Collection
<
ItemParam
>
items
)
{
List
<
GenshinItem
>
changedItems
=
new
LinkedList
<>();
for
(
ItemParam
itemParam
:
items
)
{
GenshinItem
toAdd
=
new
GenshinItem
(
itemParam
.
getItemId
(),
itemParam
.
getCount
());
GenshinItem
result
=
putItem
(
toAdd
);
if
(
result
!=
null
)
{
changedItems
.
add
(
result
);
}
}
getPlayer
().
sendPacket
(
new
PacketStoreItemChangeNotify
(
changedItems
));
}
private
synchronized
GenshinItem
putItem
(
GenshinItem
item
)
{
// Dont add items that dont have a valid item definition.
if
(
item
.
getItemData
()
==
null
)
{
return
null
;
}
// Add item to inventory store
ItemType
type
=
item
.
getItemData
().
getItemType
();
InventoryTab
tab
=
getInventoryTab
(
type
);
// Add
if
(
type
==
ItemType
.
ITEM_WEAPON
||
type
==
ItemType
.
ITEM_RELIQUARY
)
{
if
(
tab
.
getSize
()
>=
tab
.
getMaxCapacity
())
{
return
null
;
}
putItem
(
item
,
tab
);
}
else
if
(
type
==
ItemType
.
ITEM_VIRTUAL
)
{
// Handle
this
.
addVirtualItem
(
item
.
getItemId
(),
item
.
getCount
());
return
null
;
}
else
if
(
item
.
getItemData
().
getMaterialType
()
==
MaterialType
.
MATERIAL_AVATAR
)
{
// Get avatar id
int
avatarId
=
(
item
.
getItemId
()
%
1000
)
+
10000000
;
// Dont let people give themselves extra main characters
if
(
avatarId
==
GenshinConstants
.
MAIN_CHARACTER_MALE
||
avatarId
==
GenshinConstants
.
MAIN_CHARACTER_FEMALE
)
{
return
null
;
}
// Add avatar
AvatarData
avatarData
=
GenshinData
.
getAvatarDataMap
().
get
(
avatarId
);
if
(
avatarData
!=
null
&&
!
player
.
getAvatars
().
hasAvatar
(
avatarId
))
{
this
.
getPlayer
().
addAvatar
(
new
GenshinAvatar
(
avatarData
));
}
return
null
;
}
else
if
(
item
.
getItemData
().
getMaterialType
()
==
MaterialType
.
MATERIAL_FLYCLOAK
)
{
AvatarFlycloakData
flycloakData
=
GenshinData
.
getAvatarFlycloakDataMap
().
get
(
item
.
getItemId
());
if
(
flycloakData
!=
null
&&
!
player
.
getFlyCloakList
().
contains
(
item
.
getItemId
()))
{
getPlayer
().
addFlycloak
(
item
.
getItemId
());
}
return
null
;
}
else
if
(
item
.
getItemData
().
getMaterialType
()
==
MaterialType
.
MATERIAL_COSTUME
)
{
AvatarCostumeData
costumeData
=
GenshinData
.
getAvatarCostumeDataItemIdMap
().
get
(
item
.
getItemId
());
if
(
costumeData
!=
null
&&
!
player
.
getCostumeList
().
contains
(
costumeData
.
getId
()))
{
getPlayer
().
addCostume
(
costumeData
.
getId
());
}
return
null
;
}
else
if
(
item
.
getItemData
().
getMaterialType
()
==
MaterialType
.
MATERIAL_NAMECARD
)
{
if
(!
player
.
getNameCardList
().
contains
(
item
.
getItemId
()))
{
getPlayer
().
addNameCard
(
item
.
getItemId
());
}
return
null
;
}
else
if
(
tab
!=
null
)
{
GenshinItem
existingItem
=
tab
.
getItemById
(
item
.
getItemId
());
if
(
existingItem
==
null
)
{
// Item type didnt exist before, we will add it to main inventory map if there is enough space
if
(
tab
.
getSize
()
>=
tab
.
getMaxCapacity
())
{
return
null
;
}
putItem
(
item
,
tab
);
}
else
{
// Add count
existingItem
.
setCount
(
Math
.
min
(
existingItem
.
getCount
()
+
item
.
getCount
(),
item
.
getItemData
().
getStackLimit
()));
existingItem
.
save
();
return
existingItem
;
}
}
// Set ownership and save to db
item
.
save
();
return
item
;
}
private
synchronized
void
putItem
(
GenshinItem
item
,
InventoryTab
tab
)
{
// Set owner and guid FIRST!
item
.
setOwner
(
getPlayer
());
// Put in item store
getItems
().
put
(
item
.
getGuid
(),
item
);
if
(
tab
!=
null
)
{
tab
.
onAddItem
(
item
);
}
}
private
void
addVirtualItem
(
int
itemId
,
int
count
)
{
switch
(
itemId
)
{
case
102
:
// Adventure exp
getPlayer
().
addExpDirectly
(
count
);
break
;
case
201
:
// Primogem
getPlayer
().
setPrimogems
(
player
.
getPrimogems
()
+
count
);
break
;
case
202
:
// Mora
getPlayer
().
setMora
(
player
.
getMora
()
+
count
);
break
;
}
}
public
void
removeItems
(
List
<
GenshinItem
>
items
)
{
// TODO Bulk delete
for
(
GenshinItem
item
:
items
)
{
this
.
removeItem
(
item
,
item
.
getCount
());
}
}
public
boolean
removeItem
(
long
guid
)
{
return
removeItem
(
guid
,
1
);
}
public
synchronized
boolean
removeItem
(
long
guid
,
int
count
)
{
GenshinItem
item
=
this
.
getItemByGuid
(
guid
);
if
(
item
==
null
)
{
return
false
;
}
return
removeItem
(
item
,
count
);
}
public
synchronized
boolean
removeItem
(
GenshinItem
item
)
{
return
removeItem
(
item
,
item
.
getCount
());
}
public
synchronized
boolean
removeItem
(
GenshinItem
item
,
int
count
)
{
// Sanity check
if
(
count
<=
0
||
item
==
null
)
{
return
false
;
}
item
.
setCount
(
item
.
getCount
()
-
count
);
if
(
item
.
getCount
()
<=
0
)
{
// Remove from inventory tab too
InventoryTab
tab
=
null
;
if
(
item
.
getItemData
()
!=
null
)
{
tab
=
getInventoryTab
(
item
.
getItemData
().
getItemType
());
}
// Remove if less than 0
deleteItem
(
item
,
tab
);
//
getPlayer
().
sendPacket
(
new
PacketStoreItemDelNotify
(
item
));
}
else
{
getPlayer
().
sendPacket
(
new
PacketStoreItemChangeNotify
(
item
));
}
// Update in db
item
.
save
();
// Returns true on success
return
true
;
}
private
void
deleteItem
(
GenshinItem
item
,
InventoryTab
tab
)
{
getItems
().
remove
(
item
.
getGuid
());
if
(
tab
!=
null
)
{
tab
.
onRemoveItem
(
item
);
}
}
public
boolean
equipItem
(
long
avatarGuid
,
long
equipGuid
)
{
GenshinAvatar
avatar
=
getPlayer
().
getAvatars
().
getAvatarByGuid
(
avatarGuid
);
GenshinItem
item
=
this
.
getItemByGuid
(
equipGuid
);
if
(
avatar
!=
null
&&
item
!=
null
)
{
return
avatar
.
equipItem
(
item
,
true
);
}
return
false
;
}
public
boolean
unequipItem
(
long
avatarGuid
,
int
slot
)
{
GenshinAvatar
avatar
=
getPlayer
().
getAvatars
().
getAvatarByGuid
(
avatarGuid
);
EquipType
equipType
=
EquipType
.
getTypeByValue
(
slot
);
if
(
avatar
!=
null
&&
equipType
!=
EquipType
.
EQUIP_WEAPON
)
{
if
(
avatar
.
unequipItem
(
equipType
))
{
getPlayer
().
sendPacket
(
new
PacketAvatarEquipChangeNotify
(
avatar
,
equipType
));
avatar
.
recalcStats
();
return
true
;
}
}
return
false
;
}
public
void
loadFromDatabase
()
{
List
<
GenshinItem
>
items
=
DatabaseHelper
.
getInventoryItems
(
getPlayer
());
for
(
GenshinItem
item
:
items
)
{
// Should never happen
if
(
item
.
getObjectId
()
==
null
)
{
continue
;
}
ItemData
itemData
=
GenshinData
.
getItemDataMap
().
get
(
item
.
getItemId
());
if
(
itemData
==
null
)
{
continue
;
}
item
.
setItemData
(
itemData
);
InventoryTab
tab
=
null
;
if
(
item
.
getItemData
()
!=
null
)
{
tab
=
getInventoryTab
(
item
.
getItemData
().
getItemType
());
}
putItem
(
item
,
tab
);
// Equip to a character if possible
if
(
item
.
isEquipped
())
{
GenshinAvatar
avatar
=
getPlayer
().
getAvatars
().
getAvatarById
(
item
.
getEquipCharacter
());
boolean
hasEquipped
=
false
;
if
(
avatar
!=
null
)
{
hasEquipped
=
avatar
.
equipItem
(
item
,
false
);
}
if
(!
hasEquipped
)
{
item
.
setEquipCharacter
(
0
);
item
.
save
();
}
}
}
}
@Override
public
Iterator
<
GenshinItem
>
iterator
()
{
return
this
.
getItems
().
values
().
iterator
();
}
}
src/main/java/emu/grasscutter/game/inventory/InventoryTab.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.inventory
;
public
interface
InventoryTab
{
public
GenshinItem
getItemById
(
int
id
);
public
void
onAddItem
(
GenshinItem
item
);
public
void
onRemoveItem
(
GenshinItem
item
);
public
int
getSize
();
public
int
getMaxCapacity
();
}
src/main/java/emu/grasscutter/game/inventory/ItemDef.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.inventory
;
public
class
ItemDef
{
private
int
itemId
;
private
int
count
;
public
ItemDef
(
int
itemId
,
int
count
)
{
this
.
itemId
=
itemId
;
this
.
count
=
count
;
}
public
int
getItemId
()
{
return
itemId
;
}
public
void
setItemId
(
int
itemId
)
{
this
.
itemId
=
itemId
;
}
public
int
getCount
()
{
return
count
;
}
public
void
setCount
(
int
count
)
{
this
.
count
=
count
;
}
}
src/main/java/emu/grasscutter/game/inventory/ItemQuality.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.inventory
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.stream.Stream
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
public
enum
ItemQuality
{
QUALITY_NONE
(
0
),
QUALITY_WHITE
(
1
),
QUALITY_GREEN
(
2
),
QUALITY_BLUE
(
3
),
QUALITY_PURPLE
(
4
),
QUALITY_ORANGE
(
5
),
QUALITY_ORANGE_SP
(
105
);
private
final
int
value
;
private
static
final
Int2ObjectMap
<
ItemQuality
>
map
=
new
Int2ObjectOpenHashMap
<>();
private
static
final
Map
<
String
,
ItemQuality
>
stringMap
=
new
HashMap
<>();
static
{
Stream
.
of
(
values
()).
forEach
(
e
->
{
map
.
put
(
e
.
getValue
(),
e
);
stringMap
.
put
(
e
.
name
(),
e
);
});
}
private
ItemQuality
(
int
value
)
{
this
.
value
=
value
;
}
public
int
getValue
()
{
return
value
;
}
public
static
ItemQuality
getTypeByValue
(
int
value
)
{
return
map
.
getOrDefault
(
value
,
QUALITY_NONE
);
}
public
static
ItemQuality
getTypeByName
(
String
name
)
{
return
stringMap
.
getOrDefault
(
name
,
QUALITY_NONE
);
}
}
src/main/java/emu/grasscutter/game/inventory/ItemType.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.inventory
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.stream.Stream
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
public
enum
ItemType
{
ITEM_NONE
(
0
),
ITEM_VIRTUAL
(
1
),
ITEM_MATERIAL
(
2
),
ITEM_RELIQUARY
(
3
),
ITEM_WEAPON
(
4
),
ITEM_DISPLAY
(
5
),
ITEM_FURNITURE
(
6
);
private
final
int
value
;
private
static
final
Int2ObjectMap
<
ItemType
>
map
=
new
Int2ObjectOpenHashMap
<>();
private
static
final
Map
<
String
,
ItemType
>
stringMap
=
new
HashMap
<>();
static
{
Stream
.
of
(
values
()).
forEach
(
e
->
{
map
.
put
(
e
.
getValue
(),
e
);
stringMap
.
put
(
e
.
name
(),
e
);
});
}
private
ItemType
(
int
value
)
{
this
.
value
=
value
;
}
public
int
getValue
()
{
return
value
;
}
public
static
ItemType
getTypeByValue
(
int
value
)
{
return
map
.
getOrDefault
(
value
,
ITEM_NONE
);
}
public
static
ItemType
getTypeByName
(
String
name
)
{
return
stringMap
.
getOrDefault
(
name
,
ITEM_NONE
);
}
}
src/main/java/emu/grasscutter/game/inventory/MaterialInventoryTab.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.inventory
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
public
class
MaterialInventoryTab
implements
InventoryTab
{
private
final
Int2ObjectMap
<
GenshinItem
>
items
;
private
final
int
maxCapacity
;
public
MaterialInventoryTab
(
int
maxCapacity
)
{
this
.
items
=
new
Int2ObjectOpenHashMap
<>();
this
.
maxCapacity
=
maxCapacity
;
}
@Override
public
GenshinItem
getItemById
(
int
id
)
{
return
this
.
items
.
get
(
id
);
}
@Override
public
void
onAddItem
(
GenshinItem
item
)
{
this
.
items
.
put
(
item
.
getItemId
(),
item
);
}
@Override
public
void
onRemoveItem
(
GenshinItem
item
)
{
this
.
items
.
remove
(
item
.
getItemId
());
}
@Override
public
int
getSize
()
{
return
this
.
items
.
size
();
}
@Override
public
int
getMaxCapacity
()
{
return
this
.
maxCapacity
;
}
}
src/main/java/emu/grasscutter/game/inventory/MaterialType.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.inventory
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.stream.Stream
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
public
enum
MaterialType
{
MATERIAL_NONE
(
0
),
MATERIAL_FOOD
(
1
),
MATERIAL_QUEST
(
2
),
MATERIAL_EXCHANGE
(
4
),
MATERIAL_CONSUME
(
5
),
MATERIAL_EXP_FRUIT
(
6
),
MATERIAL_AVATAR
(
7
),
MATERIAL_ADSORBATE
(
8
),
MATERIAL_CRICKET
(
9
),
MATERIAL_ELEM_CRYSTAL
(
10
),
MATERIAL_WEAPON_EXP_STONE
(
11
),
MATERIAL_CHEST
(
12
),
MATERIAL_RELIQUARY_MATERIAL
(
13
),
MATERIAL_AVATAR_MATERIAL
(
14
),
MATERIAL_NOTICE_ADD_HP
(
15
),
MATERIAL_SEA_LAMP
(
16
),
MATERIAL_SELECTABLE_CHEST
(
17
),
MATERIAL_FLYCLOAK
(
18
),
MATERIAL_NAMECARD
(
19
),
MATERIAL_TALENT
(
20
),
MATERIAL_WIDGET
(
21
),
MATERIAL_CHEST_BATCH_USE
(
22
),
MATERIAL_FAKE_ABSORBATE
(
23
),
MATERIAL_CONSUME_BATCH_USE
(
24
),
MATERIAL_WOOD
(
25
),
MATERIAL_FURNITURE_FORMULA
(
27
),
MATERIAL_CHANNELLER_SLAB_BUFF
(
28
),
MATERIAL_FURNITURE_SUITE_FORMULA
(
29
),
MATERIAL_COSTUME
(
30
);
private
final
int
value
;
private
static
final
Int2ObjectMap
<
MaterialType
>
map
=
new
Int2ObjectOpenHashMap
<>();
private
static
final
Map
<
String
,
MaterialType
>
stringMap
=
new
HashMap
<>();
static
{
Stream
.
of
(
values
()).
forEach
(
e
->
{
map
.
put
(
e
.
getValue
(),
e
);
stringMap
.
put
(
e
.
name
(),
e
);
});
}
private
MaterialType
(
int
value
)
{
this
.
value
=
value
;
}
public
int
getValue
()
{
return
value
;
}
public
static
MaterialType
getTypeByValue
(
int
value
)
{
return
map
.
getOrDefault
(
value
,
MATERIAL_NONE
);
}
public
static
MaterialType
getTypeByName
(
String
name
)
{
return
stringMap
.
getOrDefault
(
name
,
MATERIAL_NONE
);
}
}
src/main/java/emu/grasscutter/game/managers/AccountManager.java
0 → 100644
View file @
7925d1cd
package
emu.grasscutter.game.managers
;
import
emu.grasscutter.server.game.GameServer
;
public
class
AccountManager
{
private
final
GameServer
server
;
public
AccountManager
(
GameServer
server
)
{
this
.
server
=
server
;
}
public
GameServer
getServer
()
{
return
server
;
}
}
Prev
1
2
3
4
5
6
7
8
9
…
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