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
a8293102
Commit
a8293102
authored
Jun 07, 2022
by
Melledy
Committed by
GitHub
Jun 07, 2022
Browse files
Merge branch 'development' into stable
parents
304b9cb8
ecf7a81a
Changes
410
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/game/drop/DropManager.java
View file @
a8293102
...
@@ -2,8 +2,9 @@ package emu.grasscutter.game.drop;
...
@@ -2,8 +2,9 @@ package emu.grasscutter.game.drop;
import
com.google.gson.reflect.TypeToken
;
import
com.google.gson.reflect.TypeToken
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.DataLoader
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.
def
.ItemData
;
import
emu.grasscutter.data.
excels
.ItemData
;
import
emu.grasscutter.game.entity.EntityItem
;
import
emu.grasscutter.game.entity.EntityItem
;
import
emu.grasscutter.game.entity.EntityMonster
;
import
emu.grasscutter.game.entity.EntityMonster
;
import
emu.grasscutter.game.inventory.GameItem
;
import
emu.grasscutter.game.inventory.GameItem
;
...
@@ -17,7 +18,8 @@ import emu.grasscutter.utils.Utils;
...
@@ -17,7 +18,8 @@ import emu.grasscutter.utils.Utils;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
java.io.FileReader
;
import
java.io.InputStreamReader
;
import
java.io.Reader
;
import
java.util.Collection
;
import
java.util.Collection
;
import
java.util.List
;
import
java.util.List
;
...
@@ -41,7 +43,7 @@ public class DropManager {
...
@@ -41,7 +43,7 @@ public class DropManager {
}
}
public
synchronized
void
load
()
{
public
synchronized
void
load
()
{
try
(
File
Reader
fileReader
=
new
FileReader
(
Grasscutter
.
getConfig
().
DATA_FOLDER
+
"Drop.json"
))
{
try
(
Reader
fileReader
=
new
InputStreamReader
(
DataLoader
.
load
(
"Drop.json"
))
)
{
getDropData
().
clear
();
getDropData
().
clear
();
List
<
DropInfo
>
banners
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
TypeToken
.
getParameterized
(
Collection
.
class
,
DropInfo
.
class
).
getType
());
List
<
DropInfo
>
banners
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
TypeToken
.
getParameterized
(
Collection
.
class
,
DropInfo
.
class
).
getType
());
if
(
banners
.
size
()
>
0
)
{
if
(
banners
.
size
()
>
0
)
{
...
@@ -69,9 +71,7 @@ public class DropManager {
...
@@ -69,9 +71,7 @@ public class DropManager {
}
else
{
}
else
{
// target is null if items will be added are shared. no one could pick it up because of the combination(give + shared)
// target is null if items will be added are shared. no one could pick it up because of the combination(give + shared)
// so it will be sent to all players' inventories directly.
// so it will be sent to all players' inventories directly.
dropScene
.
getPlayers
().
forEach
(
x
->
{
dropScene
.
getPlayers
().
forEach
(
x
->
x
.
getInventory
().
addItem
(
new
GameItem
(
itemData
,
num
),
ActionReason
.
SubfieldDrop
,
true
));
x
.
getInventory
().
addItem
(
new
GameItem
(
itemData
,
num
),
ActionReason
.
SubfieldDrop
,
true
);
});
}
}
}
}
}
}
...
...
src/main/java/emu/grasscutter/game/dungeons/DungeonChallenge.java
View file @
a8293102
package
emu.grasscutter.game.dungeons
;
package
emu.grasscutter.game.dungeons
;
import
emu.grasscutter.data.common.ItemParamData
;
import
emu.grasscutter.data.common.ItemParamData
;
import
emu.grasscutter.data.
def
.DungeonData
;
import
emu.grasscutter.data.
excels
.DungeonData
;
import
emu.grasscutter.game.entity.EntityMonster
;
import
emu.grasscutter.game.entity.EntityMonster
;
import
emu.grasscutter.game.inventory.GameItem
;
import
emu.grasscutter.game.inventory.GameItem
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
...
@@ -28,14 +28,20 @@ public class DungeonChallenge {
...
@@ -28,14 +28,20 @@ public class DungeonChallenge {
private
int
challengeId
;
private
int
challengeId
;
private
boolean
success
;
private
boolean
success
;
private
boolean
progress
;
private
boolean
progress
;
/**
* has more challenge
*/
private
boolean
stage
;
private
int
score
;
private
int
score
;
private
int
objective
=
0
;
private
int
objective
=
0
;
private
IntSet
rewardedPlayers
;
private
IntSet
rewardedPlayers
;
public
DungeonChallenge
(
Scene
scene
,
SceneGroup
group
)
{
public
DungeonChallenge
(
Scene
scene
,
SceneGroup
group
,
int
challengeId
,
int
challengeIndex
,
int
objective
)
{
this
.
scene
=
scene
;
this
.
scene
=
scene
;
this
.
group
=
group
;
this
.
group
=
group
;
this
.
challengeId
=
challengeId
;
this
.
challengeIndex
=
challengeIndex
;
this
.
objective
=
objective
;
this
.
setRewardedPlayers
(
new
IntOpenHashSet
());
this
.
setRewardedPlayers
(
new
IntOpenHashSet
());
}
}
...
@@ -86,7 +92,15 @@ public class DungeonChallenge {
...
@@ -86,7 +92,15 @@ public class DungeonChallenge {
public
int
getScore
()
{
public
int
getScore
()
{
return
score
;
return
score
;
}
}
public
boolean
isStage
()
{
return
stage
;
}
public
void
setStage
(
boolean
stage
)
{
this
.
stage
=
stage
;
}
public
int
getTimeLimit
()
{
public
int
getTimeLimit
()
{
return
600
;
return
600
;
}
}
...
@@ -112,7 +126,7 @@ public class DungeonChallenge {
...
@@ -112,7 +126,7 @@ public class DungeonChallenge {
if
(
this
.
isSuccess
())
{
if
(
this
.
isSuccess
())
{
// Call success script event
// Call success script event
this
.
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_CHALLENGE_SUCCESS
,
null
);
this
.
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_CHALLENGE_SUCCESS
,
null
);
// Settle
// Settle
settle
();
settle
();
}
else
{
}
else
{
...
@@ -122,8 +136,10 @@ public class DungeonChallenge {
...
@@ -122,8 +136,10 @@ public class DungeonChallenge {
private
void
settle
()
{
private
void
settle
()
{
getScene
().
getDungeonSettleObservers
().
forEach
(
o
->
o
.
onDungeonSettle
(
getScene
()));
getScene
().
getDungeonSettleObservers
().
forEach
(
o
->
o
.
onDungeonSettle
(
getScene
()));
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_DUNGEON_SETTLE
,
new
ScriptArgs
(
this
.
isSuccess
()
?
1
:
0
));
if
(!
stage
){
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_DUNGEON_SETTLE
,
new
ScriptArgs
(
this
.
isSuccess
()
?
1
:
0
));
}
}
}
public
void
onMonsterDie
(
EntityMonster
entity
)
{
public
void
onMonsterDie
(
EntityMonster
entity
)
{
...
...
src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java
View file @
a8293102
...
@@ -3,10 +3,12 @@ package emu.grasscutter.game.dungeons;
...
@@ -3,10 +3,12 @@ package emu.grasscutter.game.dungeons;
import
emu.grasscutter.GameConstants
;
import
emu.grasscutter.GameConstants
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.
custom
.ScenePointEntry
;
import
emu.grasscutter.data.
binout
.ScenePointEntry
;
import
emu.grasscutter.data.
def
.DungeonData
;
import
emu.grasscutter.data.
excels
.DungeonData
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.SceneType
;
import
emu.grasscutter.game.props.SceneType
;
import
emu.grasscutter.game.quest.enums.QuestTrigger
;
import
emu.grasscutter.game.world.Scene
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.game.GameServer
;
...
@@ -51,8 +53,9 @@ public class DungeonManager {
...
@@ -51,8 +53,9 @@ public class DungeonManager {
int
sceneId
=
data
.
getSceneId
();
int
sceneId
=
data
.
getSceneId
();
player
.
getScene
().
setPrevScene
(
sceneId
);
player
.
getScene
().
setPrevScene
(
sceneId
);
if
(
player
.
getWorld
().
transferPlayerToScene
(
player
,
sceneId
,
data
)){
if
(
player
.
getWorld
().
transferPlayerToScene
(
player
,
sceneId
,
data
))
{
player
.
getScene
().
addDungeonSettleObserver
(
basicDungeonSettleObserver
);
player
.
getScene
().
addDungeonSettleObserver
(
basicDungeonSettleObserver
);
player
.
getQuestManager
().
triggerEvent
(
QuestTrigger
.
QUEST_CONTENT_ENTER_DUNGEON
,
data
.
getId
());
}
}
player
.
getScene
().
setPrevScenePoint
(
pointId
);
player
.
getScene
().
setPrevScenePoint
(
pointId
);
...
@@ -78,19 +81,21 @@ public class DungeonManager {
...
@@ -78,19 +81,21 @@ public class DungeonManager {
}
}
public
void
exitDungeon
(
Player
player
)
{
public
void
exitDungeon
(
Player
player
)
{
if
(
player
.
getScene
().
getSceneType
()
!=
SceneType
.
SCENE_DUNGEON
)
{
Scene
scene
=
player
.
getScene
();
if
(
scene
==
null
||
scene
.
getSceneType
()
!=
SceneType
.
SCENE_DUNGEON
)
{
return
;
return
;
}
}
// Get previous scene
// Get previous scene
int
prevScene
=
player
.
getS
cene
()
.
getPrevScene
()
>
0
?
player
.
getS
cene
()
.
getPrevScene
()
:
3
;
int
prevScene
=
s
cene
.
getPrevScene
()
>
0
?
s
cene
.
getPrevScene
()
:
3
;
// Get previous position
// Get previous position
DungeonData
dungeonData
=
player
.
getS
cene
()
.
getDungeonData
();
DungeonData
dungeonData
=
s
cene
.
getDungeonData
();
Position
prevPos
=
new
Position
(
GameConstants
.
START_POSITION
);
Position
prevPos
=
new
Position
(
GameConstants
.
START_POSITION
);
if
(
dungeonData
!=
null
)
{
if
(
dungeonData
!=
null
)
{
ScenePointEntry
entry
=
GameData
.
getScenePointEntryById
(
prevScene
,
player
.
getS
cene
()
.
getPrevScenePoint
());
ScenePointEntry
entry
=
GameData
.
getScenePointEntryById
(
prevScene
,
s
cene
.
getPrevScenePoint
());
if
(
entry
!=
null
)
{
if
(
entry
!=
null
)
{
prevPos
.
set
(
entry
.
getPointData
().
getTranPos
());
prevPos
.
set
(
entry
.
getPointData
().
getTranPos
());
...
...
src/main/java/emu/grasscutter/game/dungeons/TowerDungeonSettleListener.java
View file @
a8293102
...
@@ -9,15 +9,25 @@ public class TowerDungeonSettleListener implements DungeonSettleListener {
...
@@ -9,15 +9,25 @@ public class TowerDungeonSettleListener implements DungeonSettleListener {
@Override
@Override
public
void
onDungeonSettle
(
Scene
scene
)
{
public
void
onDungeonSettle
(
Scene
scene
)
{
if
(
scene
.
getScriptManager
().
getVariables
().
containsKey
(
"stage"
)
&&
scene
.
getScriptManager
().
getVariables
().
get
(
"stage"
)
==
1
){
return
;
}
scene
.
setAutoCloseTime
(
Utils
.
getCurrentSeconds
()
+
1000
);
scene
.
setAutoCloseTime
(
Utils
.
getCurrentSeconds
()
+
1000
);
var
towerManager
=
scene
.
getPlayers
().
get
(
0
).
getTowerManager
();
var
towerManager
=
scene
.
getPlayers
().
get
(
0
).
getTowerManager
();
towerManager
.
notifyCurLevelRecordChangeWhenDone
();
towerManager
.
notifyCurLevelRecordChangeWhenDone
(
3
);
scene
.
broadcastPacket
(
new
PacketTowerFloorRecordChangeNotify
(
towerManager
.
getCurrentFloorId
()));
scene
.
broadcastPacket
(
new
PacketTowerFloorRecordChangeNotify
(
scene
.
broadcastPacket
(
new
PacketDungeonSettleNotify
(
scene
.
getChallenge
(),
towerManager
.
getCurrentFloorId
(),
true
,
3
,
towerManager
.
canEnterScheduleFloor
()
));
scene
.
broadcastPacket
(
new
PacketDungeonSettleNotify
(
scene
.
getChallenge
(),
towerManager
.
hasNextFloor
(),
towerManager
.
hasNextLevel
(),
towerManager
.
hasNextLevel
(),
towerManager
.
getNextFloorId
()
towerManager
.
hasNextLevel
()
?
0
:
towerManager
.
getNextFloorId
()
));
));
}
}
...
...
src/main/java/emu/grasscutter/game/entity/EntityAvatar.java
View file @
a8293102
...
@@ -2,8 +2,8 @@ package emu.grasscutter.game.entity;
...
@@ -2,8 +2,8 @@ package emu.grasscutter.game.entity;
import
emu.grasscutter.GameConstants
;
import
emu.grasscutter.GameConstants
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.
def
.AvatarData
;
import
emu.grasscutter.data.
excels
.AvatarData
;
import
emu.grasscutter.data.
def
.AvatarSkillDepotData
;
import
emu.grasscutter.data.
excels
.AvatarSkillDepotData
;
import
emu.grasscutter.game.avatar.Avatar
;
import
emu.grasscutter.game.avatar.Avatar
;
import
emu.grasscutter.game.inventory.EquipType
;
import
emu.grasscutter.game.inventory.EquipType
;
import
emu.grasscutter.game.inventory.GameItem
;
import
emu.grasscutter.game.inventory.GameItem
;
...
@@ -12,22 +12,25 @@ import emu.grasscutter.game.props.EntityIdType;
...
@@ -12,22 +12,25 @@ import emu.grasscutter.game.props.EntityIdType;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.game.world.Scene
;
import
emu.grasscutter.game.world.Scene
;
import
emu.grasscutter.game.world.World
;
import
emu.grasscutter.net.proto.AbilityControlBlockOuterClass.AbilityControlBlock
;
import
emu.grasscutter.net.proto.AbilityControlBlockOuterClass.AbilityControlBlock
;
import
emu.grasscutter.net.proto.AbilityEmbryoOuterClass.AbilityEmbryo
;
import
emu.grasscutter.net.proto.AbilityEmbryoOuterClass.AbilityEmbryo
;
import
emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo
;
import
emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo
;
import
emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair
;
import
emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair
;
import
emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason
;
import
emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo
;
import
emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo
;
import
emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData
;
import
emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData
;
import
emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo
;
import
emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo
;
import
emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair
;
import
emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair
;
import
emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType
;
import
emu.grasscutter.net.proto.PlayerDieTypeOuterClass.PlayerDieType
;
import
emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason
;
import
emu.grasscutter.net.proto.PropPairOuterClass.PropPair
;
import
emu.grasscutter.net.proto.PropPairOuterClass.PropPair
;
import
emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType
;
import
emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType
;
import
emu.grasscutter.net.proto.SceneAvatarInfoOuterClass.SceneAvatarInfo
;
import
emu.grasscutter.net.proto.SceneAvatarInfoOuterClass.SceneAvatarInfo
;
import
emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo
;
import
emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo
;
import
emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo
;
import
emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.server.packet.send.PacketAvatarFightPropUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify
;
import
emu.grasscutter.utils.Position
;
import
emu.grasscutter.utils.Position
;
import
emu.grasscutter.utils.ProtoHelper
;
import
emu.grasscutter.utils.ProtoHelper
;
import
emu.grasscutter.utils.Utils
;
import
emu.grasscutter.utils.Utils
;
...
@@ -43,6 +46,7 @@ public class EntityAvatar extends GameEntity {
...
@@ -43,6 +46,7 @@ public class EntityAvatar extends GameEntity {
public
EntityAvatar
(
Scene
scene
,
Avatar
avatar
)
{
public
EntityAvatar
(
Scene
scene
,
Avatar
avatar
)
{
super
(
scene
);
super
(
scene
);
this
.
avatar
=
avatar
;
this
.
avatar
=
avatar
;
this
.
avatar
.
setCurrentEnergy
();
this
.
id
=
getScene
().
getWorld
().
getNextEntityId
(
EntityIdType
.
AVATAR
);
this
.
id
=
getScene
().
getWorld
().
getNextEntityId
(
EntityIdType
.
AVATAR
);
GameItem
weapon
=
this
.
getAvatar
().
getWeapon
();
GameItem
weapon
=
this
.
getAvatar
().
getWeapon
();
...
@@ -54,6 +58,7 @@ public class EntityAvatar extends GameEntity {
...
@@ -54,6 +58,7 @@ public class EntityAvatar extends GameEntity {
public
EntityAvatar
(
Avatar
avatar
)
{
public
EntityAvatar
(
Avatar
avatar
)
{
super
(
null
);
super
(
null
);
this
.
avatar
=
avatar
;
this
.
avatar
=
avatar
;
this
.
avatar
.
setCurrentEnergy
();
}
}
public
Player
getPlayer
()
{
public
Player
getPlayer
()
{
...
@@ -101,15 +106,69 @@ public class EntityAvatar extends GameEntity {
...
@@ -101,15 +106,69 @@ public class EntityAvatar extends GameEntity {
@Override
@Override
public
void
onDeath
(
int
killerId
)
{
public
void
onDeath
(
int
killerId
)
{
this
.
killedType
=
PlayerDieType
.
PLAYER_DIE_KILL_BY_MONSTER
;
this
.
killedType
=
PlayerDieType
.
PLAYER_DIE_
TYPE_
KILL_BY_MONSTER
;
this
.
killedBy
=
killerId
;
this
.
killedBy
=
killerId
;
clearEnergy
(
PropChangeReason
.
PROP_CHANGE_REASON_STATUE_RECOVER
);
}
}
public
void
onDeath
(
PlayerDieType
dieType
,
int
killerId
)
{
public
void
onDeath
(
PlayerDieType
dieType
,
int
killerId
)
{
this
.
killedType
=
dieType
;
this
.
killedType
=
dieType
;
this
.
killedBy
=
killerId
;
this
.
killedBy
=
killerId
;
clearEnergy
(
PropChangeReason
.
PROP_CHANGE_REASON_STATUE_RECOVER
);
}
}
@Override
public
float
heal
(
float
amount
)
{
float
healed
=
super
.
heal
(
amount
);
if
(
healed
>
0
f
)
{
getScene
().
broadcastPacket
(
new
PacketEntityFightPropChangeReasonNotify
(
this
,
FightProperty
.
FIGHT_PROP_CUR_HP
,
healed
,
PropChangeReason
.
PROP_CHANGE_REASON_ABILITY
,
ChangeHpReason
.
CHANGE_HP_REASON_CHANGE_HP_ADD_ABILITY
)
);
}
return
healed
;
}
public
void
clearEnergy
(
PropChangeReason
reason
)
{
FightProperty
curEnergyProp
=
this
.
getAvatar
().
getSkillDepot
().
getElementType
().
getCurEnergyProp
();
this
.
avatar
.
setCurrentEnergy
(
curEnergyProp
,
0
);
this
.
getScene
().
broadcastPacket
(
new
PacketAvatarFightPropUpdateNotify
(
this
.
getAvatar
(),
curEnergyProp
));
this
.
getScene
().
broadcastPacket
(
new
PacketEntityFightPropChangeReasonNotify
(
this
,
curEnergyProp
,
0
f
,
reason
));
}
public
void
addEnergy
(
float
amount
,
PropChangeReason
reason
)
{
this
.
addEnergy
(
amount
,
reason
,
false
);
}
public
void
addEnergy
(
float
amount
,
PropChangeReason
reason
,
boolean
isFlat
)
{
// Get current and maximum energy for this avatar.
FightProperty
curEnergyProp
=
this
.
getAvatar
().
getSkillDepot
().
getElementType
().
getCurEnergyProp
();
FightProperty
maxEnergyProp
=
this
.
getAvatar
().
getSkillDepot
().
getElementType
().
getMaxEnergyProp
();
float
curEnergy
=
this
.
getFightProperty
(
curEnergyProp
);
float
maxEnergy
=
this
.
getFightProperty
(
maxEnergyProp
);
// Get energy recharge.
float
energyRecharge
=
this
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CHARGE_EFFICIENCY
);
// Scale amount by energy recharge, if the amount is not flat.
if
(!
isFlat
)
{
amount
*=
energyRecharge
;
}
// Determine the new energy value.
float
newEnergy
=
Math
.
min
(
curEnergy
+
amount
,
maxEnergy
);
// Set energy and notify.
if
(
newEnergy
!=
curEnergy
)
{
this
.
avatar
.
setCurrentEnergy
(
curEnergyProp
,
newEnergy
);
this
.
getScene
().
broadcastPacket
(
new
PacketAvatarFightPropUpdateNotify
(
this
.
getAvatar
(),
curEnergyProp
));
this
.
getScene
().
broadcastPacket
(
new
PacketEntityFightPropChangeReasonNotify
(
this
,
curEnergyProp
,
newEnergy
,
reason
));
}
}
public
SceneAvatarInfo
getSceneAvatarInfo
()
{
public
SceneAvatarInfo
getSceneAvatarInfo
()
{
SceneAvatarInfo
.
Builder
avatarInfo
=
SceneAvatarInfo
.
newBuilder
()
SceneAvatarInfo
.
Builder
avatarInfo
=
SceneAvatarInfo
.
newBuilder
()
.
setUid
(
this
.
getPlayer
().
getUid
())
.
setUid
(
this
.
getPlayer
().
getUid
())
...
@@ -150,7 +209,7 @@ public class EntityAvatar extends GameEntity {
...
@@ -150,7 +209,7 @@ public class EntityAvatar extends GameEntity {
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
.
setEntityId
(
getId
())
.
setEntityId
(
getId
())
.
setEntityType
(
ProtEntityType
.
PROT_ENTITY_AVATAR
)
.
setEntityType
(
ProtEntityType
.
PROT_ENTITY_
TYPE_
AVATAR
)
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
.
setEntityAuthorityInfo
(
authority
)
.
setEntityAuthorityInfo
(
authority
)
...
@@ -241,5 +300,5 @@ public class EntityAvatar extends GameEntity {
...
@@ -241,5 +300,5 @@ public class EntityAvatar extends GameEntity {
//
//
return
abilityControlBlock
.
build
();
return
abilityControlBlock
.
build
();
}
}
}
}
src/main/java/emu/grasscutter/game/entity/EntityClientGadget.java
View file @
a8293102
...
@@ -35,6 +35,8 @@ public class EntityClientGadget extends EntityBaseGadget {
...
@@ -35,6 +35,8 @@ public class EntityClientGadget extends EntityBaseGadget {
private
int
ownerEntityId
;
private
int
ownerEntityId
;
private
int
targetEntityId
;
private
int
targetEntityId
;
private
boolean
asyncLoad
;
private
boolean
asyncLoad
;
private
int
originalOwnerEntityId
;
public
EntityClientGadget
(
Scene
scene
,
Player
player
,
EvtCreateGadgetNotify
notify
)
{
public
EntityClientGadget
(
Scene
scene
,
Player
player
,
EvtCreateGadgetNotify
notify
)
{
super
(
scene
);
super
(
scene
);
...
@@ -48,6 +50,14 @@ public class EntityClientGadget extends EntityBaseGadget {
...
@@ -48,6 +50,14 @@ public class EntityClientGadget extends EntityBaseGadget {
this
.
ownerEntityId
=
notify
.
getPropOwnerEntityId
();
this
.
ownerEntityId
=
notify
.
getPropOwnerEntityId
();
this
.
targetEntityId
=
notify
.
getTargetEntityId
();
this
.
targetEntityId
=
notify
.
getTargetEntityId
();
this
.
asyncLoad
=
notify
.
getIsAsyncLoad
();
this
.
asyncLoad
=
notify
.
getIsAsyncLoad
();
GameEntity
owner
=
scene
.
getEntityById
(
this
.
ownerEntityId
);
if
(
owner
instanceof
EntityClientGadget
ownerGadget
)
{
this
.
originalOwnerEntityId
=
ownerGadget
.
getOriginalOwnerEntityId
();
}
else
{
this
.
originalOwnerEntityId
=
this
.
ownerEntityId
;
}
}
}
@Override
@Override
...
@@ -79,6 +89,10 @@ public class EntityClientGadget extends EntityBaseGadget {
...
@@ -79,6 +89,10 @@ public class EntityClientGadget extends EntityBaseGadget {
return
this
.
asyncLoad
;
return
this
.
asyncLoad
;
}
}
public
int
getOriginalOwnerEntityId
()
{
return
this
.
originalOwnerEntityId
;
}
@Override
@Override
public
void
onDeath
(
int
killerId
)
{
public
void
onDeath
(
int
killerId
)
{
...
@@ -113,7 +127,7 @@ public class EntityClientGadget extends EntityBaseGadget {
...
@@ -113,7 +127,7 @@ public class EntityClientGadget extends EntityBaseGadget {
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
.
setEntityId
(
getId
())
.
setEntityId
(
getId
())
.
setEntityType
(
ProtEntityType
.
PROT_ENTITY_GADGET
)
.
setEntityType
(
ProtEntityType
.
PROT_ENTITY_
TYPE_
GADGET
)
.
setMotionInfo
(
MotionInfo
.
newBuilder
().
setPos
(
getPosition
().
toProto
()).
setRot
(
getRotation
().
toProto
()).
setSpeed
(
Vector
.
newBuilder
()))
.
setMotionInfo
(
MotionInfo
.
newBuilder
().
setPos
(
getPosition
().
toProto
()).
setRot
(
getRotation
().
toProto
()).
setSpeed
(
Vector
.
newBuilder
()))
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
...
...
src/main/java/emu/grasscutter/game/entity/EntityGadget.java
View file @
a8293102
...
@@ -4,7 +4,7 @@ import java.util.Arrays;
...
@@ -4,7 +4,7 @@ import java.util.Arrays;
import
java.util.List
;
import
java.util.List
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.
def
.GadgetData
;
import
emu.grasscutter.data.
excels
.GadgetData
;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.props.EntityType
;
import
emu.grasscutter.game.props.EntityType
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
...
@@ -122,7 +122,7 @@ public class EntityGadget extends EntityBaseGadget {
...
@@ -122,7 +122,7 @@ public class EntityGadget extends EntityBaseGadget {
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
.
setEntityId
(
getId
())
.
setEntityId
(
getId
())
.
setEntityType
(
ProtEntityType
.
PROT_ENTITY_GADGET
)
.
setEntityType
(
ProtEntityType
.
PROT_ENTITY_
TYPE_
GADGET
)
.
setMotionInfo
(
MotionInfo
.
newBuilder
().
setPos
(
getPosition
().
toProto
()).
setRot
(
getRotation
().
toProto
()).
setSpeed
(
Vector
.
newBuilder
()))
.
setMotionInfo
(
MotionInfo
.
newBuilder
().
setPos
(
getPosition
().
toProto
()).
setRot
(
getRotation
().
toProto
()).
setSpeed
(
Vector
.
newBuilder
()))
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
...
...
src/main/java/emu/grasscutter/game/entity/EntityItem.java
View file @
a8293102
package
emu.grasscutter.game.entity
;
package
emu.grasscutter.game.entity
;
import
emu.grasscutter.data.
def
.ItemData
;
import
emu.grasscutter.data.
excels
.ItemData
;
import
emu.grasscutter.game.inventory.GameItem
;
import
emu.grasscutter.game.inventory.GameItem
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.props.EntityIdType
;
...
@@ -111,7 +111,7 @@ public class EntityItem extends EntityBaseGadget {
...
@@ -111,7 +111,7 @@ public class EntityItem extends EntityBaseGadget {
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
.
setEntityId
(
getId
())
.
setEntityId
(
getId
())
.
setEntityType
(
ProtEntityType
.
PROT_ENTITY_GADGET
)
.
setEntityType
(
ProtEntityType
.
PROT_ENTITY_
TYPE_
GADGET
)
.
setMotionInfo
(
MotionInfo
.
newBuilder
().
setPos
(
getPosition
().
toProto
()).
setRot
(
getRotation
().
toProto
()).
setSpeed
(
Vector
.
newBuilder
()))
.
setMotionInfo
(
MotionInfo
.
newBuilder
().
setPos
(
getPosition
().
toProto
()).
setRot
(
getRotation
().
toProto
()).
setSpeed
(
Vector
.
newBuilder
()))
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
...
@@ -127,7 +127,7 @@ public class EntityItem extends EntityBaseGadget {
...
@@ -127,7 +127,7 @@ public class EntityItem extends EntityBaseGadget {
SceneGadgetInfo
.
Builder
gadgetInfo
=
SceneGadgetInfo
.
newBuilder
()
SceneGadgetInfo
.
Builder
gadgetInfo
=
SceneGadgetInfo
.
newBuilder
()
.
setGadgetId
(
this
.
getItemData
().
getGadgetId
())
.
setGadgetId
(
this
.
getItemData
().
getGadgetId
())
.
setTrifleItem
(
this
.
getItem
().
toProto
())
.
setTrifleItem
(
this
.
getItem
().
toProto
())
.
setBornType
(
GadgetBornType
.
GADGET_BORN_IN_AIR
)
.
setBornType
(
GadgetBornType
.
GADGET_BORN_
TYPE_
IN_AIR
)
.
setAuthorityPeerId
(
this
.
getWorld
().
getHostPeerId
())
.
setAuthorityPeerId
(
this
.
getWorld
().
getHostPeerId
())
.
setIsEnableInteract
(
true
);
.
setIsEnableInteract
(
true
);
...
...
src/main/java/emu/grasscutter/game/entity/EntityMonster.java
View file @
a8293102
...
@@ -2,9 +2,10 @@ package emu.grasscutter.game.entity;
...
@@ -2,9 +2,10 @@ package emu.grasscutter.game.entity;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.common.PropGrowCurve
;
import
emu.grasscutter.data.common.PropGrowCurve
;
import
emu.grasscutter.data.
def
.MonsterCurveData
;
import
emu.grasscutter.data.
excels
.MonsterCurveData
;
import
emu.grasscutter.data.
def
.MonsterData
;
import
emu.grasscutter.data.
excels
.MonsterData
;
import
emu.grasscutter.game.dungeons.DungeonChallenge
;
import
emu.grasscutter.game.dungeons.DungeonChallenge
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
...
@@ -111,17 +112,41 @@ public class EntityMonster extends GameEntity {
...
@@ -111,17 +112,41 @@ public class EntityMonster extends GameEntity {
this
.
poseId
=
poseId
;
this
.
poseId
=
poseId
;
}
}
@Override
public
void
damage
(
float
amount
,
int
killerId
)
{
// Get HP before damage.
float
hpBeforeDamage
=
this
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
);
// Apply damage.
super
.
damage
(
amount
,
killerId
);
// Get HP after damage.
float
hpAfterDamage
=
this
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
);
// Invoke energy drop logic.
for
(
Player
player
:
this
.
getScene
().
getPlayers
())
{
player
.
getEnergyManager
().
handleMonsterEnergyDrop
(
this
,
hpBeforeDamage
,
hpAfterDamage
);
}
}
@Override
@Override
public
void
onDeath
(
int
killerId
)
{
public
void
onDeath
(
int
killerId
)
{
if
(
this
.
getSpawnEntry
()
!=
null
)
{
if
(
this
.
getSpawnEntry
()
!=
null
)
{
this
.
getScene
().
getDeadSpawnedEntities
().
add
(
getSpawnEntry
());
this
.
getScene
().
getDeadSpawnedEntities
().
add
(
getSpawnEntry
());
}
}
if
(
getScene
().
getScriptManager
().
isInit
()
&&
this
.
getGroupId
()
>
0
)
{
// first set the challenge data
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_ANY_MONSTER_DIE
,
null
);
}
if
(
getScene
().
getChallenge
()
!=
null
&&
getScene
().
getChallenge
().
getGroup
().
id
==
this
.
getGroupId
())
{
if
(
getScene
().
getChallenge
()
!=
null
&&
getScene
().
getChallenge
().
getGroup
().
id
==
this
.
getGroupId
())
{
getScene
().
getChallenge
().
onMonsterDie
(
this
);
getScene
().
getChallenge
().
onMonsterDie
(
this
);
}
}
if
(
getScene
().
getScriptManager
().
isInit
()
&&
this
.
getGroupId
()
>
0
)
{
if
(
getScene
().
getScriptManager
().
getScriptMonsterSpawnService
()
!=
null
){
getScene
().
getScriptManager
().
getScriptMonsterSpawnService
().
onMonsterDead
(
this
);
}
// prevent spawn monster after success
if
(
getScene
().
getChallenge
()
!=
null
&&
getScene
().
getChallenge
().
inProgress
()){
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_ANY_MONSTER_DIE
,
null
);
}
}
}
}
public
void
recalcStats
()
{
public
void
recalcStats
()
{
...
@@ -186,7 +211,7 @@ public class EntityMonster extends GameEntity {
...
@@ -186,7 +211,7 @@ public class EntityMonster extends GameEntity {
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
.
setEntityId
(
getId
())
.
setEntityId
(
getId
())
.
setEntityType
(
ProtEntityType
.
PROT_ENTITY_MONSTER
)
.
setEntityType
(
ProtEntityType
.
PROT_ENTITY_
TYPE_
MONSTER
)
.
setMotionInfo
(
this
.
getMotionInfo
())
.
setMotionInfo
(
this
.
getMotionInfo
())
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
.
setEntityClientData
(
EntityClientData
.
newBuilder
())
...
@@ -215,7 +240,7 @@ public class EntityMonster extends GameEntity {
...
@@ -215,7 +240,7 @@ public class EntityMonster extends GameEntity {
.
setAuthorityPeerId
(
getWorld
().
getHostPeerId
())
.
setAuthorityPeerId
(
getWorld
().
getHostPeerId
())
.
setPoseId
(
this
.
getPoseId
())
.
setPoseId
(
this
.
getPoseId
())
.
setBlockId
(
3001
)
.
setBlockId
(
3001
)
.
setBornType
(
MonsterBornType
.
MONSTER_BORN_DEFAULT
)
.
setBornType
(
MonsterBornType
.
MONSTER_BORN_
TYPE_
DEFAULT
)
.
setSpecialNameId
(
40
);
.
setSpecialNameId
(
40
);
if
(
getMonsterData
().
getDescribeData
()
!=
null
)
{
if
(
getMonsterData
().
getDescribeData
()
!=
null
)
{
...
...
src/main/java/emu/grasscutter/game/entity/EntityVehicle.java
View file @
a8293102
...
@@ -106,7 +106,7 @@ public class EntityVehicle extends EntityBaseGadget {
...
@@ -106,7 +106,7 @@ public class EntityVehicle extends EntityBaseGadget {
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfo
.
newBuilder
()
.
setEntityId
(
getId
())
.
setEntityId
(
getId
())
.
setEntityType
(
ProtEntityType
.
PROT_ENTITY_GADGET
)
.
setEntityType
(
ProtEntityType
.
PROT_ENTITY_
TYPE_
GADGET
)
.
setMotionInfo
(
MotionInfo
.
newBuilder
().
setPos
(
getPosition
().
toProto
()).
setRot
(
getRotation
().
toProto
()).
setSpeed
(
Vector
.
newBuilder
()))
.
setMotionInfo
(
MotionInfo
.
newBuilder
().
setPos
(
getPosition
().
toProto
()).
setRot
(
getRotation
().
toProto
()).
setSpeed
(
Vector
.
newBuilder
()))
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
addAnimatorParaList
(
AnimatorParameterValueInfoPair
.
newBuilder
())
.
setGadget
(
gadgetInfo
)
.
setGadget
(
gadgetInfo
)
...
...
src/main/java/emu/grasscutter/game/entity/GameEntity.java
View file @
a8293102
package
emu.grasscutter.game.entity
;
package
emu.grasscutter.game.entity
;
import
java.util.HashMap
;
import
java.util.Map
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.game.world.Scene
;
import
emu.grasscutter.game.world.Scene
;
...
@@ -9,8 +12,11 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
...
@@ -9,8 +12,11 @@ import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo
;
import
emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify
;
import
emu.grasscutter.utils.Position
;
import
emu.grasscutter.utils.Position
;
import
it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
public
abstract
class
GameEntity
{
public
abstract
class
GameEntity
{
protected
int
id
;
protected
int
id
;
...
@@ -25,9 +31,13 @@ public abstract class GameEntity {
...
@@ -25,9 +31,13 @@ public abstract class GameEntity {
private
int
lastMoveSceneTimeMs
;
private
int
lastMoveSceneTimeMs
;
private
int
lastMoveReliableSeq
;
private
int
lastMoveReliableSeq
;
// Abilities
private
Map
<
String
,
Float
>
metaOverrideMap
;
private
Int2ObjectMap
<
String
>
metaModifiers
;
public
GameEntity
(
Scene
scene
)
{
public
GameEntity
(
Scene
scene
)
{
this
.
scene
=
scene
;
this
.
scene
=
scene
;
this
.
moveState
=
MotionState
.
MOTION_NONE
;
this
.
moveState
=
MotionState
.
MOTION_
STATE_
NONE
;
}
}
public
int
getId
()
{
public
int
getId
()
{
...
@@ -54,6 +64,20 @@ public abstract class GameEntity {
...
@@ -54,6 +64,20 @@ public abstract class GameEntity {
return
isAlive
()
?
LifeState
.
LIFE_ALIVE
:
LifeState
.
LIFE_DEAD
;
return
isAlive
()
?
LifeState
.
LIFE_ALIVE
:
LifeState
.
LIFE_DEAD
;
}
}
public
Map
<
String
,
Float
>
getMetaOverrideMap
()
{
if
(
this
.
metaOverrideMap
==
null
)
{
this
.
metaOverrideMap
=
new
HashMap
<>();
}
return
this
.
metaOverrideMap
;
}
public
Int2ObjectMap
<
String
>
getMetaModifiers
()
{
if
(
this
.
metaModifiers
==
null
)
{
this
.
metaModifiers
=
new
Int2ObjectOpenHashMap
<>();
}
return
this
.
metaModifiers
;
}
public
abstract
Int2FloatOpenHashMap
getFightProperties
();
public
abstract
Int2FloatOpenHashMap
getFightProperties
();
public
abstract
Position
getPosition
();
public
abstract
Position
getPosition
();
...
@@ -146,4 +170,53 @@ public abstract class GameEntity {
...
@@ -146,4 +170,53 @@ public abstract class GameEntity {
public
void
setSpawnEntry
(
SpawnDataEntry
spawnEntry
)
{
public
void
setSpawnEntry
(
SpawnDataEntry
spawnEntry
)
{
this
.
spawnEntry
=
spawnEntry
;
this
.
spawnEntry
=
spawnEntry
;
}
}
public
float
heal
(
float
amount
)
{
if
(
this
.
getFightProperties
()
==
null
)
{
return
0
f
;
}
float
curHp
=
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
);
float
maxHp
=
getFightProperty
(
FightProperty
.
FIGHT_PROP_MAX_HP
);
if
(
curHp
>=
maxHp
)
{
return
0
f
;
}
float
healed
=
Math
.
min
(
maxHp
-
curHp
,
amount
);
this
.
addFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
healed
);
getScene
().
broadcastPacket
(
new
PacketEntityFightPropUpdateNotify
(
this
,
FightProperty
.
FIGHT_PROP_CUR_HP
));
return
healed
;
}
public
void
damage
(
float
amount
)
{
damage
(
amount
,
0
);
}
public
void
damage
(
float
amount
,
int
killerId
)
{
// Sanity check
if
(
getFightProperties
()
==
null
)
{
return
;
}
// Lose hp
addFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
-
amount
);
// Check if dead
boolean
isDead
=
false
;
if
(
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
)
<=
0
f
)
{
setFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
,
0
f
);
isDead
=
true
;
}
// Packets
this
.
getScene
().
broadcastPacket
(
new
PacketEntityFightPropUpdateNotify
(
this
,
FightProperty
.
FIGHT_PROP_CUR_HP
));
// Check if dead
if
(
isDead
)
{
getScene
().
killEntity
(
this
,
killerId
);
}
}
}
}
src/main/java/emu/grasscutter/game/expedition/ExpeditionManager.java
View file @
a8293102
...
@@ -2,14 +2,19 @@ package emu.grasscutter.game.expedition;
...
@@ -2,14 +2,19 @@ package emu.grasscutter.game.expedition;
import
com.google.gson.reflect.TypeToken
;
import
com.google.gson.reflect.TypeToken
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.DataLoader
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.game.GameServer
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
java.io.FileReader
;
import
java.io.FileReader
;
import
java.io.InputStreamReader
;
import
java.io.Reader
;
import
java.util.Collection
;
import
java.util.Collection
;
import
java.util.List
;
import
java.util.List
;
import
static
emu
.
grasscutter
.
Configuration
.*;
public
class
ExpeditionManager
{
public
class
ExpeditionManager
{
public
GameServer
getGameServer
()
{
public
GameServer
getGameServer
()
{
return
gameServer
;
return
gameServer
;
...
@@ -28,7 +33,7 @@ public class ExpeditionManager {
...
@@ -28,7 +33,7 @@ public class ExpeditionManager {
}
}
public
synchronized
void
load
()
{
public
synchronized
void
load
()
{
try
(
File
Reader
fileReader
=
new
FileReader
(
Grasscutter
.
getConfig
().
DATA_FOLDER
+
"ExpeditionReward.json"
))
{
try
(
Reader
fileReader
=
new
InputStreamReader
(
DataLoader
.
load
(
"ExpeditionReward.json"
))
)
{
getExpeditionRewardDataList
().
clear
();
getExpeditionRewardDataList
().
clear
();
List
<
ExpeditionRewardInfo
>
banners
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
TypeToken
.
getParameterized
(
Collection
.
class
,
ExpeditionRewardInfo
.
class
).
getType
());
List
<
ExpeditionRewardInfo
>
banners
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
TypeToken
.
getParameterized
(
Collection
.
class
,
ExpeditionRewardInfo
.
class
).
getType
());
if
(
banners
.
size
()
>
0
)
{
if
(
banners
.
size
()
>
0
)
{
...
...
src/main/java/emu/grasscutter/game/friends/FriendsList.java
View file @
a8293102
...
@@ -104,7 +104,7 @@ public class FriendsList {
...
@@ -104,7 +104,7 @@ public class FriendsList {
}
}
// Handle
// Handle
if
(
result
==
DealAddFriendResultType
.
DEAL_ADD_FRIEND_ACCEPT
)
{
// Request accepted
if
(
result
==
DealAddFriendResultType
.
DEAL_ADD_FRIEND_
RESULT_TYPE_
ACCEPT
)
{
// Request accepted
myFriendship
.
setIsFriend
(
true
);
myFriendship
.
setIsFriend
(
true
);
theirFriendship
.
setIsFriend
(
true
);
theirFriendship
.
setIsFriend
(
true
);
...
...
src/main/java/emu/grasscutter/game/friends/Friendship.java
View file @
a8293102
...
@@ -95,13 +95,13 @@ public class Friendship {
...
@@ -95,13 +95,13 @@ public class Friendship {
.
setProfilePicture
(
ProfilePicture
.
newBuilder
().
setAvatarId
(
getFriendProfile
().
getAvatarId
()))
.
setProfilePicture
(
ProfilePicture
.
newBuilder
().
setAvatarId
(
getFriendProfile
().
getAvatarId
()))
.
setWorldLevel
(
getFriendProfile
().
getWorldLevel
())
.
setWorldLevel
(
getFriendProfile
().
getWorldLevel
())
.
setSignature
(
getFriendProfile
().
getSignature
())
.
setSignature
(
getFriendProfile
().
getSignature
())
.
setOnlineState
(
getFriendProfile
().
isOnline
()
?
FriendOnlineState
.
FRIEND_ONLINE
:
FriendOnlineState
.
FREIEND_DISCONNECT
)
.
setOnlineState
(
getFriendProfile
().
isOnline
()
?
FriendOnlineState
.
FRIEND_ONLINE
_STATE_ONLINE
:
FriendOnlineState
.
FRIEND_ONLINE_STATE_
FREIEND_DISCONNECT
)
.
setIsMpModeAvailable
(
true
)
.
setIsMpModeAvailable
(
true
)
.
setLastActiveTime
(
getFriendProfile
().
getLastActiveTime
())
.
setLastActiveTime
(
getFriendProfile
().
getLastActiveTime
())
.
setNameCardId
(
getFriendProfile
().
getNameCard
())
.
setNameCardId
(
getFriendProfile
().
getNameCard
())
.
setParam
(
getFriendProfile
().
getDaysSinceLogin
())
.
setParam
(
getFriendProfile
().
getDaysSinceLogin
())
.
setIsGameSource
(
true
)
.
setIsGameSource
(
true
)
.
setPlatformType
(
PlatformTypeOuterClass
.
PlatformType
.
PC
)
.
setPlatformType
(
PlatformTypeOuterClass
.
PlatformType
.
PLATFORM_TYPE_
PC
)
.
build
();
.
build
();
return
proto
;
return
proto
;
...
...
src/main/java/emu/grasscutter/game/gacha/GachaBanner.java
View file @
a8293102
package
emu.grasscutter.game.gacha
;
package
emu.grasscutter.game.gacha
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo
;
import
emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo
;
import
emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo
;
import
emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo
;
import
emu.grasscutter.utils.Utils
;
import
static
emu
.
grasscutter
.
Configuration
.*;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.common.ItemParamData
;
public
class
GachaBanner
{
public
class
GachaBanner
{
private
int
gachaType
;
private
int
gachaType
;
...
@@ -10,18 +15,35 @@ public class GachaBanner {
...
@@ -10,18 +15,35 @@ public class GachaBanner {
private
String
prefabPath
;
private
String
prefabPath
;
private
String
previewPrefabPath
;
private
String
previewPrefabPath
;
private
String
titlePath
;
private
String
titlePath
;
private
int
costItem
;
private
int
costItemId
=
0
;
private
int
costItemAmount
=
1
;
private
int
costItemId10
=
0
;
private
int
costItemAmount10
=
10
;
private
int
beginTime
;
private
int
beginTime
;
private
int
endTime
;
private
int
endTime
;
private
int
sortId
;
private
int
sortId
;
private
int
[]
rateUpItems1
;
private
int
[]
rateUpItems4
=
{};
private
int
[]
rateUpItems2
;
private
int
[]
rateUpItems5
=
{};
private
int
baseYellowWeight
=
60
;
// Max 10000
private
int
[]
fallbackItems3
=
{
11301
,
11302
,
11306
,
12301
,
12302
,
12305
,
13303
,
14301
,
14302
,
14304
,
15301
,
15302
,
15304
};
private
int
basePurpleWeight
=
510
;
// Max 10000
private
int
[]
fallbackItems4Pool1
=
{
1014
,
1020
,
1023
,
1024
,
1025
,
1027
,
1031
,
1032
,
1034
,
1036
,
1039
,
1043
,
1044
,
1045
,
1048
,
1053
,
1055
,
1056
,
1064
};
private
int
eventChance
=
50
;
// Chance to win a featured event item
private
int
[]
fallbackItems4Pool2
=
{
11401
,
11402
,
11403
,
11405
,
12401
,
12402
,
12403
,
12405
,
13401
,
13407
,
14401
,
14402
,
14403
,
14409
,
15401
,
15402
,
15403
,
15405
};
private
int
softPity
=
75
;
private
int
[]
fallbackItems5Pool1
=
{
1003
,
1016
,
1042
,
1035
,
1041
};
private
int
hardPity
=
90
;
private
int
[]
fallbackItems5Pool2
=
{
11501
,
11502
,
12501
,
12502
,
13502
,
13505
,
14501
,
14502
,
15501
,
15502
};
private
boolean
removeC6FromPool
=
false
;
private
boolean
autoStripRateUpFromFallback
=
true
;
private
int
[][]
weights4
=
{{
1
,
510
},
{
8
,
510
},
{
10
,
10000
}};
private
int
[][]
weights5
=
{{
1
,
75
},
{
73
,
150
},
{
90
,
10000
}};
private
int
[][]
poolBalanceWeights4
=
{{
1
,
255
},
{
17
,
255
},
{
21
,
10455
}};
private
int
[][]
poolBalanceWeights5
=
{{
1
,
30
},
{
147
,
150
},
{
181
,
10230
}};
private
int
eventChance4
=
50
;
// Chance to win a featured event item
private
int
eventChance5
=
50
;
// Chance to win a featured event item
private
BannerType
bannerType
=
BannerType
.
STANDARD
;
private
BannerType
bannerType
=
BannerType
.
STANDARD
;
// Kinda wanna deprecate these but they're in people's configs
private
int
[]
rateUpItems1
=
{};
private
int
[]
rateUpItems2
=
{};
private
int
eventChance
=
-
1
;
private
int
costItem
=
0
;
public
int
getGachaType
()
{
public
int
getGachaType
()
{
return
gachaType
;
return
gachaType
;
...
@@ -47,8 +69,15 @@ public class GachaBanner {
...
@@ -47,8 +69,15 @@ public class GachaBanner {
return
titlePath
;
return
titlePath
;
}
}
public
ItemParamData
getCost
(
int
numRolls
)
{
return
switch
(
numRolls
)
{
case
10
->
new
ItemParamData
((
costItemId10
>
0
)
?
costItemId10
:
getCostItem
(),
costItemAmount10
);
default
->
new
ItemParamData
(
getCostItem
(),
costItemAmount
*
numRolls
);
};
}
public
int
getCostItem
()
{
public
int
getCostItem
()
{
return
costItem
;
return
(
costItem
>
0
)
?
costItem
:
costItemId
;
}
}
public
int
getBeginTime
()
{
public
int
getBeginTime
()
{
...
@@ -63,90 +92,102 @@ public class GachaBanner {
...
@@ -63,90 +92,102 @@ public class GachaBanner {
return
sortId
;
return
sortId
;
}
}
public
int
get
BaseYellowWeight
()
{
public
int
[]
get
RateUpItems4
()
{
return
baseYellowWeight
;
return
(
rateUpItems2
.
length
>
0
)
?
rateUpItems2
:
rateUpItems4
;
}
}
public
int
[]
getRateUpItems5
()
{
public
int
getBasePurpleWeight
()
{
return
(
rateUpItems1
.
length
>
0
)
?
rateUpItems1
:
rateUpItems5
;
return
basePurpleWeight
;
}
}
public
int
[]
getRateUpItems1
()
{
public
int
[]
getFallbackItems3
()
{
return
fallbackItems3
;}
return
rateUpItems1
;
public
int
[]
getFallbackItems4Pool1
()
{
return
fallbackItems4Pool1
;}
}
public
int
[]
getFallbackItems4Pool2
()
{
return
fallbackItems4Pool2
;}
public
int
[]
getFallbackItems5Pool1
()
{
return
fallbackItems5Pool1
;}
public
int
[]
getFallbackItems5Pool2
()
{
return
fallbackItems5Pool2
;}
public
int
[]
getRateUpItems2
()
{
public
boolean
getRemoveC6FromPool
()
{
return
removeC6FromPool
;}
return
rateUpItems2
;
public
boolean
getAutoStripRateUpFromFallback
()
{
return
autoStripRateUpFromFallback
;}
}
public
int
getSoftPity
()
{
public
int
getWeight
(
int
rarity
,
int
pity
)
{
return
softPity
-
1
;
return
switch
(
rarity
)
{
case
4
->
Utils
.
lerp
(
pity
,
weights4
);
default
->
Utils
.
lerp
(
pity
,
weights5
);
};
}
}
public
int
getHardPity
()
{
public
int
getPoolBalanceWeight
(
int
rarity
,
int
pity
)
{
return
hardPity
-
1
;
return
switch
(
rarity
)
{
case
4
->
Utils
.
lerp
(
pity
,
poolBalanceWeights4
);
default
->
Utils
.
lerp
(
pity
,
poolBalanceWeights5
);
};
}
}
public
int
getEventChance
()
{
public
int
getEventChance
(
int
rarity
)
{
return
eventChance
;
return
switch
(
rarity
)
{
case
4
->
eventChance4
;
default
->
(
eventChance
>
-
1
)
?
eventChance
:
eventChance5
;
};
}
}
@Deprecated
@Deprecated
public
GachaInfo
toProto
()
{
public
GachaInfo
toProto
()
{
return
toProto
(
""
);
return
toProto
(
""
);
}
}
public
GachaInfo
toProto
(
String
sessionKey
)
{
public
GachaInfo
toProto
(
String
sessionKey
)
{
String
record
=
"http"
+
(
Grasscutter
.
getConfig
().
getDispatchOptions
().
FrontHTTPS
?
"s"
:
""
)
+
"://"
String
record
=
"http"
+
(
HTTP_ENCRYPTION
.
useInRouting
?
"s"
:
""
)
+
"://"
+
(
Grasscutter
.
getConfig
().
getDispatchOptions
().
PublicIp
.
isEmpty
()
?
+
lr
(
HTTP_INFO
.
accessAddress
,
HTTP_INFO
.
bindAddress
)
+
":"
Grasscutter
.
getConfig
().
getDispatchOptions
().
Ip
:
+
lr
(
HTTP_INFO
.
accessPort
,
HTTP_INFO
.
bindPort
)
Grasscutter
.
getConfig
().
getDispatchOptions
().
PublicIp
)
+
":"
+
Integer
.
toString
(
Grasscutter
.
getConfig
().
getDispatchOptions
().
PublicPort
==
0
?
Grasscutter
.
getConfig
().
getDispatchOptions
().
Port
:
Grasscutter
.
getConfig
().
getDispatchOptions
().
PublicPort
)
+
"/gacha?s="
+
sessionKey
+
"&gachaType="
+
gachaType
;
+
"/gacha?s="
+
sessionKey
+
"&gachaType="
+
gachaType
;
String
details
=
"http"
+
(
HTTP_ENCRYPTION
.
useInRouting
?
"s"
:
""
)
+
"://"
+
lr
(
HTTP_INFO
.
accessAddress
,
HTTP_INFO
.
bindAddress
)
+
":"
+
lr
(
HTTP_INFO
.
accessPort
,
HTTP_INFO
.
bindPort
)
+
"/gacha/details?s="
+
sessionKey
+
"&scheduleId="
+
scheduleId
;
// Grasscutter.getLogger().info("record = " + record);
// Grasscutter.getLogger().info("record = " + record);
ItemParamData
costItem1
=
this
.
getCost
(
1
);
ItemParamData
costItem10
=
this
.
getCost
(
10
);
GachaInfo
.
Builder
info
=
GachaInfo
.
newBuilder
()
GachaInfo
.
Builder
info
=
GachaInfo
.
newBuilder
()
.
setGachaType
(
this
.
getGachaType
())
.
setGachaType
(
this
.
getGachaType
())
.
setScheduleId
(
this
.
getScheduleId
())
.
setScheduleId
(
this
.
getScheduleId
())
.
setBeginTime
(
this
.
getBeginTime
())
.
setBeginTime
(
this
.
getBeginTime
())
.
setEndTime
(
this
.
getEndTime
())
.
setEndTime
(
this
.
getEndTime
())
.
setCostItemId
(
this
.
getCostItem
())
.
setCostItemId
(
costItem1
.
getId
())
.
setCostItemNum
(
1
)
.
setCostItemNum
(
costItem1
.
getCount
())
.
setTenCostItemId
(
costItem10
.
getId
())
.
setTenCostItemNum
(
costItem10
.
getCount
())
.
setGachaPrefabPath
(
this
.
getPrefabPath
())
.
setGachaPrefabPath
(
this
.
getPrefabPath
())
.
setGachaPreviewPrefabPath
(
this
.
getPreviewPrefabPath
())
.
setGachaPreviewPrefabPath
(
this
.
getPreviewPrefabPath
())
.
setGachaProbUrl
(
record
)
.
setGachaProbUrl
(
details
)
.
setGachaProbUrlOversea
(
record
)
.
setGachaProbUrlOversea
(
details
)
.
setGachaRecordUrl
(
record
)
.
setGachaRecordUrl
(
record
)
.
setGachaRecordUrlOversea
(
record
)
.
setGachaRecordUrlOversea
(
record
)
.
setTenCostItemId
(
this
.
getCostItem
())
.
setTenCostItemNum
(
10
)
.
setLeftGachaTimes
(
Integer
.
MAX_VALUE
)
.
setLeftGachaTimes
(
Integer
.
MAX_VALUE
)
.
setGachaTimesLimit
(
Integer
.
MAX_VALUE
)
.
setGachaTimesLimit
(
Integer
.
MAX_VALUE
)
.
setGachaSortId
(
this
.
getSortId
());
.
setGachaSortId
(
this
.
getSortId
());
if
(
this
.
getTitlePath
()
!=
null
)
{
if
(
this
.
getTitlePath
()
!=
null
)
{
info
.
set
GachaTitlePath
(
this
.
getTitlePath
());
info
.
set
TitleTextmap
(
this
.
getTitlePath
());
}
}
if
(
this
.
getRateUpItems
1
().
length
>
0
)
{
if
(
this
.
getRateUpItems
5
().
length
>
0
)
{
GachaUpInfo
.
Builder
upInfo
=
GachaUpInfo
.
newBuilder
().
setItemParentType
(
1
);
GachaUpInfo
.
Builder
upInfo
=
GachaUpInfo
.
newBuilder
().
setItemParentType
(
1
);
for
(
int
id
:
getRateUpItems
1
())
{
for
(
int
id
:
getRateUpItems
5
())
{
upInfo
.
addItemIdList
(
id
);
upInfo
.
addItemIdList
(
id
);
info
.
add
MainNameId
(
id
);
info
.
add
DisplayUp5ItemList
(
id
);
}
}
info
.
addGachaUpInfoList
(
upInfo
);
info
.
addGachaUpInfoList
(
upInfo
);
}
}
if
(
this
.
getRateUpItems
2
().
length
>
0
)
{
if
(
this
.
getRateUpItems
4
().
length
>
0
)
{
GachaUpInfo
.
Builder
upInfo
=
GachaUpInfo
.
newBuilder
().
setItemParentType
(
2
);
GachaUpInfo
.
Builder
upInfo
=
GachaUpInfo
.
newBuilder
().
setItemParentType
(
2
);
for
(
int
id
:
getRateUpItems
2
())
{
for
(
int
id
:
getRateUpItems
4
())
{
upInfo
.
addItemIdList
(
id
);
upInfo
.
addItemIdList
(
id
);
if
(
info
.
get
SubNameId
Count
()
==
0
)
{
if
(
info
.
get
DisplayUp4ItemList
Count
()
==
0
)
{
info
.
add
SubNameId
(
id
);
info
.
add
DisplayUp4ItemList
(
id
);
}
}
}
}
...
...
src/main/java/emu/grasscutter/game/gacha/GachaManager.java
View file @
a8293102
...
@@ -2,8 +2,11 @@ package emu.grasscutter.game.gacha;
...
@@ -2,8 +2,11 @@ package emu.grasscutter.game.gacha;
import
java.io.File
;
import
java.io.File
;
import
java.io.FileReader
;
import
java.io.FileReader
;
import
java.io.InputStreamReader
;
import
java.io.Reader
;
import
java.nio.file.*
;
import
java.nio.file.*
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collection
;
import
java.util.Collection
;
import
java.util.List
;
import
java.util.List
;
import
java.util.concurrent.ThreadLocalRandom
;
import
java.util.concurrent.ThreadLocalRandom
;
...
@@ -12,12 +15,15 @@ import com.google.gson.reflect.TypeToken;
...
@@ -12,12 +15,15 @@ import com.google.gson.reflect.TypeToken;
import
com.sun.nio.file.SensitivityWatchEventModifier
;
import
com.sun.nio.file.SensitivityWatchEventModifier
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.DataLoader
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.def.ItemData
;
import
emu.grasscutter.data.common.ItemParamData
;
import
emu.grasscutter.data.excels.ItemData
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.avatar.Avatar
;
import
emu.grasscutter.game.avatar.Avatar
;
import
emu.grasscutter.game.gacha.GachaBanner.BannerType
;
import
emu.grasscutter.game.gacha.GachaBanner.BannerType
;
import
emu.grasscutter.game.inventory.GameItem
;
import
emu.grasscutter.game.inventory.GameItem
;
import
emu.grasscutter.game.inventory.Inventory
;
import
emu.grasscutter.game.inventory.ItemType
;
import
emu.grasscutter.game.inventory.ItemType
;
import
emu.grasscutter.game.inventory.MaterialType
;
import
emu.grasscutter.game.inventory.MaterialType
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
...
@@ -28,26 +34,25 @@ import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam;
...
@@ -28,26 +34,25 @@ import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.game.GameServer
;
import
emu.grasscutter.server.game.GameServerTickEvent
;
import
emu.grasscutter.server.game.GameServerTickEvent
;
import
emu.grasscutter.server.packet.send.PacketDoGachaRsp
;
import
emu.grasscutter.server.packet.send.PacketDoGachaRsp
;
import
emu.grasscutter.utils.Utils
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.IntArrayList
;
import
it.unimi.dsi.fastutil.ints.IntArrayList
;
import
it.unimi.dsi.fastutil.ints.IntList
;
import
it.unimi.dsi.fastutil.ints.IntList
;
import
org.greenrobot.eventbus.Subscribe
;
import
org.greenrobot.eventbus.Subscribe
;
import
static
emu
.
grasscutter
.
Configuration
.*;
public
class
GachaManager
{
public
class
GachaManager
{
private
final
GameServer
server
;
private
final
GameServer
server
;
private
final
Int2ObjectMap
<
GachaBanner
>
gachaBanners
;
private
final
Int2ObjectMap
<
GachaBanner
>
gachaBanners
;
private
GetGachaInfoRsp
cachedProto
;
private
GetGachaInfoRsp
cachedProto
;
WatchService
watchService
;
WatchService
watchService
;
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
final
int
starglitterId
=
221
;
private
static
int
stardustId
=
222
;
private
static
final
int
stardustId
=
222
;
private
int
[]
fallbackItems4Pool2Default
=
{
11401
,
11402
,
11403
,
11405
,
12401
,
12402
,
12403
,
12405
,
13401
,
13407
,
14401
,
14402
,
14403
,
14409
,
15401
,
15402
,
15403
,
15405
};
private
int
[]
fallbackItems5Pool2Default
=
{
11501
,
11502
,
12501
,
12502
,
13502
,
13505
,
14501
,
14502
,
15501
,
15502
};
public
GachaManager
(
GameServer
server
)
{
public
GachaManager
(
GameServer
server
)
{
this
.
server
=
server
;
this
.
server
=
server
;
...
@@ -64,7 +69,7 @@ public class GachaManager {
...
@@ -64,7 +69,7 @@ public class GachaManager {
return
gachaBanners
;
return
gachaBanners
;
}
}
public
int
randomRange
(
int
min
,
int
max
)
{
public
int
randomRange
(
int
min
,
int
max
)
{
// Both are inclusive
return
ThreadLocalRandom
.
current
().
nextInt
(
max
-
min
+
1
)
+
min
;
return
ThreadLocalRandom
.
current
().
nextInt
(
max
-
min
+
1
)
+
min
;
}
}
...
@@ -73,14 +78,16 @@ public class GachaManager {
...
@@ -73,14 +78,16 @@ public class GachaManager {
}
}
public
synchronized
void
load
()
{
public
synchronized
void
load
()
{
try
(
File
Reader
fileReader
=
new
FileReader
(
Grasscutter
.
getConfig
().
DATA_FOLDER
+
"Banners.json"
))
{
try
(
Reader
fileReader
=
new
InputStreamReader
(
DataLoader
.
load
(
"Banners.json"
))
)
{
getGachaBanners
().
clear
();
getGachaBanners
().
clear
();
List
<
GachaBanner
>
banners
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
TypeToken
.
getParameterized
(
Collection
.
class
,
GachaBanner
.
class
).
getType
());
List
<
GachaBanner
>
banners
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
TypeToken
.
getParameterized
(
Collection
.
class
,
GachaBanner
.
class
).
getType
());
if
(
banners
.
size
()
>
0
)
{
if
(
banners
.
size
()
>
0
)
{
for
(
GachaBanner
banner
:
banners
)
{
for
(
GachaBanner
banner
:
banners
)
{
getGachaBanners
().
put
(
banner
.
get
GachaType
(),
banner
);
getGachaBanners
().
put
(
banner
.
get
ScheduleId
(),
banner
);
}
}
Grasscutter
.
getLogger
().
info
(
"Banners successfully loaded."
);
Grasscutter
.
getLogger
().
info
(
"Banners successfully loaded."
);
this
.
cachedProto
=
createProto
();
this
.
cachedProto
=
createProto
();
}
else
{
}
else
{
Grasscutter
.
getLogger
().
error
(
"Unable to load banners. Banners size is 0."
);
Grasscutter
.
getLogger
().
error
(
"Unable to load banners. Banners size is 0."
);
...
@@ -90,116 +97,196 @@ public class GachaManager {
...
@@ -90,116 +97,196 @@ public class GachaManager {
e
.
printStackTrace
();
e
.
printStackTrace
();
}
}
}
}
private
class
BannerPools
{
public
int
[]
rateUpItems4
;
public
int
[]
rateUpItems5
;
public
int
[]
fallbackItems4Pool1
;
public
int
[]
fallbackItems4Pool2
;
public
int
[]
fallbackItems5Pool1
;
public
int
[]
fallbackItems5Pool2
;
public
BannerPools
(
GachaBanner
banner
)
{
rateUpItems4
=
banner
.
getRateUpItems4
();
rateUpItems5
=
banner
.
getRateUpItems5
();
fallbackItems4Pool1
=
banner
.
getFallbackItems4Pool1
();
fallbackItems4Pool2
=
banner
.
getFallbackItems4Pool2
();
fallbackItems5Pool1
=
banner
.
getFallbackItems5Pool1
();
fallbackItems5Pool2
=
banner
.
getFallbackItems5Pool2
();
if
(
banner
.
getAutoStripRateUpFromFallback
())
{
fallbackItems4Pool1
=
Utils
.
setSubtract
(
fallbackItems4Pool1
,
rateUpItems4
);
fallbackItems4Pool2
=
Utils
.
setSubtract
(
fallbackItems4Pool2
,
rateUpItems4
);
fallbackItems5Pool1
=
Utils
.
setSubtract
(
fallbackItems5Pool1
,
rateUpItems5
);
fallbackItems5Pool2
=
Utils
.
setSubtract
(
fallbackItems5Pool2
,
rateUpItems5
);
}
}
public
void
removeFromAllPools
(
int
[]
itemIds
)
{
rateUpItems4
=
Utils
.
setSubtract
(
rateUpItems4
,
itemIds
);
rateUpItems5
=
Utils
.
setSubtract
(
rateUpItems5
,
itemIds
);
fallbackItems4Pool1
=
Utils
.
setSubtract
(
fallbackItems4Pool1
,
itemIds
);
fallbackItems4Pool2
=
Utils
.
setSubtract
(
fallbackItems4Pool2
,
itemIds
);
fallbackItems5Pool1
=
Utils
.
setSubtract
(
fallbackItems5Pool1
,
itemIds
);
fallbackItems5Pool2
=
Utils
.
setSubtract
(
fallbackItems5Pool2
,
itemIds
);
}
}
private
synchronized
int
checkPlayerAvatarConstellationLevel
(
Player
player
,
int
itemId
)
{
// Maybe this would be useful in the Player class?
ItemData
itemData
=
GameData
.
getItemDataMap
().
get
(
itemId
);
if
((
itemData
==
null
)
||
(
itemData
.
getMaterialType
()
!=
MaterialType
.
MATERIAL_AVATAR
)){
return
-
2
;
// Not an Avatar
}
Avatar
avatar
=
player
.
getAvatars
().
getAvatarById
((
itemId
%
1000
)
+
10000000
);
if
(
avatar
==
null
)
{
return
-
1
;
// Doesn't have
}
// Constellation
int
constLevel
=
avatar
.
getCoreProudSkillLevel
();
GameItem
constItem
=
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
itemId
+
100
);
constLevel
+=
(
constItem
==
null
)?
0
:
constItem
.
getCount
();
return
constLevel
;
}
private
synchronized
int
[]
removeC6FromPool
(
int
[]
itemPool
,
Player
player
)
{
IntList
temp
=
new
IntArrayList
();
for
(
int
itemId
:
itemPool
)
{
if
(
checkPlayerAvatarConstellationLevel
(
player
,
itemId
)
<
6
)
{
temp
.
add
(
itemId
);
}
}
return
temp
.
toIntArray
();
}
private
synchronized
int
drawRoulette
(
int
[]
weights
,
int
cutoff
)
{
// This follows the logic laid out in issue #183
// Simple weighted selection with an upper bound for the roll that cuts off trailing entries
// All weights must be >= 0
int
total
=
0
;
for
(
int
weight
:
weights
)
{
if
(
weight
<
0
)
{
throw
new
IllegalArgumentException
(
"Weights must be non-negative!"
);
}
total
+=
weight
;
}
int
roll
=
ThreadLocalRandom
.
current
().
nextInt
((
total
<
cutoff
)?
total
:
cutoff
);
int
subTotal
=
0
;
for
(
int
i
=
0
;
i
<
weights
.
length
;
i
++)
{
subTotal
+=
weights
[
i
];
if
(
roll
<
subTotal
)
{
return
i
;
}
}
// throw new IllegalStateException();
return
0
;
// This should only be reachable if total==0
}
private
synchronized
int
doRarePull
(
int
[]
featured
,
int
[]
fallback1
,
int
[]
fallback2
,
int
rarity
,
GachaBanner
banner
,
PlayerGachaBannerInfo
gachaInfo
)
{
int
itemId
=
0
;
boolean
pullFeatured
=
(
gachaInfo
.
getFailedFeaturedItemPulls
(
rarity
)
>=
1
)
// Lost previous coinflip
||
(
this
.
randomRange
(
1
,
100
)
<=
banner
.
getEventChance
(
rarity
));
// Won this coinflip
if
(
pullFeatured
&&
(
featured
.
length
>
0
))
{
itemId
=
getRandom
(
featured
);
gachaInfo
.
setFailedFeaturedItemPulls
(
rarity
,
0
);
}
else
{
gachaInfo
.
addFailedFeaturedItemPulls
(
rarity
,
1
);
if
(
fallback1
.
length
<
1
)
{
if
(
fallback2
.
length
<
1
)
{
itemId
=
getRandom
((
rarity
==
5
)?
fallbackItems5Pool2Default
:
fallbackItems4Pool2Default
);
}
else
{
itemId
=
getRandom
(
fallback2
);
}
}
else
if
(
fallback2
.
length
<
1
)
{
itemId
=
getRandom
(
fallback1
);
}
else
{
// Both pools are possible, use the pool balancer
int
pityPool1
=
banner
.
getPoolBalanceWeight
(
rarity
,
gachaInfo
.
getPityPool
(
rarity
,
1
));
int
pityPool2
=
banner
.
getPoolBalanceWeight
(
rarity
,
gachaInfo
.
getPityPool
(
rarity
,
2
));
int
chosenPool
=
switch
((
pityPool1
>=
pityPool2
)?
1
:
0
)
{
// Larger weight must come first for the hard cutoff to function correctly
case
1
->
1
+
drawRoulette
(
new
int
[]
{
pityPool1
,
pityPool2
},
10000
);
default
->
2
-
drawRoulette
(
new
int
[]
{
pityPool2
,
pityPool1
},
10000
);
};
itemId
=
switch
(
chosenPool
)
{
case
1
:
gachaInfo
.
setPityPool
(
rarity
,
1
,
0
);
yield
getRandom
(
fallback1
);
default
:
gachaInfo
.
setPityPool
(
rarity
,
2
,
0
);
yield
getRandom
(
fallback2
);
};
}
}
return
itemId
;
}
private
synchronized
int
doPull
(
GachaBanner
banner
,
PlayerGachaBannerInfo
gachaInfo
,
BannerPools
pools
)
{
// Pre-increment all pity pools (yes this makes all calculations assume 1-indexed pity)
gachaInfo
.
incPityAll
();
int
[]
weights
=
{
banner
.
getWeight
(
5
,
gachaInfo
.
getPity5
()),
banner
.
getWeight
(
4
,
gachaInfo
.
getPity4
()),
10000
};
int
levelWon
=
5
-
drawRoulette
(
weights
,
10000
);
return
switch
(
levelWon
)
{
case
5
:
gachaInfo
.
setPity5
(
0
);
yield
doRarePull
(
pools
.
rateUpItems5
,
pools
.
fallbackItems5Pool1
,
pools
.
fallbackItems5Pool2
,
5
,
banner
,
gachaInfo
);
case
4
:
gachaInfo
.
setPity4
(
0
);
yield
doRarePull
(
pools
.
rateUpItems4
,
pools
.
fallbackItems4Pool1
,
pools
.
fallbackItems4Pool2
,
4
,
banner
,
gachaInfo
);
default
:
yield
getRandom
(
banner
.
getFallbackItems3
());
};
}
public
synchronized
void
doPulls
(
Player
player
,
int
gachaType
,
int
times
)
{
public
synchronized
void
doPulls
(
Player
player
,
int
scheduleId
,
int
times
)
{
// Sanity check
// Sanity check
if
(
times
!=
10
&&
times
!=
1
)
{
if
(
times
!=
10
&&
times
!=
1
)
{
return
;
return
;
}
}
if
(
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_WEAPON
).
getSize
()
+
times
>
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_WEAPON
).
getMaxCapacity
())
{
Inventory
inventory
=
player
.
getInventory
();
if
(
inventory
.
getInventoryTab
(
ItemType
.
ITEM_WEAPON
).
getSize
()
+
times
>
inventory
.
getInventoryTab
(
ItemType
.
ITEM_WEAPON
).
getMaxCapacity
())
{
player
.
sendPacket
(
new
PacketDoGachaRsp
());
player
.
sendPacket
(
new
PacketDoGachaRsp
());
return
;
return
;
}
}
// Get banner
// Get banner
GachaBanner
banner
=
this
.
getGachaBanners
().
get
(
gachaType
);
GachaBanner
banner
=
this
.
getGachaBanners
().
get
(
scheduleId
);
if
(
banner
==
null
)
{
if
(
banner
==
null
)
{
player
.
sendPacket
(
new
PacketDoGachaRsp
());
player
.
sendPacket
(
new
PacketDoGachaRsp
());
return
;
return
;
}
}
// Spend currency
// Spend currency
if
(
banner
.
getCostItem
()
>
0
)
{
ItemParamData
cost
=
banner
.
getCost
(
times
);
GameItem
costItem
=
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
banner
.
getCostItem
());
if
(
cost
.
getCount
()
>
0
&&
!
inventory
.
payItem
(
cost
))
{
if
(
costItem
==
null
||
costItem
.
getCount
()
<
times
)
{
player
.
sendPacket
(
new
PacketDoGachaRsp
());
return
;
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
=
banner
.
getBaseYellowWeight
()
+
(
int
)
Math
.
floor
(
100
f
*
(
gachaInfo
.
getPity5
()
/
(
banner
.
getSoftPity
()
-
1
D
)))
+
bonusYellowChance
;
int
purpleChance
=
10000
-
(
banner
.
getBasePurpleWeight
()
+
(
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
.
getBannerType
()
==
BannerType
.
WEAPON
?
2
:
1
,
banner
.
getBannerType
()
==
BannerType
.
EVENT
?
1
:
2
);
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
.
getBannerType
()
==
BannerType
.
WEAPON
?
2
:
1
,
banner
.
getBannerType
()
==
BannerType
.
EVENT
?
1
:
2
);
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
// Add to character
PlayerGachaBannerInfo
gachaInfo
=
player
.
getGachaInfo
().
getBannerInfo
(
banner
);
BannerPools
pools
=
new
BannerPools
(
banner
);
List
<
GachaItem
>
list
=
new
ArrayList
<>();
List
<
GachaItem
>
list
=
new
ArrayList
<>();
int
stardust
=
0
,
starglitter
=
0
;
int
stardust
=
0
,
starglitter
=
0
;
if
(
banner
.
getRemoveC6FromPool
())
{
// The ultimate form of pity (non-vanilla)
pools
.
rateUpItems4
=
removeC6FromPool
(
pools
.
rateUpItems4
,
player
);
pools
.
rateUpItems5
=
removeC6FromPool
(
pools
.
rateUpItems5
,
player
);
pools
.
fallbackItems4Pool1
=
removeC6FromPool
(
pools
.
fallbackItems4Pool1
,
player
);
pools
.
fallbackItems4Pool2
=
removeC6FromPool
(
pools
.
fallbackItems4Pool2
,
player
);
pools
.
fallbackItems5Pool1
=
removeC6FromPool
(
pools
.
fallbackItems5Pool1
,
player
);
pools
.
fallbackItems5Pool2
=
removeC6FromPool
(
pools
.
fallbackItems5Pool2
,
player
);
}
for
(
int
itemId
:
wonItems
)
{
for
(
int
i
=
0
;
i
<
times
;
i
++)
{
// Roll
int
itemId
=
doPull
(
banner
,
gachaInfo
,
pools
);
ItemData
itemData
=
GameData
.
getItemDataMap
().
get
(
itemId
);
ItemData
itemData
=
GameData
.
getItemDataMap
().
get
(
itemId
);
if
(
itemData
==
null
)
{
if
(
itemData
==
null
)
{
continue
;
continue
;
// Maybe we should bail out if an item fails instead of rolling the rest?
}
}
// Write gacha record
// Write gacha record
GachaRecord
gachaRecord
=
new
GachaRecord
(
itemId
,
player
.
getUid
(),
g
achaType
);
GachaRecord
gachaRecord
=
new
GachaRecord
(
itemId
,
player
.
getUid
(),
banner
.
getG
achaType
()
);
DatabaseHelper
.
saveGachaRecord
(
gachaRecord
);
DatabaseHelper
.
saveGachaRecord
(
gachaRecord
);
// Create gacha item
// Create gacha item
...
@@ -208,63 +295,47 @@ public class GachaManager {
...
@@ -208,63 +295,47 @@ public class GachaManager {
boolean
isTransferItem
=
false
;
boolean
isTransferItem
=
false
;
// Const check
// Const check
if
(
itemData
.
getMaterialType
()
==
MaterialType
.
MATERIAL_AVATAR
)
{
int
constellation
=
checkPlayerAvatarConstellationLevel
(
player
,
itemId
);
int
avatarId
=
(
itemData
.
getId
()
%
1000
)
+
10000000
;
switch
(
constellation
)
{
Avatar
avatar
=
player
.
getAvatars
().
getAvatarById
(
avatarId
);
case
-
2
:
// Is weapon
if
(
avatar
!=
null
)
{
switch
(
itemData
.
getRankLevel
())
{
int
constLevel
=
avatar
.
getCoreProudSkillLevel
();
case
5
->
addStarglitter
=
10
;
int
constItemId
=
itemData
.
getId
()
+
100
;
case
4
->
addStarglitter
=
2
;
GameItem
constItem
=
player
.
getInventory
().
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
constItemId
);
default
->
addStardust
=
15
;
if
(
constItem
!=
null
)
{
constLevel
+=
constItem
.
getCount
();
}
}
break
;
if
(
constLevel
<
6
)
{
case
-
1
:
// New character
// Not max const
gachaItem
.
setIsGachaItemNew
(
true
);
addStarglitter
=
2
;
break
;
// Add 1 const
default
:
if
(
constellation
>=
6
)
{
// C6, give consolation starglitter
addStarglitter
=
(
itemData
.
getRankLevel
()==
5
)?
25
:
5
;
}
else
{
// C0-C5, give constellation item
if
(
banner
.
getRemoveC6FromPool
()
&&
constellation
==
5
)
{
// New C6, remove it from the pools so we don't get C7 in a 10pull
pools
.
removeFromAllPools
(
new
int
[]
{
itemId
});
}
addStarglitter
=
(
itemData
.
getRankLevel
()==
5
)?
10
:
2
;
int
constItemId
=
itemId
+
100
;
GameItem
constItem
=
inventory
.
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
constItemId
);
gachaItem
.
addTransferItems
(
GachaTransferItem
.
newBuilder
().
setItem
(
ItemParam
.
newBuilder
().
setItemId
(
constItemId
).
setCount
(
1
)).
setIsTransferItemNew
(
constItem
==
null
));
gachaItem
.
addTransferItems
(
GachaTransferItem
.
newBuilder
().
setItem
(
ItemParam
.
newBuilder
().
setItemId
(
constItemId
).
setCount
(
1
)).
setIsTransferItemNew
(
constItem
==
null
));
player
.
getInventory
().
addItem
(
constItemId
,
1
);
inventory
.
addItem
(
constItemId
,
1
);
}
else
{
// Is max const
addStarglitter
=
5
;
}
}
if
(
itemData
.
getRankLevel
()
==
5
)
{
addStarglitter
*=
5
;
}
isTransferItem
=
true
;
isTransferItem
=
true
;
}
else
{
break
;
// 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
// Create item
GameItem
item
=
new
GameItem
(
itemData
);
GameItem
item
=
new
GameItem
(
itemData
);
gachaItem
.
setGachaItem
(
item
.
toItemParam
());
gachaItem
.
setGachaItem
(
item
.
toItemParam
());
player
.
getI
nventory
()
.
addItem
(
item
);
i
nventory
.
addItem
(
item
);
stardust
+=
addStardust
;
stardust
+=
addStardust
;
starglitter
+=
addStarglitter
;
starglitter
+=
addStarglitter
;
if
(
addStardust
>
0
)
{
if
(
addStardust
>
0
)
{
gachaItem
.
addTokenItemList
(
ItemParam
.
newBuilder
().
setItemId
(
stardustId
).
setCount
(
addStardust
));
gachaItem
.
addTokenItemList
(
ItemParam
.
newBuilder
().
setItemId
(
stardustId
).
setCount
(
addStardust
));
}
if
(
addStarglitter
>
0
)
{
}
if
(
addStarglitter
>
0
)
{
ItemParam
starglitterParam
=
ItemParam
.
newBuilder
().
setItemId
(
starglitterId
).
setCount
(
addStarglitter
).
build
();
ItemParam
starglitterParam
=
ItemParam
.
newBuilder
().
setItemId
(
starglitterId
).
setCount
(
addStarglitter
).
build
();
if
(
isTransferItem
)
{
if
(
isTransferItem
)
{
gachaItem
.
addTransferItems
(
GachaTransferItem
.
newBuilder
().
setItem
(
starglitterParam
));
gachaItem
.
addTransferItems
(
GachaTransferItem
.
newBuilder
().
setItem
(
starglitterParam
));
...
@@ -277,9 +348,10 @@ public class GachaManager {
...
@@ -277,9 +348,10 @@ public class GachaManager {
// Add stardust/starglitter
// Add stardust/starglitter
if
(
stardust
>
0
)
{
if
(
stardust
>
0
)
{
player
.
getInventory
().
addItem
(
stardustId
,
stardust
);
inventory
.
addItem
(
stardustId
,
stardust
);
}
if
(
starglitter
>
0
)
{
}
player
.
getInventory
().
addItem
(
starglitterId
,
starglitter
);
if
(
starglitter
>
0
)
{
inventory
.
addItem
(
starglitterId
,
starglitter
);
}
}
// Packets
// Packets
...
@@ -290,7 +362,7 @@ public class GachaManager {
...
@@ -290,7 +362,7 @@ public class GachaManager {
if
(
this
.
watchService
==
null
)
{
if
(
this
.
watchService
==
null
)
{
try
{
try
{
this
.
watchService
=
FileSystems
.
getDefault
().
newWatchService
();
this
.
watchService
=
FileSystems
.
getDefault
().
newWatchService
();
Path
path
=
new
File
(
Grasscutter
.
getConfig
().
DATA_FOLDER
).
toPath
();
Path
path
=
new
File
(
DATA
()
).
toPath
();
path
.
register
(
watchService
,
new
WatchEvent
.
Kind
[]{
StandardWatchEventKinds
.
ENTRY_MODIFY
},
SensitivityWatchEventModifier
.
HIGH
);
path
.
register
(
watchService
,
new
WatchEvent
.
Kind
[]{
StandardWatchEventKinds
.
ENTRY_MODIFY
},
SensitivityWatchEventModifier
.
HIGH
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"Unable to load the Gacha Manager Watch Service. If ServerOptions.watchGacha is true it will not auto-reload"
);
Grasscutter
.
getLogger
().
error
(
"Unable to load the Gacha Manager Watch Service. If ServerOptions.watchGacha is true it will not auto-reload"
);
...
@@ -303,7 +375,7 @@ public class GachaManager {
...
@@ -303,7 +375,7 @@ public class GachaManager {
@Subscribe
@Subscribe
public
synchronized
void
watchBannerJson
(
GameServerTickEvent
tickEvent
)
{
public
synchronized
void
watchBannerJson
(
GameServerTickEvent
tickEvent
)
{
if
(
G
rasscutter
.
getConfig
().
getGameServerOptions
().
W
atchGacha
)
{
if
(
G
AME_OPTIONS
.
w
atchGacha
Config
)
{
try
{
try
{
WatchKey
watchKey
=
watchService
.
take
();
WatchKey
watchKey
=
watchService
.
take
();
...
@@ -340,8 +412,13 @@ public class GachaManager {
...
@@ -340,8 +412,13 @@ public class GachaManager {
private
synchronized
GetGachaInfoRsp
createProto
(
String
sessionKey
)
{
private
synchronized
GetGachaInfoRsp
createProto
(
String
sessionKey
)
{
GetGachaInfoRsp
.
Builder
proto
=
GetGachaInfoRsp
.
newBuilder
().
setGachaRandom
(
12345
);
GetGachaInfoRsp
.
Builder
proto
=
GetGachaInfoRsp
.
newBuilder
().
setGachaRandom
(
12345
);
long
currentTime
=
System
.
currentTimeMillis
()
/
1000L
;
for
(
GachaBanner
banner
:
getGachaBanners
().
values
())
{
for
(
GachaBanner
banner
:
getGachaBanners
().
values
())
{
proto
.
addGachaInfoList
(
banner
.
toProto
(
sessionKey
));
if
((
banner
.
getEndTime
()
>=
currentTime
&&
banner
.
getBeginTime
()
<=
currentTime
)
||
(
banner
.
getBannerType
()
==
BannerType
.
STANDARD
))
{
proto
.
addGachaInfoList
(
banner
.
toProto
(
sessionKey
));
}
}
}
return
proto
.
build
();
return
proto
.
build
();
...
...
src/main/java/emu/grasscutter/game/gacha/PlayerGachaBannerInfo.java
View file @
a8293102
...
@@ -7,6 +7,11 @@ public class PlayerGachaBannerInfo {
...
@@ -7,6 +7,11 @@ public class PlayerGachaBannerInfo {
private
int
pity5
=
0
;
private
int
pity5
=
0
;
private
int
pity4
=
0
;
private
int
pity4
=
0
;
private
int
failedFeaturedItemPulls
=
0
;
private
int
failedFeaturedItemPulls
=
0
;
private
int
failedFeatured4ItemPulls
=
0
;
private
int
pity5Pool1
=
0
;
private
int
pity5Pool2
=
0
;
private
int
pity4Pool1
=
0
;
private
int
pity4Pool2
=
0
;
public
int
getPity5
()
{
public
int
getPity5
()
{
return
pity5
;
return
pity5
;
...
@@ -32,15 +37,82 @@ public class PlayerGachaBannerInfo {
...
@@ -32,15 +37,82 @@ public class PlayerGachaBannerInfo {
this
.
pity4
+=
amount
;
this
.
pity4
+=
amount
;
}
}
public
int
getFailedFeaturedItemPulls
()
{
public
int
getFailedFeaturedItemPulls
(
int
rarity
)
{
return
failedFeaturedItemPulls
;
return
switch
(
rarity
)
{
case
4
->
failedFeatured4ItemPulls
;
default
->
failedFeaturedItemPulls
;
// 5
};
}
}
public
void
setFailedFeaturedItemPulls
(
int
failedEventCharacterPulls
)
{
public
void
setFailedFeaturedItemPulls
(
int
rarity
,
int
amount
)
{
this
.
failedFeaturedItemPulls
=
failedEventCharacterPulls
;
switch
(
rarity
)
{
case
4
->
failedFeatured4ItemPulls
=
amount
;
default
->
failedFeaturedItemPulls
=
amount
;
// 5
};
}
}
public
void
addFailedFeaturedItemPulls
(
int
amount
)
{
public
void
addFailedFeaturedItemPulls
(
int
rarity
,
int
amount
)
{
failedFeaturedItemPulls
+=
amount
;
switch
(
rarity
)
{
case
4
->
failedFeatured4ItemPulls
+=
amount
;
default
->
failedFeaturedItemPulls
+=
amount
;
// 5
};
}
public
int
getPityPool
(
int
rarity
,
int
pool
)
{
return
switch
(
rarity
)
{
case
4
->
switch
(
pool
)
{
case
1
->
pity4Pool1
;
default
->
pity4Pool2
;
};
default
->
switch
(
pool
)
{
case
1
->
pity5Pool1
;
default
->
pity5Pool2
;
};
};
}
public
void
setPityPool
(
int
rarity
,
int
pool
,
int
amount
)
{
switch
(
rarity
)
{
case
4
:
switch
(
pool
)
{
case
1
->
pity4Pool1
=
amount
;
default
->
pity4Pool2
=
amount
;
};
break
;
case
5
:
default
:
switch
(
pool
)
{
case
1
->
pity5Pool1
=
amount
;
default
->
pity5Pool2
=
amount
;
};
break
;
};
}
public
void
addPityPool
(
int
rarity
,
int
pool
,
int
amount
)
{
switch
(
rarity
)
{
case
4
:
switch
(
pool
)
{
case
1
->
pity4Pool1
+=
amount
;
default
->
pity4Pool2
+=
amount
;
};
break
;
case
5
:
default
:
switch
(
pool
)
{
case
1
->
pity5Pool1
+=
amount
;
default
->
pity5Pool2
+=
amount
;
};
break
;
};
}
public
void
incPityAll
()
{
pity4
++;
pity5
++;
pity4Pool1
++;
pity4Pool2
++;
pity5Pool1
++;
pity5Pool2
++;
}
}
}
}
src/main/java/emu/grasscutter/game/inventory/GameItem.java
View file @
a8293102
...
@@ -15,9 +15,9 @@ import dev.morphia.annotations.Transient;
...
@@ -15,9 +15,9 @@ import dev.morphia.annotations.Transient;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameDepot
;
import
emu.grasscutter.data.GameDepot
;
import
emu.grasscutter.data.
def
.ItemData
;
import
emu.grasscutter.data.
excels
.ItemData
;
import
emu.grasscutter.data.
def
.ReliquaryAffixData
;
import
emu.grasscutter.data.
excels
.ReliquaryAffixData
;
import
emu.grasscutter.data.
def
.ReliquaryMainPropData
;
import
emu.grasscutter.data.
excels
.ReliquaryMainPropData
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.FightProperty
;
...
...
src/main/java/emu/grasscutter/game/inventory/Inventory.java
View file @
a8293102
...
@@ -6,16 +6,15 @@ import java.util.LinkedList;
...
@@ -6,16 +6,15 @@ import java.util.LinkedList;
import
java.util.List
;
import
java.util.List
;
import
emu.grasscutter.GameConstants
;
import
emu.grasscutter.GameConstants
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.def.AvatarCostumeData
;
import
emu.grasscutter.data.common.ItemParamData
;
import
emu.grasscutter.data.def.AvatarData
;
import
emu.grasscutter.data.excels.AvatarCostumeData
;
import
emu.grasscutter.data.def.AvatarFlycloakData
;
import
emu.grasscutter.data.excels.AvatarData
;
import
emu.grasscutter.data.def.ItemData
;
import
emu.grasscutter.data.excels.AvatarFlycloakData
;
import
emu.grasscutter.data.excels.ItemData
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.database.DatabaseHelper
;
import
emu.grasscutter.game.avatar.AvatarStorage
;
import
emu.grasscutter.game.avatar.AvatarStorage
;
import
emu.grasscutter.game.avatar.Avatar
;
import
emu.grasscutter.game.avatar.Avatar
;
import
emu.grasscutter.game.entity.EntityAvatar
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.ActionReason
;
import
emu.grasscutter.game.props.ActionReason
;
import
emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam
;
import
emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam
;
...
@@ -28,6 +27,8 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
...
@@ -28,6 +27,8 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import
it.unimi.dsi.fastutil.longs.Long2ObjectMap
;
import
it.unimi.dsi.fastutil.longs.Long2ObjectMap
;
import
it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
;
import
it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
;
import
static
emu
.
grasscutter
.
Configuration
.*;
public
class
Inventory
implements
Iterable
<
GameItem
>
{
public
class
Inventory
implements
Iterable
<
GameItem
>
{
private
final
Player
player
;
private
final
Player
player
;
...
@@ -39,10 +40,10 @@ public class Inventory implements Iterable<GameItem> {
...
@@ -39,10 +40,10 @@ public class Inventory implements Iterable<GameItem> {
this
.
store
=
new
Long2ObjectOpenHashMap
<>();
this
.
store
=
new
Long2ObjectOpenHashMap
<>();
this
.
inventoryTypes
=
new
Int2ObjectOpenHashMap
<>();
this
.
inventoryTypes
=
new
Int2ObjectOpenHashMap
<>();
this
.
createInventoryTab
(
ItemType
.
ITEM_WEAPON
,
new
EquipInventoryTab
(
Grasscutter
.
getConfig
().
getGameServerOptions
().
InventoryLimitWeapon
));
this
.
createInventoryTab
(
ItemType
.
ITEM_WEAPON
,
new
EquipInventoryTab
(
INVENTORY_LIMITS
.
weapons
));
this
.
createInventoryTab
(
ItemType
.
ITEM_RELIQUARY
,
new
EquipInventoryTab
(
Grasscutter
.
getConfig
().
getGameServerOptions
().
InventoryLimitR
elic
));
this
.
createInventoryTab
(
ItemType
.
ITEM_RELIQUARY
,
new
EquipInventoryTab
(
INVENTORY_LIMITS
.
r
elic
s
));
this
.
createInventoryTab
(
ItemType
.
ITEM_MATERIAL
,
new
MaterialInventoryTab
(
Grasscutter
.
getConfig
().
getGameServerOptions
().
InventoryLimitM
aterial
));
this
.
createInventoryTab
(
ItemType
.
ITEM_MATERIAL
,
new
MaterialInventoryTab
(
INVENTORY_LIMITS
.
m
aterial
s
));
this
.
createInventoryTab
(
ItemType
.
ITEM_FURNITURE
,
new
MaterialInventoryTab
(
Grasscutter
.
getConfig
().
getGameServerOptions
().
InventoryLimitF
urniture
));
this
.
createInventoryTab
(
ItemType
.
ITEM_FURNITURE
,
new
MaterialInventoryTab
(
INVENTORY_LIMITS
.
f
urniture
));
}
}
public
Player
getPlayer
()
{
public
Player
getPlayer
()
{
...
@@ -149,6 +150,14 @@ public class Inventory implements Iterable<GameItem> {
...
@@ -149,6 +150,14 @@ public class Inventory implements Iterable<GameItem> {
addItems
(
items
.
stream
().
map
(
param
->
new
GameItem
(
param
.
getItemId
(),
param
.
getCount
())).
toList
(),
null
);
addItems
(
items
.
stream
().
map
(
param
->
new
GameItem
(
param
.
getItemId
(),
param
.
getCount
())).
toList
(),
null
);
}
}
public
void
addItemParamDatas
(
Collection
<
ItemParamData
>
items
)
{
addItemParamDatas
(
items
,
null
);
}
public
void
addItemParamDatas
(
Collection
<
ItemParamData
>
items
,
ActionReason
reason
)
{
addItems
(
items
.
stream
().
map
(
param
->
new
GameItem
(
param
.
getItemId
(),
param
.
getCount
())).
toList
(),
reason
);
}
private
synchronized
GameItem
putItem
(
GameItem
item
)
{
private
synchronized
GameItem
putItem
(
GameItem
item
)
{
// Dont add items that dont have a valid item definition.
// Dont add items that dont have a valid item definition.
if
(
item
.
getItemData
()
==
null
)
{
if
(
item
.
getItemData
()
==
null
)
{
...
@@ -172,6 +181,9 @@ public class Inventory implements Iterable<GameItem> {
...
@@ -172,6 +181,9 @@ public class Inventory implements Iterable<GameItem> {
// Handle
// Handle
this
.
addVirtualItem
(
item
.
getItemId
(),
item
.
getCount
());
this
.
addVirtualItem
(
item
.
getItemId
(),
item
.
getCount
());
return
item
;
return
item
;
}
else
if
(
item
.
getItemData
().
getMaterialType
()
==
MaterialType
.
MATERIAL_ADSORBATE
)
{
this
.
player
.
getEnergyManager
().
handlePickupElemBall
(
item
);
return
null
;
}
else
if
(
item
.
getItemData
().
getMaterialType
()
==
MaterialType
.
MATERIAL_AVATAR
)
{
}
else
if
(
item
.
getItemData
().
getMaterialType
()
==
MaterialType
.
MATERIAL_AVATAR
)
{
// Get avatar id
// Get avatar id
int
avatarId
=
(
item
.
getItemId
()
%
1000
)
+
10000000
;
int
avatarId
=
(
item
.
getItemId
()
%
1000
)
+
10000000
;
...
@@ -228,6 +240,7 @@ public class Inventory implements Iterable<GameItem> {
...
@@ -228,6 +240,7 @@ public class Inventory implements Iterable<GameItem> {
}
}
private
synchronized
void
putItem
(
GameItem
item
,
InventoryTab
tab
)
{
private
synchronized
void
putItem
(
GameItem
item
,
InventoryTab
tab
)
{
getPlayer
().
getCodex
().
checkAddedItem
(
item
);
// Set owner and guid FIRST!
// Set owner and guid FIRST!
item
.
setOwner
(
getPlayer
());
item
.
setOwner
(
getPlayer
());
// Put in item store
// Put in item store
...
@@ -239,26 +252,78 @@ public class Inventory implements Iterable<GameItem> {
...
@@ -239,26 +252,78 @@ public class Inventory implements Iterable<GameItem> {
private
void
addVirtualItem
(
int
itemId
,
int
count
)
{
private
void
addVirtualItem
(
int
itemId
,
int
count
)
{
switch
(
itemId
)
{
switch
(
itemId
)
{
case
101
:
// Character exp
case
101
->
// Character exp
getPlayer
().
getServer
().
getInventoryManager
().
upgradeAvatar
(
player
,
getPlayer
().
getTeamManager
().
getCurrentAvatarEntity
().
getAvatar
(),
count
);
getPlayer
().
getServer
().
getInventoryManager
().
upgradeAvatar
(
player
,
getPlayer
().
getTeamManager
().
getCurrentAvatarEntity
().
getAvatar
(),
count
);
break
;
case
102
->
// Adventure exp
case
102
:
// Adventure exp
getPlayer
().
addExpDirectly
(
count
);
getPlayer
().
addExpDirectly
(
count
);
case
105
->
// Companionship exp
break
;
getPlayer
().
getServer
().
getInventoryManager
().
upgradeAvatarFetterLevel
(
player
,
getPlayer
().
getTeamManager
().
getCurrentAvatarEntity
().
getAvatar
(),
count
);
case
105
:
// Companionship exp
case
201
->
// Primogem
getPlayer
().
getServer
().
getInventoryManager
().
upgradeAvatarFetterLevel
(
player
,
getPlayer
().
getTeamManager
().
getCurrentAvatarEntity
().
getAvatar
(),
count
);
getPlayer
().
setPrimogems
(
player
.
getPrimogems
()
+
count
);
break
;
case
202
->
// Mora
case
201
:
// Primogem
getPlayer
().
setMora
(
player
.
getMora
()
+
count
);
getPlayer
().
setPrimogems
(
player
.
getPrimogems
()
+
count
);
case
203
->
// Genesis Crystals
break
;
getPlayer
().
setCrystals
(
player
.
getCrystals
()
+
count
);
case
202
:
// Mora
}
getPlayer
().
setMora
(
player
.
getMora
()
+
count
);
}
break
;
case
203
:
// Genesis Crystals
private
int
getVirtualItemCount
(
int
itemId
)
{
getPlayer
().
setCrystals
(
player
.
getCrystals
()
+
count
);
switch
(
itemId
)
{
break
;
case
201
:
// Primogem
return
player
.
getPrimogems
();
case
202
:
// Mora
return
player
.
getMora
();
case
203
:
// Genesis Crystals
return
player
.
getCrystals
();
default
:
GameItem
item
=
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
itemId
);
// What if we ever want to operate on weapons/relics/furniture? :S
return
(
item
==
null
)
?
0
:
item
.
getCount
();
}
}
}
}
public
boolean
payItem
(
int
id
,
int
count
)
{
return
payItem
(
new
ItemParamData
(
id
,
count
));
}
public
boolean
payItem
(
ItemParamData
costItem
)
{
return
payItems
(
new
ItemParamData
[]
{
costItem
},
1
,
null
);
}
public
boolean
payItems
(
ItemParamData
[]
costItems
)
{
return
payItems
(
costItems
,
1
,
null
);
}
public
boolean
payItems
(
ItemParamData
[]
costItems
,
int
quantity
)
{
return
payItems
(
costItems
,
quantity
,
null
);
}
public
synchronized
boolean
payItems
(
ItemParamData
[]
costItems
,
int
quantity
,
ActionReason
reason
)
{
// Make sure player has requisite items
for
(
ItemParamData
cost
:
costItems
)
{
if
(
getVirtualItemCount
(
cost
.
getId
())
<
(
cost
.
getCount
()
*
quantity
))
{
return
false
;
}
}
// All costs are satisfied, now remove them all
for
(
ItemParamData
cost
:
costItems
)
{
switch
(
cost
.
getId
())
{
case
201
->
// Primogem
player
.
setPrimogems
(
player
.
getPrimogems
()
-
(
cost
.
getCount
()
*
quantity
));
case
202
->
// Mora
player
.
setMora
(
player
.
getMora
()
-
(
cost
.
getCount
()
*
quantity
));
case
203
->
// Genesis Crystals
player
.
setCrystals
(
player
.
getCrystals
()
-
(
cost
.
getCount
()
*
quantity
));
default
->
removeItem
(
getInventoryTab
(
ItemType
.
ITEM_MATERIAL
).
getItemById
(
cost
.
getId
()),
cost
.
getCount
()
*
quantity
);
}
}
if
(
reason
!=
null
)
{
// Do we need these?
// getPlayer().sendPacket(new PacketItemAddHintNotify(changedItems, reason));
}
// getPlayer().sendPacket(new PacketStoreItemChangeNotify(changedItems));
return
true
;
}
public
void
removeItems
(
List
<
GameItem
>
items
)
{
public
void
removeItems
(
List
<
GameItem
>
items
)
{
// TODO Bulk delete
// TODO Bulk delete
...
...
src/main/java/emu/grasscutter/game/managers/ChatManager.java
→
src/main/java/emu/grasscutter/game/managers/ChatManager
/ChatManager
.java
View file @
a8293102
package
emu.grasscutter.game.managers
;
package
emu.grasscutter.game.managers
.ChatManager
;
import
emu.grasscutter.command.CommandMap
;
import
emu.grasscutter.command.CommandMap
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.player.Player
;
...
@@ -10,7 +10,7 @@ import emu.grasscutter.server.packet.send.PacketPrivateChatNotify;
...
@@ -10,7 +10,7 @@ import emu.grasscutter.server.packet.send.PacketPrivateChatNotify;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.List
;
public
class
ChatManager
{
public
class
ChatManager
implements
ChatManagerHandler
{
static
final
List
<
Character
>
PREFIXES
=
Arrays
.
asList
(
'/'
,
'!'
);
static
final
List
<
Character
>
PREFIXES
=
Arrays
.
asList
(
'/'
,
'!'
);
private
final
GameServer
server
;
private
final
GameServer
server
;
...
...
Prev
1
…
4
5
6
7
8
9
10
11
12
…
21
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