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
30c7bb94
Commit
30c7bb94
authored
Jun 17, 2022
by
Melledy
Browse files
Merge branch 'dev-world-scripts' of
https://github.com/Grasscutters/Grasscutter
into development
parents
8e6aa50c
5a3e9bc3
Changes
79
Expand all
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/game/entity/EntityGadget.java
View file @
30c7bb94
package
emu.grasscutter.game.entity
;
import
java.util.Arrays
;
import
java.util.List
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.excels.GadgetData
;
import
emu.grasscutter.game.entity.gadget.*
;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.props.EntityType
;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.game.world.Scene
;
import
emu.grasscutter.game.world.World
;
import
emu.grasscutter.net.proto.ClientGadgetInfoOuterClass
;
import
emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo
;
import
emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair
;
import
emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo
;
...
...
@@ -23,15 +20,17 @@ import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo;
import
emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo
;
import
emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.net.proto.WorktopInfoOuterClass.WorktopInfo
;
import
emu.grasscutter.scripts.constants.EventType
;
import
emu.grasscutter.scripts.data.SceneGadget
;
import
emu.grasscutter.scripts.data.ScriptArgs
;
import
emu.grasscutter.server.packet.send.PacketGadgetStateNotify
;
import
emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify
;
import
emu.grasscutter.utils.Position
;
import
emu.grasscutter.utils.ProtoHelper
;
import
it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap
;
import
it.unimi.dsi.fastutil.ints.IntArrayList
;
import
it.unimi.dsi.fastutil.ints.IntList
;
import
it.unimi.dsi.fastutil.ints.IntOpenHashSet
;
import
it.unimi.dsi.fastutil.ints.IntSet
;
import
lombok.ToString
;
@ToString
(
callSuper
=
true
)
public
class
EntityGadget
extends
EntityBaseGadget
{
private
final
GadgetData
data
;
private
final
Position
pos
;
...
...
@@ -39,7 +38,9 @@ public class EntityGadget extends EntityBaseGadget {
private
int
gadgetId
;
private
int
state
;
private
IntSet
worktopOptions
;
private
int
pointType
;
private
GadgetContent
content
;
private
SceneGadget
metaGadget
;
public
EntityGadget
(
Scene
scene
,
int
gadgetId
,
Position
pos
)
{
super
(
scene
);
...
...
@@ -50,19 +51,22 @@ public class EntityGadget extends EntityBaseGadget {
this
.
rot
=
new
Position
();
}
public
EntityGadget
(
Scene
scene
,
int
gadgetId
,
Position
pos
,
GadgetContent
content
)
{
this
(
scene
,
gadgetId
,
pos
);
this
.
content
=
content
;
}
public
GadgetData
getGadgetData
()
{
return
data
;
}
@Override
public
Position
getPosition
()
{
// TODO Auto-generated method stub
return
this
.
pos
;
}
@Override
public
Position
getRotation
()
{
// TODO Auto-generated method stub
return
this
.
rot
;
}
...
...
@@ -81,34 +85,73 @@ public class EntityGadget extends EntityBaseGadget {
public
void
setState
(
int
state
)
{
this
.
state
=
state
;
}
public
void
updateState
(
int
state
){
this
.
setState
(
state
);
this
.
getScene
().
broadcastPacket
(
new
PacketGadgetStateNotify
(
this
,
state
));
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_GADGET_STATE_CHANGE
,
new
ScriptArgs
(
state
,
this
.
getConfigId
()));
}
public
IntSet
getWorktopOptions
()
{
return
worktopOptions
;
public
int
getPointType
()
{
return
pointType
;
}
public
void
addWorktopOptions
(
int
[]
options
)
{
if
(
this
.
worktopOptions
==
null
)
{
this
.
worktopOptions
=
new
IntOpenHashSet
();
}
Arrays
.
stream
(
options
).
forEach
(
this
.
worktopOptions
::
add
);
public
void
setPointType
(
int
pointType
)
{
this
.
pointType
=
pointType
;
}
public
void
removeWorktopOption
(
int
option
)
{
if
(
this
.
worktopOptions
==
null
)
{
public
GadgetContent
getContent
()
{
return
content
;
}
@Deprecated
// Dont use!
public
void
setContent
(
GadgetContent
content
)
{
this
.
content
=
this
.
content
==
null
?
content
:
this
.
content
;
}
public
SceneGadget
getMetaGadget
()
{
return
metaGadget
;
}
public
void
setMetaGadget
(
SceneGadget
metaGadget
)
{
this
.
metaGadget
=
metaGadget
;
}
// TODO refactor
public
void
buildContent
()
{
if
(
getContent
()
!=
null
||
getGadgetData
()
==
null
||
getGadgetData
().
getType
()
==
null
)
{
return
;
}
this
.
worktopOptions
.
remove
(
option
);
EntityType
type
=
getGadgetData
().
getType
();
GadgetContent
content
=
switch
(
type
)
{
case
GatherPoint
->
new
GadgetGatherPoint
(
this
);
case
Worktop
->
new
GadgetWorktop
(
this
);
case
RewardStatue
->
new
GadgetRewardStatue
(
this
);
case
Chest
->
new
GadgetChest
(
this
);
default
->
null
;
};
this
.
content
=
content
;
}
@Override
public
Int2FloatOpenHashMap
getFightProperties
()
{
// TODO Auto-generated method stub
return
null
;
}
@Override
public
void
onCreate
()
{
// Lua event
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_GADGET_CREATE
,
new
ScriptArgs
(
this
.
getConfigId
()));
}
@Override
public
void
onDeath
(
int
killerId
)
{
if
(
getScene
().
getChallenge
()
!=
null
){
getScene
().
getChallenge
().
onGadgetDeath
(
this
);
}
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_ANY_GADGET_DIE
,
new
ScriptArgs
(
this
.
getConfigId
()));
}
@Override
...
...
@@ -143,15 +186,16 @@ public class EntityGadget extends EntityBaseGadget {
.
setIsEnableInteract
(
true
)
.
setAuthorityPeerId
(
this
.
getScene
().
getWorld
().
getHostPeerId
());
if
(
this
.
getGadgetData
().
getType
()
==
EntityType
.
Worktop
&&
this
.
getWorktopOptions
()
!=
null
)
{
WorktopInfo
worktop
=
WorktopInfo
.
newBuilder
()
.
addAllOptionList
(
this
.
getWorktopOptions
())
.
build
();
gadgetInfo
.
setWorktop
(
worktop
);
if
(
this
.
getContent
()
!=
null
)
{
this
.
getContent
().
onBuildProto
(
gadgetInfo
);
}
entityInfo
.
setGadget
(
gadgetInfo
);
return
entityInfo
.
build
();
}
public
void
die
()
{
getScene
().
broadcastPacket
(
new
PacketLifeStateChangeNotify
(
this
,
LifeState
.
LIFE_DEAD
));
this
.
onDeath
(
0
);
}
}
src/main/java/emu/grasscutter/game/entity/EntityMonster.java
View file @
30c7bb94
...
...
@@ -4,13 +4,11 @@ import emu.grasscutter.data.GameData;
import
emu.grasscutter.data.common.PropGrowCurve
;
import
emu.grasscutter.data.excels.MonsterCurveData
;
import
emu.grasscutter.data.excels.MonsterData
;
import
emu.grasscutter.game.dungeons.DungeonChallenge
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.game.world.Scene
;
import
emu.grasscutter.game.world.World
;
import
emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo
;
import
emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair
;
import
emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo
;
...
...
@@ -25,6 +23,7 @@ import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo;
import
emu.grasscutter.net.proto.SceneMonsterInfoOuterClass.SceneMonsterInfo
;
import
emu.grasscutter.net.proto.SceneWeaponInfoOuterClass.SceneWeaponInfo
;
import
emu.grasscutter.scripts.constants.EventType
;
import
emu.grasscutter.scripts.data.ScriptArgs
;
import
emu.grasscutter.utils.Position
;
import
emu.grasscutter.utils.ProtoHelper
;
import
it.unimi.dsi.fastutil.ints.Int2FloatMap
;
...
...
@@ -111,6 +110,12 @@ public class EntityMonster extends GameEntity {
public
void
setPoseId
(
int
poseId
)
{
this
.
poseId
=
poseId
;
}
@Override
public
void
onCreate
()
{
// Lua event
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_ANY_MONSTER_LIVE
,
new
ScriptArgs
(
this
.
getConfigId
()));
}
@Override
public
void
damage
(
float
amount
,
int
killerId
)
{
...
...
@@ -135,8 +140,8 @@ public class EntityMonster extends GameEntity {
this
.
getScene
().
getDeadSpawnedEntities
().
add
(
getSpawnEntry
());
}
// first set the challenge data
if
(
getScene
().
getChallenge
()
!=
null
&&
getScene
().
getChallenge
().
getGroup
().
id
==
this
.
getGroupId
()
)
{
getScene
().
getChallenge
().
onMonsterD
i
e
(
this
);
if
(
getScene
().
getChallenge
()
!=
null
)
{
getScene
().
getChallenge
().
onMonsterDe
ath
(
this
);
}
if
(
getScene
().
getScriptManager
().
isInit
()
&&
this
.
getGroupId
()
>
0
)
{
if
(
getScene
().
getScriptManager
().
getScriptMonsterSpawnService
()
!=
null
){
...
...
@@ -144,7 +149,9 @@ public class EntityMonster extends GameEntity {
}
// prevent spawn monster after success
if
(
getScene
().
getChallenge
()
!=
null
&&
getScene
().
getChallenge
().
inProgress
()){
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_ANY_MONSTER_DIE
,
null
);
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_ANY_MONSTER_DIE
,
new
ScriptArgs
().
setParam1
(
this
.
getConfigId
()));
}
else
if
(
getScene
().
getChallenge
()
==
null
){
getScene
().
getScriptManager
().
callEvent
(
EventType
.
EVENT_ANY_MONSTER_DIE
,
new
ScriptArgs
().
setParam1
(
this
.
getConfigId
()));
}
}
}
...
...
src/main/java/emu/grasscutter/game/entity/EntityNPC.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.game.entity
;
import
emu.grasscutter.game.props.EntityIdType
;
import
emu.grasscutter.game.world.Scene
;
import
emu.grasscutter.net.proto.*
;
import
emu.grasscutter.scripts.data.SceneNPC
;
import
emu.grasscutter.utils.Position
;
import
it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap
;
public
class
EntityNPC
extends
GameEntity
{
private
final
Position
position
;
private
final
Position
rotation
;
private
final
SceneNPC
metaNpc
;
private
final
int
suiteId
;
public
EntityNPC
(
Scene
scene
,
SceneNPC
metaNPC
,
int
blockId
,
int
suiteId
)
{
super
(
scene
);
this
.
id
=
getScene
().
getWorld
().
getNextEntityId
(
EntityIdType
.
NPC
);
setConfigId
(
metaNPC
.
config_id
);
setGroupId
(
metaNPC
.
group
.
id
);
setBlockId
(
blockId
);
this
.
suiteId
=
suiteId
;
this
.
position
=
metaNPC
.
pos
.
clone
();
this
.
rotation
=
metaNPC
.
rot
.
clone
();
this
.
metaNpc
=
metaNPC
;
}
@Override
public
Int2FloatOpenHashMap
getFightProperties
()
{
return
null
;
}
@Override
public
Position
getPosition
()
{
return
position
;
}
@Override
public
Position
getRotation
()
{
return
rotation
;
}
public
int
getSuiteId
()
{
return
suiteId
;
}
@Override
public
SceneEntityInfoOuterClass
.
SceneEntityInfo
toProto
()
{
EntityAuthorityInfoOuterClass
.
EntityAuthorityInfo
authority
=
EntityAuthorityInfoOuterClass
.
EntityAuthorityInfo
.
newBuilder
()
.
setAbilityInfo
(
AbilitySyncStateInfoOuterClass
.
AbilitySyncStateInfo
.
newBuilder
())
.
setRendererChangedInfo
(
EntityRendererChangedInfoOuterClass
.
EntityRendererChangedInfo
.
newBuilder
())
.
setAiInfo
(
SceneEntityAiInfoOuterClass
.
SceneEntityAiInfo
.
newBuilder
()
.
setIsAiOpen
(
true
)
.
setBornPos
(
getPosition
().
toProto
()))
.
setBornPos
(
getPosition
().
toProto
())
.
build
();
SceneEntityInfoOuterClass
.
SceneEntityInfo
.
Builder
entityInfo
=
SceneEntityInfoOuterClass
.
SceneEntityInfo
.
newBuilder
()
.
setEntityId
(
getId
())
.
setEntityType
(
ProtEntityTypeOuterClass
.
ProtEntityType
.
PROT_ENTITY_NPC
)
.
setMotionInfo
(
MotionInfoOuterClass
.
MotionInfo
.
newBuilder
()
.
setPos
(
getPosition
().
toProto
())
.
setRot
(
getRotation
().
toProto
())
.
setSpeed
(
VectorOuterClass
.
Vector
.
newBuilder
()))
.
addAnimatorParaList
(
AnimatorParameterValueInfoPairOuterClass
.
AnimatorParameterValueInfoPair
.
newBuilder
())
.
setEntityClientData
(
EntityClientDataOuterClass
.
EntityClientData
.
newBuilder
())
.
setEntityAuthorityInfo
(
authority
)
.
setLifeState
(
1
);
entityInfo
.
setNpc
(
SceneNpcInfoOuterClass
.
SceneNpcInfo
.
newBuilder
()
.
setNpcId
(
metaNpc
.
npc_id
)
.
setBlockId
(
getBlockId
())
.
build
());
return
entityInfo
.
build
();
}
}
src/main/java/emu/grasscutter/game/entity/GameEntity.java
View file @
30c7bb94
...
...
@@ -107,10 +107,6 @@ public abstract class GameEntity {
public
void
setLastMoveReliableSeq
(
int
lastMoveReliableSeq
)
{
this
.
lastMoveReliableSeq
=
lastMoveReliableSeq
;
}
public
abstract
SceneEntityInfo
toProto
();
public
abstract
void
onDeath
(
int
killerId
);
public
void
setFightProperty
(
FightProperty
prop
,
float
value
)
{
this
.
getFightProperties
().
put
(
prop
.
getId
(),
value
);
...
...
@@ -219,4 +215,21 @@ public abstract class GameEntity {
getScene
().
killEntity
(
this
,
killerId
);
}
}
/**
* Called when this entity is added to the world
*/
public
void
onCreate
()
{
}
/**
* Called when this entity dies
* @param killerId Entity id of the entity that killed this entity
*/
public
void
onDeath
(
int
killerId
)
{
}
public
abstract
SceneEntityInfo
toProto
();
}
src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.game.entity.gadget
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.entity.EntityGadget
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.proto.BossChestInfoOuterClass.BossChestInfo
;
import
emu.grasscutter.net.proto.InterOpTypeOuterClass
;
import
emu.grasscutter.net.proto.InteractTypeOuterClass
;
import
emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType
;
import
emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo
;
import
emu.grasscutter.scripts.constants.ScriptGadgetState
;
import
emu.grasscutter.server.packet.send.PacketGadgetInteractRsp
;
import
static
emu
.
grasscutter
.
net
.
proto
.
InterOpTypeOuterClass
.
InterOpType
.
INTER_OP_START
;
public
class
GadgetChest
extends
GadgetContent
{
public
GadgetChest
(
EntityGadget
gadget
)
{
super
(
gadget
);
}
public
boolean
onInteract
(
Player
player
,
InterOpTypeOuterClass
.
InterOpType
opType
)
{
var
chestInteractHandlerMap
=
getGadget
().
getScene
().
getWorld
().
getServer
().
getWorldDataManager
().
getChestInteractHandlerMap
();
var
handler
=
chestInteractHandlerMap
.
get
(
getGadget
().
getGadgetData
().
getJsonName
());
if
(
handler
==
null
){
Grasscutter
.
getLogger
().
warn
(
"Could not found the handler of this type of Chests {}"
,
getGadget
().
getGadgetData
().
getJsonName
());
return
false
;
}
if
(
opType
==
INTER_OP_START
&&
handler
.
isTwoStep
()){
player
.
sendPacket
(
new
PacketGadgetInteractRsp
(
getGadget
(),
InteractType
.
INTERACT_OPEN_CHEST
,
INTER_OP_START
));
return
false
;
}
else
{
var
success
=
handler
.
onInteract
(
this
,
player
);
if
(!
success
){
return
false
;
}
getGadget
().
updateState
(
ScriptGadgetState
.
ChestOpened
);
player
.
sendPacket
(
new
PacketGadgetInteractRsp
(
this
.
getGadget
(),
InteractTypeOuterClass
.
InteractType
.
INTERACT_OPEN_CHEST
));
// let the chest disappear
getGadget
().
die
();
return
true
;
}
}
public
void
onBuildProto
(
SceneGadgetInfo
.
Builder
gadgetInfo
)
{
if
(
getGadget
().
getMetaGadget
()
==
null
){
return
;
}
var
bossChest
=
getGadget
().
getMetaGadget
().
boss_chest
;
if
(
bossChest
!=
null
){
var
players
=
getGadget
().
getScene
().
getPlayers
().
stream
().
map
(
Player:
:
getUid
).
toList
();
gadgetInfo
.
setBossChest
(
BossChestInfo
.
newBuilder
()
.
setMonsterConfigId
(
bossChest
.
monster_config_id
)
.
setResin
(
bossChest
.
resin
)
.
addAllQualifyUidList
(
players
)
.
addAllRemainUidList
(
players
)
.
build
());
}
}
}
src/main/java/emu/grasscutter/game/entity/gadget/GadgetContent.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.game.entity.gadget
;
import
emu.grasscutter.game.entity.EntityGadget
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.proto.InterOpTypeOuterClass
;
import
emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo
;
public
abstract
class
GadgetContent
{
private
final
EntityGadget
gadget
;
public
GadgetContent
(
EntityGadget
gadget
)
{
this
.
gadget
=
gadget
;
}
public
EntityGadget
getGadget
()
{
return
gadget
;
}
public
abstract
boolean
onInteract
(
Player
player
,
InterOpTypeOuterClass
.
InterOpType
opType
);
public
abstract
void
onBuildProto
(
SceneGadgetInfo
.
Builder
gadgetInfo
);
}
src/main/java/emu/grasscutter/game/entity/gadget/GadgetGatherPoint.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.game.entity.gadget
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.def.GatherData
;
import
emu.grasscutter.game.entity.EntityGadget
;
import
emu.grasscutter.game.inventory.GameItem
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.ActionReason
;
import
emu.grasscutter.net.proto.GatherGadgetInfoOuterClass.GatherGadgetInfo
;
import
emu.grasscutter.net.proto.InterOpTypeOuterClass
;
import
emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo
;
public
class
GadgetGatherPoint
extends
GadgetContent
{
private
GatherData
gatherData
;
public
GadgetGatherPoint
(
EntityGadget
gadget
)
{
super
(
gadget
);
this
.
gatherData
=
GameData
.
getGatherDataMap
().
get
(
gadget
.
getPointType
());
}
public
GatherData
getGatherData
()
{
return
gatherData
;
}
public
int
getItemId
()
{
return
getGatherData
().
getItemId
();
}
public
boolean
onInteract
(
Player
player
,
InterOpTypeOuterClass
.
InterOpType
opType
)
{
GameItem
item
=
new
GameItem
(
gatherData
.
getItemId
(),
1
);
player
.
getInventory
().
addItem
(
item
,
ActionReason
.
Gather
);
return
true
;
}
public
void
onBuildProto
(
SceneGadgetInfo
.
Builder
gadgetInfo
)
{
GatherGadgetInfo
gatherGadgetInfo
=
GatherGadgetInfo
.
newBuilder
()
.
setItemId
(
this
.
getItemId
())
.
setIsForbidGuest
(
this
.
getGatherData
().
isForbidGuest
())
.
build
();
gadgetInfo
.
setGatherGadget
(
gatherGadgetInfo
);
}
}
src/main/java/emu/grasscutter/game/entity/gadget/GadgetRewardStatue.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.game.entity.gadget
;
import
emu.grasscutter.game.dungeons.challenge.DungeonChallenge
;
import
emu.grasscutter.game.entity.EntityGadget
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.proto.InterOpTypeOuterClass
;
import
emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType
;
import
emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo
;
import
emu.grasscutter.server.packet.send.PacketGadgetInteractRsp
;
public
class
GadgetRewardStatue
extends
GadgetContent
{
public
GadgetRewardStatue
(
EntityGadget
gadget
)
{
super
(
gadget
);
}
public
boolean
onInteract
(
Player
player
,
InterOpTypeOuterClass
.
InterOpType
opType
)
{
if
(
player
.
getScene
().
getChallenge
()
!=
null
&&
player
.
getScene
().
getChallenge
()
instanceof
DungeonChallenge
dungeonChallenge
)
{
dungeonChallenge
.
getStatueDrops
(
player
);
}
player
.
sendPacket
(
new
PacketGadgetInteractRsp
(
getGadget
(),
InteractType
.
INTERACT_OPEN_STATUE
));
return
false
;
}
public
void
onBuildProto
(
SceneGadgetInfo
.
Builder
gadgetInfo
)
{
}
}
src/main/java/emu/grasscutter/game/entity/gadget/GadgetWorktop.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.game.entity.gadget
;
import
java.util.Arrays
;
import
emu.grasscutter.game.entity.EntityGadget
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.net.proto.InterOpTypeOuterClass
;
import
emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo
;
import
emu.grasscutter.net.proto.WorktopInfoOuterClass.WorktopInfo
;
import
it.unimi.dsi.fastutil.ints.IntOpenHashSet
;
import
it.unimi.dsi.fastutil.ints.IntSet
;
public
class
GadgetWorktop
extends
GadgetContent
{
private
IntSet
worktopOptions
;
public
GadgetWorktop
(
EntityGadget
gadget
)
{
super
(
gadget
);
}
public
IntSet
getWorktopOptions
()
{
return
worktopOptions
;
}
public
void
addWorktopOptions
(
int
[]
options
)
{
if
(
this
.
worktopOptions
==
null
)
{
this
.
worktopOptions
=
new
IntOpenHashSet
();
}
Arrays
.
stream
(
options
).
forEach
(
this
.
worktopOptions
::
add
);
}
public
void
removeWorktopOption
(
int
option
)
{
if
(
this
.
worktopOptions
==
null
)
{
return
;
}
this
.
worktopOptions
.
remove
(
option
);
}
public
boolean
onInteract
(
Player
player
,
InterOpTypeOuterClass
.
InterOpType
opType
)
{
return
false
;
}
public
void
onBuildProto
(
SceneGadgetInfo
.
Builder
gadgetInfo
)
{
if
(
this
.
worktopOptions
==
null
)
{
return
;
}
WorktopInfo
worktop
=
WorktopInfo
.
newBuilder
()
.
addAllOptionList
(
this
.
getWorktopOptions
())
.
build
();
gadgetInfo
.
setWorktop
(
worktop
);
}
}
src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.game.entity.gadget.chest
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.common.ItemParamData
;
import
emu.grasscutter.game.entity.gadget.GadgetChest
;
import
emu.grasscutter.game.inventory.GameItem
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.props.ActionReason
;
import
emu.grasscutter.server.packet.send.PacketGadgetAutoPickDropInfoNotify
;
import
java.util.ArrayList
;
import
java.util.List
;
public
class
BossChestInteractHandler
implements
ChestInteractHandler
{
@Override
public
boolean
isTwoStep
()
{
return
true
;
}
@Override
public
boolean
onInteract
(
GadgetChest
chest
,
Player
player
)
{
var
worldDataManager
=
chest
.
getGadget
().
getScene
().
getWorld
().
getServer
().
getWorldDataManager
();
var
monster
=
chest
.
getGadget
().
getMetaGadget
().
group
.
monsters
.
get
(
chest
.
getGadget
().
getMetaGadget
().
boss_chest
.
monster_config_id
);
var
reward
=
worldDataManager
.
getRewardByBossId
(
monster
.
monster_id
);
if
(
reward
==
null
){
Grasscutter
.
getLogger
().
warn
(
"Could not found the reward of boss monster {}"
,
monster
.
monster_id
);
return
false
;
}
List
<
GameItem
>
rewards
=
new
ArrayList
<>();
for
(
ItemParamData
param
:
reward
.
getPreviewItems
())
{
rewards
.
add
(
new
GameItem
(
param
.
getId
(),
Math
.
max
(
param
.
getCount
(),
1
)));
}
player
.
getInventory
().
addItems
(
rewards
,
ActionReason
.
OpenWorldBossChest
);
player
.
sendPacket
(
new
PacketGadgetAutoPickDropInfoNotify
(
rewards
));
return
true
;
}
}
src/main/java/emu/grasscutter/game/entity/gadget/chest/ChestInteractHandler.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.game.entity.gadget.chest
;
import
emu.grasscutter.game.entity.gadget.GadgetChest
;
import
emu.grasscutter.game.player.Player
;
public
interface
ChestInteractHandler
{
boolean
isTwoStep
();
boolean
onInteract
(
GadgetChest
chest
,
Player
player
);
}
src/main/java/emu/grasscutter/game/entity/gadget/chest/NormalChestInteractHandler.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.game.entity.gadget.chest
;
import
emu.grasscutter.game.entity.gadget.GadgetChest
;
import
emu.grasscutter.game.player.Player
;
import
emu.grasscutter.game.world.ChestReward
;
import
java.util.Random
;
public
class
NormalChestInteractHandler
implements
ChestInteractHandler
{
private
final
ChestReward
chestReward
;
public
NormalChestInteractHandler
(
ChestReward
rewardData
){
this
.
chestReward
=
rewardData
;
}
@Override
public
boolean
isTwoStep
()
{
return
false
;
}
@Override
public
boolean
onInteract
(
GadgetChest
chest
,
Player
player
)
{
player
.
earnExp
(
chestReward
.
getAdvExp
());
player
.
getInventory
().
addItem
(
201
,
chestReward
.
getResin
());
var
mora
=
chestReward
.
getMora
()
*
(
1
+
(
player
.
getWorldLevel
()
-
1
)
*
0.5
);
player
.
getInventory
().
addItem
(
202
,
(
int
)
mora
);
for
(
int
i
=
0
;
i
<
chestReward
.
getContent
().
size
();
i
++){
chest
.
getGadget
().
getScene
().
addItemEntity
(
chestReward
.
getContent
().
get
(
i
).
getItemId
(),
chestReward
.
getContent
().
get
(
i
).
getCount
(),
chest
.
getGadget
());
}
var
random
=
new
Random
(
System
.
currentTimeMillis
());
for
(
int
i
=
0
;
i
<
chestReward
.
getRandomCount
();
i
++){
var
index
=
random
.
nextInt
(
chestReward
.
getRandomContent
().
size
());
var
item
=
chestReward
.
getRandomContent
().
get
(
index
);
chest
.
getGadget
().
getScene
().
addItemEntity
(
item
.
getItemId
(),
item
.
getCount
(),
chest
.
getGadget
());
}
return
true
;
}
}
src/main/java/emu/grasscutter/game/player/Player.java
View file @
30c7bb94
...
...
@@ -37,7 +37,6 @@ import emu.grasscutter.game.managers.mapmark.*;
import
emu.grasscutter.game.managers.stamina.StaminaManager
;
import
emu.grasscutter.game.managers.SotSManager
;
import
emu.grasscutter.game.props.ActionReason
;
import
emu.grasscutter.game.props.EntityType
;
import
emu.grasscutter.game.props.PlayerProperty
;
import
emu.grasscutter.game.props.SceneType
;
import
emu.grasscutter.game.quest.QuestManager
;
...
...
@@ -988,7 +987,8 @@ public class Player {
return
this
.
getMailHandler
().
replaceMailByIndex
(
index
,
message
);
}
public
void
interactWith
(
int
gadgetEntityId
,
GadgetInteractReq
request
)
{
public
void
interactWith
(
int
gadgetEntityId
,
InterOpTypeOuterClass
.
InterOpType
opType
)
{
GameEntity
entity
=
getScene
().
getEntityById
(
gadgetEntityId
);
if
(
entity
==
null
)
{
return
;
...
...
@@ -1016,11 +1016,15 @@ public class Player {
}
}
}
else
if
(
entity
instanceof
EntityGadget
gadget
)
{
if
(
gadget
.
getGadgetData
().
getType
()
==
EntityType
.
RewardStatue
)
{
if
(
scene
.
getChallenge
()
!=
null
)
{
scene
.
getChallenge
().
getStatueDrops
(
this
,
request
);
}
this
.
sendPacket
(
new
PacketGadgetInteractRsp
(
gadget
,
InteractType
.
INTERACT_TYPE_OPEN_STATUE
));
if
(
gadget
.
getContent
()
==
null
)
{
return
;
}
boolean
shouldDelete
=
gadget
.
getContent
().
onInteract
(
this
,
opType
);
if
(
shouldDelete
)
{
entity
.
getScene
().
removeEntity
(
entity
);
}
}
else
if
(
entity
instanceof
EntityMonster
monster
)
{
insectCaptureManager
.
arrestSmallCreature
(
monster
);
...
...
src/main/java/emu/grasscutter/game/world/ChestReward.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.game.world
;
import
emu.grasscutter.game.inventory.ItemDef
;
import
lombok.AccessLevel
;
import
lombok.Data
;
import
lombok.experimental.FieldDefaults
;
import
java.util.List
;
@Data
@FieldDefaults
(
level
=
AccessLevel
.
PRIVATE
)
public
class
ChestReward
{
List
<
String
>
objNames
;
int
advExp
;
int
resin
;
int
mora
;
int
sigil
;
List
<
ItemDef
>
content
;
int
randomCount
;
List
<
ItemDef
>
randomContent
;
}
src/main/java/emu/grasscutter/game/world/Scene.java
View file @
30c7bb94
package
emu.grasscutter.game.world
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameDepot
;
import
emu.grasscutter.data.excels.*
;
import
emu.grasscutter.game.dungeons.DungeonChallenge
;
import
emu.grasscutter.game.dungeons.DungeonSettleListener
;
import
emu.grasscutter.game.entity.*
;
import
emu.grasscutter.game.player.Player
;
...
...
@@ -13,24 +13,24 @@ import emu.grasscutter.game.props.FightProperty;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.game.props.SceneType
;
import
emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry
;
import
emu.grasscutter.game.dungeons.challenge.WorldChallenge
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult
;
import
emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType
;
import
emu.grasscutter.scripts.SceneIndexManager
;
import
emu.grasscutter.scripts.SceneScriptManager
;
import
emu.grasscutter.scripts.data.SceneBlock
;
import
emu.grasscutter.scripts.data.SceneGadget
;
import
emu.grasscutter.scripts.data.SceneGroup
;
import
emu.grasscutter.server.packet.send.PacketAvatarSkillInfoNotify
;
import
emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify
;
import
emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify
;
import
emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify
;
import
emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify
;
import
emu.grasscutter.server.packet.send.PacketSceneEntityDisappearNotify
;
import
emu.grasscutter.server.packet.send.*
;
import
emu.grasscutter.utils.Position
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMaps
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
org.danilopianini.util.SpatialIndex
;
import
java.util.*
;
import
java.util.stream.Collectors
;
public
class
Scene
{
private
final
World
world
;
...
...
@@ -49,12 +49,11 @@ public class Scene {
private
int
weather
;
private
SceneScriptManager
scriptManager
;
private
Dungeon
Challenge
challenge
;
private
World
Challenge
challenge
;
private
List
<
DungeonSettleListener
>
dungeonSettleListeners
;
private
DungeonData
dungeonData
;
private
int
prevScene
;
// Id of the previous scene
private
int
prevScenePoint
;
public
Scene
(
World
world
,
SceneData
sceneData
)
{
this
.
world
=
world
;
this
.
sceneData
=
sceneData
;
...
...
@@ -198,11 +197,11 @@ public class Scene {
this
.
dungeonData
=
dungeonData
;
}
public
Dungeon
Challenge
getChallenge
()
{
public
World
Challenge
getChallenge
()
{
return
challenge
;
}
public
void
setChallenge
(
Dungeon
Challenge
challenge
)
{
public
void
setChallenge
(
World
Challenge
challenge
)
{
this
.
challenge
=
challenge
;
}
...
...
@@ -310,6 +309,7 @@ public class Scene {
private
void
addEntityDirectly
(
GameEntity
entity
)
{
getEntities
().
put
(
entity
.
getId
(),
entity
);
entity
.
onCreate
();
// Call entity create event
}
public
synchronized
void
addEntity
(
GameEntity
entity
)
{
...
...
@@ -320,14 +320,21 @@ public class Scene {
public
synchronized
void
addEntityToSingleClient
(
Player
player
,
GameEntity
entity
)
{
this
.
addEntityDirectly
(
entity
);
player
.
sendPacket
(
new
PacketSceneEntityAppearNotify
(
entity
));
}
public
void
addEntities
(
Collection
<?
extends
GameEntity
>
entities
){
addEntities
(
entities
,
VisionType
.
VISION_TYPE_BORN
);
}
public
synchronized
void
addEntities
(
Collection
<
GameEntity
>
entities
)
{
public
synchronized
void
addEntities
(
Collection
<?
extends
GameEntity
>
entities
,
VisionType
visionType
)
{
if
(
entities
==
null
||
entities
.
isEmpty
()){
return
;
}
for
(
GameEntity
entity
:
entities
)
{
this
.
addEntityDirectly
(
entity
);
}
this
.
broadcastPacket
(
new
PacketSceneEntityAppearNotify
(
entities
,
V
isionType
.
VISION_TYPE_BORN
));
this
.
broadcastPacket
(
new
PacketSceneEntityAppearNotify
(
entities
,
v
isionType
));
}
private
GameEntity
removeEntityDirectly
(
GameEntity
entity
)
{
...
...
@@ -344,14 +351,21 @@ public class Scene {
this
.
broadcastPacket
(
new
PacketSceneEntityDisappearNotify
(
removed
,
visionType
));
}
}
public
synchronized
void
removeEntities
(
List
<
GameEntity
>
entity
,
VisionType
visionType
)
{
var
toRemove
=
entity
.
stream
()
.
map
(
this
::
removeEntityDirectly
)
.
toList
();
if
(
toRemove
.
size
()
>
0
)
{
this
.
broadcastPacket
(
new
PacketSceneEntityDisappearNotify
(
toRemove
,
visionType
));
}
}
public
synchronized
void
replaceEntity
(
EntityAvatar
oldEntity
,
EntityAvatar
newEntity
)
{
this
.
removeEntityDirectly
(
oldEntity
);
this
.
addEntityDirectly
(
newEntity
);
this
.
broadcastPacket
(
new
PacketSceneEntityDisappearNotify
(
oldEntity
,
VisionType
.
VISION_TYPE_REPLACE
));
this
.
broadcastPacket
(
new
PacketSceneEntityAppearNotify
(
newEntity
,
VisionType
.
VISION_TYPE_REPLACE
,
oldEntity
.
getId
()));
}
public
void
showOtherEntities
(
Player
player
)
{
List
<
GameEntity
>
entities
=
new
LinkedList
<>();
GameEntity
currentEntity
=
player
.
getTeamManager
().
getCurrentAvatarEntity
();
...
...
@@ -362,7 +376,7 @@ public class Scene {
}
entities
.
add
(
entity
);
}
player
.
sendPacket
(
new
PacketSceneEntityAppearNotify
(
entities
,
VisionType
.
VISION_TYPE_MEET
));
}
...
...
@@ -412,7 +426,7 @@ public class Scene {
// Death event
target
.
onDeath
(
attackerId
);
}
public
void
onTick
()
{
// disable script for home
if
(
this
.
getSceneType
()
==
SceneType
.
SCENE_HOME_WORLD
||
this
.
getSceneType
()
==
SceneType
.
SCENE_HOME_ROOM
){
...
...
@@ -424,9 +438,12 @@ public class Scene {
// TEMPORARY
this
.
checkSpawns
();
}
// Triggers
this
.
getScriptManager
().
onTick
();
this
.
scriptManager
.
checkRegions
();
if
(
challenge
!=
null
){
challenge
.
onCheckTimeOut
();
}
}
// TODO - Test
...
...
@@ -502,83 +519,152 @@ public class Scene {
this
.
broadcastPacket
(
new
PacketSceneEntityDisappearNotify
(
toRemove
,
VisionType
.
VISION_TYPE_REMOVE
));
}
}
public
List
<
SceneBlock
>
getPlayerActiveBlocks
(
Player
player
){
// consider the borders' entities of blocks, so we check if contains by index
return
SceneIndexManager
.
queryNeighbors
(
getScriptManager
().
getBlocksIndex
(),
player
.
getPos
().
toXZDoubleArray
(),
Grasscutter
.
getConfig
().
server
.
game
.
loadEntitiesForPlayerRange
);
}
public
void
checkBlocks
()
{
Set
<
SceneBlock
>
visible
=
new
HashSet
<>();
for
(
Player
player
:
this
.
getPlayers
())
{
for
(
SceneBlock
block
:
getScriptManager
().
getBlocks
())
{
if
(!
block
.
contains
(
player
.
getPos
()))
{
continue
;
}
visible
.
add
(
block
);
}
var
blocks
=
getPlayerActiveBlocks
(
player
);
visible
.
addAll
(
blocks
);
}
Iterator
<
SceneBlock
>
it
=
this
.
getLoadedBlocks
().
iterator
();
while
(
it
.
hasNext
())
{
SceneBlock
block
=
it
.
next
();
if
(!
visible
.
contains
(
block
))
{
it
.
remove
();
onUnloadBlock
(
block
);
}
}
for
(
SceneBlock
block
:
visible
)
{
for
(
var
block
:
visible
){
if
(!
this
.
getLoadedBlocks
().
contains
(
block
))
{
this
.
onLoadBlock
(
block
);
this
.
onLoadBlock
(
block
,
this
.
getPlayers
()
);
this
.
getLoadedBlocks
().
add
(
block
);
}
else
{
// dynamic load the groups for players in a loaded block
var
toLoad
=
this
.
getPlayers
().
stream
()
.
filter
(
p
->
block
.
contains
(
p
.
getPos
()))
.
map
(
p
->
playerMeetGroups
(
p
,
block
))
.
flatMap
(
Collection:
:
stream
)
.
toList
();
onLoadGroup
(
toLoad
);
}
for
(
Player
player
:
this
.
getPlayers
())
{
getScriptManager
().
meetEntities
(
loadNpcForPlayer
(
player
,
block
));
}
}
}
// TODO optimize
public
void
onLoadBlock
(
SceneBlock
block
)
{
for
(
SceneGroup
group
:
block
.
groups
)
{
public
List
<
SceneGroup
>
playerMeetGroups
(
Player
player
,
SceneBlock
block
){
List
<
SceneGroup
>
sceneGroups
=
SceneIndexManager
.
queryNeighbors
(
block
.
sceneGroupIndex
,
player
.
getPos
().
toDoubleArray
(),
Grasscutter
.
getConfig
().
server
.
game
.
loadEntitiesForPlayerRange
);
List
<
SceneGroup
>
groups
=
sceneGroups
.
stream
()
.
filter
(
group
->
!
scriptManager
.
getLoadedGroupSetPerBlock
().
get
(
block
.
id
).
contains
(
group
))
.
peek
(
group
->
scriptManager
.
getLoadedGroupSetPerBlock
().
get
(
block
.
id
).
add
(
group
))
.
toList
();
if
(
groups
.
size
()
==
0
)
{
return
List
.
of
();
}
return
groups
;
}
public
void
onLoadBlock
(
SceneBlock
block
,
List
<
Player
>
players
)
{
this
.
getScriptManager
().
loadBlockFromScript
(
block
);
scriptManager
.
getLoadedGroupSetPerBlock
().
put
(
block
.
id
,
new
HashSet
<>());
// the groups form here is not added in current scene
var
groups
=
players
.
stream
()
.
filter
(
player
->
block
.
contains
(
player
.
getPos
()))
.
map
(
p
->
playerMeetGroups
(
p
,
block
))
.
flatMap
(
Collection:
:
stream
)
.
toList
();
onLoadGroup
(
groups
);
Grasscutter
.
getLogger
().
info
(
"Scene {} Block {} loaded."
,
this
.
getId
(),
block
.
id
);
}
public
void
onLoadGroup
(
List
<
SceneGroup
>
groups
){
if
(
groups
==
null
||
groups
.
isEmpty
()){
return
;
}
for
(
SceneGroup
group
:
groups
)
{
// We load the script files for the groups here
if
(!
group
.
isLoaded
())
{
this
.
getScriptManager
().
loadGroupFromScript
(
group
);
}
group
.
triggers
.
forEach
(
getScriptManager
()::
registerTrigger
);
group
.
regions
.
forEach
(
getScriptManager
()::
registerRegion
);
this
.
getScriptManager
().
loadGroupFromScript
(
group
);
}
// Spawn gadgets AFTER triggers are added
// TODO
for
(
SceneGroup
group
:
block
.
groups
)
{
var
entities
=
new
ArrayList
<
GameEntity
>();
for
(
SceneGroup
group
:
groups
)
{
if
(
group
.
init_config
==
null
)
{
continue
;
}
int
suite
=
group
.
init_config
.
suite
;
// Load garbages
List
<
SceneGadget
>
garbageGadgets
=
group
.
getGarbageGadgets
();
if
(
suite
==
0
)
{
if
(
garbageGadgets
!=
null
)
{
entities
.
addAll
(
garbageGadgets
.
stream
().
map
(
g
->
scriptManager
.
createGadget
(
group
.
id
,
group
.
block_id
,
g
))
.
filter
(
Objects:
:
nonNull
)
.
toList
());
}
// Load suites
int
suite
=
group
.
init_config
.
suite
;
if
(
suite
==
0
||
group
.
suites
==
null
||
group
.
suites
.
size
()
==
0
)
{
continue
;
}
do
{
this
.
getScriptManager
().
spawnGadgetsInGroup
(
group
,
suite
);
suite
++;
}
while
(
suite
<
group
.
init_config
.
end_suite
);
// just load the 'init' suite, avoid spawn the suite added by AddExtraGroupSuite etc.
var
suiteData
=
group
.
getSuiteByIndex
(
suite
);
suiteData
.
sceneTriggers
.
forEach
(
getScriptManager
()::
registerTrigger
);
entities
.
addAll
(
suiteData
.
sceneGadgets
.
stream
()
.
map
(
g
->
scriptManager
.
createGadget
(
group
.
id
,
group
.
block_id
,
g
))
.
filter
(
Objects:
:
nonNull
)
.
toList
());
entities
.
addAll
(
suiteData
.
sceneMonsters
.
stream
()
.
map
(
mob
->
scriptManager
.
createMonster
(
group
.
id
,
group
.
block_id
,
mob
))
.
filter
(
Objects:
:
nonNull
)
.
toList
());
}
scriptManager
.
meetEntities
(
entities
);
//scriptManager.callEvent(EventType.EVENT_GROUP_LOAD, null);
//groups.forEach(g -> scriptManager.callEvent(EventType.EVENT_GROUP_LOAD, null));
Grasscutter
.
getLogger
().
info
(
"Scene {} loaded {} group(s)"
,
this
.
getId
(),
groups
.
size
());
}
public
void
onUnloadBlock
(
SceneBlock
block
)
{
List
<
GameEntity
>
toRemove
=
this
.
getEntities
().
values
().
stream
().
filter
(
e
->
e
.
getBlockId
()
==
block
.
id
).
toList
();
List
<
GameEntity
>
toRemove
=
this
.
getEntities
().
values
().
stream
()
.
filter
(
e
->
e
.
getBlockId
()
==
block
.
id
).
toList
();
if
(
toRemove
.
size
()
>
0
)
{
toRemove
.
stream
().
forEach
(
this
::
removeEntityDirectly
);
toRemove
.
forEach
(
this
::
removeEntityDirectly
);
this
.
broadcastPacket
(
new
PacketSceneEntityDisappearNotify
(
toRemove
,
VisionType
.
VISION_TYPE_REMOVE
));
}
for
(
SceneGroup
group
:
block
.
groups
)
{
group
.
triggers
.
forEach
(
getScriptManager
()::
deregisterTrigger
);
group
.
regions
.
forEach
(
getScriptManager
()::
deregisterRegion
);
for
(
SceneGroup
group
:
block
.
groups
.
values
())
{
if
(
group
.
triggers
!=
null
){
group
.
triggers
.
values
().
forEach
(
getScriptManager
()::
deregisterTrigger
);
}
if
(
group
.
regions
!=
null
){
group
.
regions
.
forEach
(
getScriptManager
()::
deregisterRegion
);
}
}
scriptManager
.
getLoadedGroupSetPerBlock
().
remove
(
block
.
id
);
Grasscutter
.
getLogger
().
info
(
"Scene {} Block {} is unloaded."
,
this
.
getId
(),
block
.
id
);
}
// Gadgets
...
...
@@ -643,4 +729,65 @@ public class Scene {
player
.
getSession
().
send
(
packet
);
}
}
public
void
addItemEntity
(
int
itemId
,
int
amount
,
GameEntity
bornForm
){
ItemData
itemData
=
GameData
.
getItemDataMap
().
get
(
itemId
);
if
(
itemData
==
null
)
{
return
;
}
if
(
itemData
.
isEquip
())
{
float
range
=
(
3
f
+
(.
1
f
*
amount
));
for
(
int
i
=
0
;
i
<
amount
;
i
++)
{
Position
pos
=
bornForm
.
getPosition
().
clone
().
addX
((
float
)
(
Math
.
random
()
*
range
)
-
(
range
/
2
)).
addZ
((
float
)
(
Math
.
random
()
*
range
)
-
(
range
/
2
)).
addZ
(.
9
f
);
EntityItem
entity
=
new
EntityItem
(
this
,
null
,
itemData
,
pos
,
1
);
addEntity
(
entity
);
}
}
else
{
EntityItem
entity
=
new
EntityItem
(
this
,
null
,
itemData
,
bornForm
.
getPosition
().
clone
().
addZ
(.
9
f
),
amount
);
addEntity
(
entity
);
}
}
public
List
<
EntityNPC
>
loadNpcForPlayer
(
Player
player
,
SceneBlock
block
){
if
(!
block
.
contains
(
player
.
getPos
())){
return
List
.
of
();
}
var
pos
=
player
.
getPos
();
var
data
=
GameData
.
getSceneNpcBornData
().
get
(
getId
());
if
(
data
==
null
){
return
List
.
of
();
}
var
npcs
=
SceneIndexManager
.
queryNeighbors
(
data
.
getIndex
(),
pos
.
toDoubleArray
(),
Grasscutter
.
getConfig
().
server
.
game
.
loadEntitiesForPlayerRange
);
var
entityNPCS
=
npcs
.
stream
().
map
(
item
->
{
var
group
=
data
.
getGroups
().
get
(
item
.
getGroupId
());
if
(
group
==
null
){
group
=
SceneGroup
.
of
(
item
.
getGroupId
());
data
.
getGroups
().
putIfAbsent
(
item
.
getGroupId
(),
group
);
group
.
load
(
getId
());
}
if
(
group
.
npc
==
null
){
return
null
;
}
var
npc
=
group
.
npc
.
get
(
item
.
getConfigId
());
if
(
npc
==
null
){
return
null
;
}
return
getScriptManager
().
createNPC
(
npc
,
block
.
id
,
item
.
getSuiteIdList
().
get
(
0
));
})
.
filter
(
Objects:
:
nonNull
)
.
filter
(
item
->
getEntities
().
values
().
stream
()
.
filter
(
e
->
e
instanceof
EntityNPC
)
.
noneMatch
(
e
->
e
.
getConfigId
()
==
item
.
getConfigId
()))
.
toList
();
if
(
entityNPCS
.
size
()
>
0
){
broadcastPacket
(
new
PacketGroupSuiteNotify
(
entityNPCS
));
}
return
entityNPCS
;
}
}
src/main/java/emu/grasscutter/game/world/WorldDataManager.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.game.world
;
import
com.google.gson.reflect.TypeToken
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.DataLoader
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.def.RewardPreviewData
;
import
emu.grasscutter.game.entity.gadget.chest.BossChestInteractHandler
;
import
emu.grasscutter.game.entity.gadget.chest.ChestInteractHandler
;
import
emu.grasscutter.game.entity.gadget.chest.NormalChestInteractHandler
;
import
emu.grasscutter.server.game.GameServer
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.util.HashMap
;
import
java.util.List
;
import
java.util.Map
;
public
class
WorldDataManager
{
private
final
GameServer
gameServer
;
private
final
Map
<
String
,
ChestInteractHandler
>
chestInteractHandlerMap
;
// chestType-Handler
public
WorldDataManager
(
GameServer
gameServer
){
this
.
gameServer
=
gameServer
;
this
.
chestInteractHandlerMap
=
new
HashMap
<>();
loadChestConfig
();
}
public
synchronized
void
loadChestConfig
(){
// set the special chest first
chestInteractHandlerMap
.
put
(
"SceneObj_Chest_Flora"
,
new
BossChestInteractHandler
());
try
(
InputStream
is
=
DataLoader
.
load
(
"ChestReward.json"
);
InputStreamReader
isr
=
new
InputStreamReader
(
is
))
{
List
<
ChestReward
>
chestReward
=
Grasscutter
.
getGsonFactory
().
fromJson
(
isr
,
TypeToken
.
getParameterized
(
List
.
class
,
ChestReward
.
class
).
getType
());
chestReward
.
forEach
(
reward
->
reward
.
getObjNames
().
forEach
(
name
->
chestInteractHandlerMap
.
putIfAbsent
(
name
,
new
NormalChestInteractHandler
(
reward
))));
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"Unable to load chest reward config."
,
e
);
}
}
public
Map
<
String
,
ChestInteractHandler
>
getChestInteractHandlerMap
()
{
return
chestInteractHandlerMap
;
}
public
RewardPreviewData
getRewardByBossId
(
int
monsterId
){
var
investigationMonsterData
=
GameData
.
getInvestigationMonsterDataMap
().
values
().
parallelStream
()
.
filter
(
imd
->
imd
.
getMonsterIdList
()
!=
null
&&
!
imd
.
getMonsterIdList
().
isEmpty
())
.
filter
(
imd
->
imd
.
getMonsterIdList
().
get
(
0
)
==
monsterId
)
.
findFirst
();
if
(
investigationMonsterData
.
isEmpty
()){
return
null
;
}
return
GameData
.
getRewardPreviewDataMap
().
get
(
investigationMonsterData
.
get
().
getRewardPreviewId
());
}
}
src/main/java/emu/grasscutter/scripts/SceneIndexManager.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.scripts
;
import
com.github.davidmoten.rtreemulti.Entry
;
import
com.github.davidmoten.rtreemulti.RTree
;
import
com.github.davidmoten.rtreemulti.geometry.Geometry
;
import
com.github.davidmoten.rtreemulti.geometry.Rectangle
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.List
;
import
java.util.function.Function
;
public
class
SceneIndexManager
{
public
static
<
T
>
RTree
<
T
,
Geometry
>
buildIndex
(
int
dimensions
,
Collection
<
T
>
elements
,
Function
<
T
,
Geometry
>
extractor
){
RTree
<
T
,
Geometry
>
rtree
=
RTree
.
dimensions
(
dimensions
).
create
();
return
rtree
.
add
(
elements
.
stream
().
map
(
e
->
Entry
.
entry
(
e
,
extractor
.
apply
(
e
))).
toList
());
}
public
static
<
T
>
List
<
T
>
queryNeighbors
(
RTree
<
T
,
Geometry
>
tree
,
double
[]
position
,
int
range
){
var
result
=
new
ArrayList
<
T
>();
Rectangle
rectangle
=
Rectangle
.
create
(
calRange
(
position
,
-
range
),
calRange
(
position
,
range
));
var
queryResult
=
tree
.
search
(
rectangle
);
queryResult
.
forEach
(
q
->
result
.
add
(
q
.
value
()));
return
result
;
}
private
static
double
[]
calRange
(
double
[]
position
,
int
range
){
var
newPos
=
position
.
clone
();
for
(
int
i
=
0
;
i
<
newPos
.
length
;
i
++){
newPos
[
i
]
+=
range
;
}
return
newPos
;
}
}
src/main/java/emu/grasscutter/scripts/SceneScriptManager.java
View file @
30c7bb94
This diff is collapsed.
Click to expand it.
src/main/java/emu/grasscutter/scripts/ScriptLib.java
View file @
30c7bb94
package
emu.grasscutter.scripts
;
import
emu.grasscutter.game.dungeons.DungeonChallenge
;
import
emu.grasscutter.game.dungeons.
challenge.
DungeonChallenge
;
import
emu.grasscutter.game.entity.EntityGadget
;
import
emu.grasscutter.game.entity.EntityMonster
;
import
emu.grasscutter.game.entity.GameEntity
;
import
emu.grasscutter.game.entity.gadget.GadgetWorktop
;
import
emu.grasscutter.game.dungeons.challenge.factory.ChallengeFactory
;
import
emu.grasscutter.scripts.data.SceneGroup
;
import
emu.grasscutter.scripts.data.SceneRegion
;
import
emu.grasscutter.server.packet.send.PacketCanUseSkillNotify
;
import
emu.grasscutter.server.packet.send.PacketGadgetStateNotify
;
import
emu.grasscutter.server.packet.send.PacketWorktopOptionNotify
;
import
io.netty.util.concurrent.FastThreadLocal
;
import
org.luaj.vm2.LuaTable
;
import
org.luaj.vm2.LuaValue
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
java.util.List
;
import
java.util.Optional
;
public
class
ScriptLib
{
public
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
ScriptLib
.
class
);
private
final
SceneScriptManager
sceneScriptManager
;
public
ScriptLib
(
SceneScriptManager
sceneScriptManager
)
{
this
.
sceneScriptManager
=
sceneScriptManager
;
private
final
FastThreadLocal
<
SceneScriptManager
>
sceneScriptManager
;
private
final
FastThreadLocal
<
SceneGroup
>
currentGroup
;
public
ScriptLib
()
{
this
.
sceneScriptManager
=
new
FastThreadLocal
<>();
this
.
currentGroup
=
new
FastThreadLocal
<>();
}
public
void
setSceneScriptManager
(
SceneScriptManager
sceneScriptManager
){
this
.
sceneScriptManager
.
set
(
sceneScriptManager
);
}
public
void
removeSceneScriptManager
(){
this
.
sceneScriptManager
.
remove
();
}
public
SceneScriptManager
getSceneScriptManager
()
{
return
sceneScriptManager
;
// normally not null
return
Optional
.
of
(
sceneScriptManager
.
get
()).
get
();
}
private
String
printTable
(
LuaTable
table
){
...
...
@@ -38,7 +49,15 @@ public class ScriptLib {
sb
.
append
(
"}"
);
return
sb
.
toString
();
}
public
void
setCurrentGroup
(
SceneGroup
currentGroup
){
this
.
currentGroup
.
set
(
currentGroup
);
}
public
Optional
<
SceneGroup
>
getCurrentGroup
(){
return
Optional
.
of
(
this
.
currentGroup
.
get
());
}
public
void
removeCurrentGroup
(){
this
.
currentGroup
.
remove
();
}
public
int
SetGadgetStateByConfigId
(
int
configId
,
int
gadgetState
)
{
logger
.
debug
(
"[LUA] Call SetGadgetStateByConfigId with {},{}"
,
configId
,
gadgetState
);
...
...
@@ -48,34 +67,24 @@ public class ScriptLib {
if
(
entity
.
isEmpty
())
{
return
1
;
}
if
(!(
entity
.
get
()
instanceof
EntityGadget
))
{
return
1
;
if
(
entity
.
get
()
instanceof
EntityGadget
entityGadget
)
{
entityGadget
.
updateState
(
gadgetState
);
return
0
;
}
EntityGadget
gadget
=
(
EntityGadget
)
entity
.
get
();
gadget
.
setState
(
gadgetState
);
getSceneScriptManager
().
getScene
().
broadcastPacket
(
new
PacketGadgetStateNotify
(
gadget
,
gadgetState
));
return
0
;
return
1
;
}
public
int
SetGroupGadgetStateByConfigId
(
int
groupId
,
int
configId
,
int
gadgetState
)
{
logger
.
debug
(
"[LUA] Call SetGroupGadgetStateByConfigId with {},{},{}"
,
groupId
,
configId
,
gadgetState
);
List
<
GameEntity
>
list
=
getSceneScriptManager
().
getScene
().
getEntities
().
values
().
stream
()
.
filter
(
e
->
e
.
getGroupId
()
==
groupId
).
toList
();
for
(
GameEntity
entity
:
list
)
{
if
(!(
entity
instanceof
EntityGadget
))
{
continue
;
}
EntityGadget
gadget
=
(
EntityGadget
)
entity
;
gadget
.
setState
(
gadgetState
);
getSceneScriptManager
().
getScene
().
broadcastPacket
(
new
PacketGadgetStateNotify
(
gadget
,
gadgetState
));
}
getSceneScriptManager
().
getScene
().
getEntities
().
values
().
stream
()
.
filter
(
e
->
e
.
getGroupId
()
==
groupId
)
.
filter
(
e
->
e
instanceof
EntityGadget
)
.
map
(
e
->
(
EntityGadget
)
e
)
.
forEach
(
e
->
e
.
updateState
(
gadgetState
));
return
0
;
}
...
...
@@ -83,42 +92,47 @@ public class ScriptLib {
public
int
SetWorktopOptionsByGroupId
(
int
groupId
,
int
configId
,
int
[]
options
)
{
logger
.
debug
(
"[LUA] Call SetWorktopOptionsByGroupId with {},{},{}"
,
groupId
,
configId
,
options
);
Optional
<
GameEntity
>
entity
=
getSceneScriptManager
().
getScene
().
getEntities
().
values
().
stream
()
.
filter
(
e
->
e
.
getConfigId
()
==
configId
&&
e
.
getGroupId
()
==
groupId
).
findFirst
();
if
(
entity
.
isEmpty
())
{
if
(
entity
.
isEmpty
()
||
!(
entity
.
get
()
instanceof
EntityGadget
gadget
))
{
return
1
;
}
if
(!(
entity
.
get
()
instanceof
EntityGadget
))
{
if
(!(
gadget
.
getContent
()
instanceof
GadgetWorktop
worktop
))
{
return
1
;
}
EntityGadget
gadget
=
(
EntityGadget
)
entity
.
get
();
gadget
.
addWorktopOptions
(
options
);
worktop
.
addWorktopOptions
(
options
);
getSceneScriptManager
().
getScene
().
broadcastPacket
(
new
PacketWorktopOptionNotify
(
gadget
));
return
0
;
}
public
int
SetWorktopOptions
(
LuaTable
table
){
logger
.
debug
(
"[LUA] Call SetWorktopOptions with {}"
,
printTable
(
table
));
// TODO
return
0
;
}
public
int
DelWorktopOptionByGroupId
(
int
groupId
,
int
configId
,
int
option
)
{
logger
.
debug
(
"[LUA] Call DelWorktopOptionByGroupId with {},{},{}"
,
groupId
,
configId
,
option
);
Optional
<
GameEntity
>
entity
=
getSceneScriptManager
().
getScene
().
getEntities
().
values
().
stream
()
.
filter
(
e
->
e
.
getConfigId
()
==
configId
&&
e
.
getGroupId
()
==
groupId
).
findFirst
();
if
(
entity
.
isEmpty
())
{
if
(
entity
.
isEmpty
()
||
!(
entity
.
get
()
instanceof
EntityGadget
gadget
)
)
{
return
1
;
}
if
(!(
entity
.
get
()
instanceof
EntityGadget
))
{
if
(!(
gadget
.
getContent
()
instanceof
GadgetWorktop
worktop
))
{
return
1
;
}
EntityGadget
gadget
=
(
EntityGadget
)
entity
.
get
();
gadget
.
removeWorktopOption
(
option
);
worktop
.
removeWorktopOption
(
option
);
getSceneScriptManager
().
getScene
().
broadcastPacket
(
new
PacketWorktopOptionNotify
(
gadget
));
return
0
;
}
...
...
@@ -146,48 +160,102 @@ public class ScriptLib {
if
(
group
==
null
||
group
.
monsters
==
null
)
{
return
1
;
}
var
suiteData
=
group
.
getSuiteByIndex
(
suite
);
if
(
suiteData
==
null
){
return
1
;
}
// avoid spawn wrong monster
if
(
getSceneScriptManager
().
getScene
().
getChallenge
()
!=
null
)
if
(!
getSceneScriptManager
().
getScene
().
getChallenge
().
inProgress
()
||
getSceneScriptManager
().
getScene
().
getChallenge
().
getGroup
().
id
!=
groupId
){
return
0
;
}
this
.
getSceneScriptManager
().
spawnMonstersInGroup
(
group
,
suite
);
this
.
getSceneScriptManager
().
addGroupSuite
(
group
,
suite
Data
);
return
0
;
}
// param3 (probably time limit for timed dungeons)
public
int
ActiveChallenge
(
int
challengeId
,
int
challengeIndex
,
int
timeLimitOrGroupId
,
int
groupId
,
int
objectiveKills
,
int
param5
)
{
logger
.
debug
(
"[LUA] Call ActiveChallenge with {},{},{},{},{},{}"
,
challengeId
,
challengeIndex
,
timeLimitOrGroupId
,
groupId
,
objectiveKills
,
param5
);
public
int
GoToGroupSuite
(
int
groupId
,
int
suite
)
{
logger
.
debug
(
"[LUA] Call GoToGroupSuite with {},{}"
,
groupId
,
suite
);
SceneGroup
group
=
getSceneScriptManager
().
getGroupById
(
groupId
);
var
objective
=
objectiveKills
;
if
(
group
==
null
||
group
.
monsters
==
null
)
{
return
1
;
}
var
suiteData
=
group
.
getSuiteByIndex
(
suite
);
if
(
suiteData
==
null
){
return
1
;
}
if
(
group
==
null
){
group
=
getSceneScriptManager
().
getGroupById
(
timeLimitOrGroupId
);
objective
=
groupId
;
for
(
var
suiteItem
:
group
.
suites
){
if
(
suiteData
==
suiteItem
){
continue
;
}
this
.
getSceneScriptManager
().
removeGroupSuite
(
group
,
suiteItem
);
}
this
.
getSceneScriptManager
().
addGroupSuite
(
group
,
suiteData
);
return
0
;
}
public
int
RemoveExtraGroupSuite
(
int
groupId
,
int
suite
)
{
logger
.
debug
(
"[LUA] Call RemoveExtraGroupSuite with {},{}"
,
groupId
,
suite
);
SceneGroup
group
=
getSceneScriptManager
().
getGroupById
(
groupId
);
if
(
group
==
null
||
group
.
monsters
==
null
)
{
return
1
;
}
var
suiteData
=
group
.
getSuiteByIndex
(
suite
);
if
(
suiteData
==
null
){
return
1
;
}
if
(
getSceneScriptManager
().
getScene
().
getChallenge
()
!=
null
&&
getSceneScriptManager
().
getScene
().
getChallenge
().
inProgress
())
{
return
0
;
this
.
getSceneScriptManager
().
removeGroupSuite
(
group
,
suiteData
);
return
0
;
}
public
int
KillExtraGroupSuite
(
int
groupId
,
int
suite
)
{
logger
.
debug
(
"[LUA] Call KillExtraGroupSuite with {},{}"
,
groupId
,
suite
);
SceneGroup
group
=
getSceneScriptManager
().
getGroupById
(
groupId
);
if
(
group
==
null
||
group
.
monsters
==
null
)
{
return
1
;
}
var
suiteData
=
group
.
getSuiteByIndex
(
suite
);
if
(
suiteData
==
null
){
return
1
;
}
DungeonChallenge
challenge
=
new
DungeonChallenge
(
getSceneScriptManager
().
getScene
(),
group
,
challengeId
,
challengeIndex
,
objective
);
// set if tower first stage (6-1)
challenge
.
setStage
(
getSceneScriptManager
().
getVariables
().
getOrDefault
(
"stage"
,
-
1
)
==
0
);
this
.
getSceneScriptManager
().
removeGroupSuite
(
group
,
suiteData
);
getSceneScriptManager
().
getScene
().
setChallenge
(
challenge
);
return
0
;
}
// param3 (probably time limit for timed dungeons)
public
int
ActiveChallenge
(
int
challengeId
,
int
challengeIndex
,
int
timeLimitOrGroupId
,
int
groupId
,
int
objectiveKills
,
int
param5
)
{
logger
.
debug
(
"[LUA] Call ActiveChallenge with {},{},{},{},{},{}"
,
challengeId
,
challengeIndex
,
timeLimitOrGroupId
,
groupId
,
objectiveKills
,
param5
);
var
challenge
=
ChallengeFactory
.
getChallenge
(
challengeId
,
challengeIndex
,
timeLimitOrGroupId
,
groupId
,
objectiveKills
,
param5
,
getSceneScriptManager
().
getScene
(),
getCurrentGroup
().
get
()
);
if
(
challenge
==
null
){
return
1
;
}
if
(
challenge
instanceof
DungeonChallenge
dungeonChallenge
){
// set if tower first stage (6-1)
dungeonChallenge
.
setStage
(
getSceneScriptManager
().
getVariables
().
getOrDefault
(
"stage"
,
-
1
)
==
0
);
}
getSceneScriptManager
().
getScene
().
setChallenge
(
challenge
);
challenge
.
start
();
return
0
;
}
...
...
@@ -244,7 +312,7 @@ public class ScriptLib {
public
int
GetRegionEntityCount
(
LuaTable
table
)
{
logger
.
debug
(
"[LUA] Call GetRegionEntityCount with {}"
,
table
);
printTable
(
table
)
)
;
int
regionId
=
table
.
get
(
"region_eid"
).
toint
();
int
entityType
=
table
.
get
(
"entity_type"
).
toint
();
...
...
@@ -267,12 +335,12 @@ public class ScriptLib {
// TODO record time
return
0
;
}
public
int
GetGroupMonsterCount
(
int
var1
){
logger
.
debug
(
"[LUA] Call GetGroupMonsterCount with {}"
,
var1
);
public
int
GetGroupMonsterCount
(){
logger
.
debug
(
"[LUA] Call GetGroupMonsterCount "
);
return
(
int
)
getSceneScriptManager
().
getScene
().
getEntities
().
values
().
stream
()
.
filter
(
e
->
e
instanceof
EntityMonster
&&
e
.
getGroupId
()
==
getSceneScriptManager
().
getCurrentGroup
().
id
)
.
filter
(
e
->
e
instanceof
EntityMonster
&&
e
.
getGroupId
()
==
getCurrentGroup
().
map
(
sceneGroup
->
sceneGroup
.
id
).
orElse
(-
1
))
.
count
();
}
public
int
SetMonsterBattleByGroup
(
int
var1
,
int
var2
,
int
var3
){
...
...
@@ -314,7 +382,7 @@ public class ScriptLib {
var
entity
=
getSceneScriptManager
().
getScene
().
getEntityByConfigId
(
configId
.
toint
());
if
(
entity
==
null
){
return
1
;
return
0
;
}
getSceneScriptManager
().
getScene
().
killEntity
(
entity
,
0
);
return
0
;
...
...
@@ -334,7 +402,11 @@ public class ScriptLib {
var
configId
=
table
.
get
(
"config_id"
).
toint
();
var
delayTime
=
table
.
get
(
"delay_time"
).
toint
();
getSceneScriptManager
().
spawnMonstersByConfigId
(
configId
,
delayTime
);
if
(
getCurrentGroup
().
isEmpty
()){
return
1
;
}
getSceneScriptManager
().
spawnMonstersByConfigId
(
getCurrentGroup
().
get
(),
configId
,
delayTime
);
return
0
;
}
...
...
@@ -353,8 +425,81 @@ public class ScriptLib {
printTable
(
table
));
var
configId
=
table
.
get
(
"config_id"
).
toint
();
//TODO
var
group
=
getCurrentGroup
();
if
(
group
.
isEmpty
())
{
return
1
;
}
var
gadget
=
group
.
get
().
gadgets
.
get
(
configId
);
var
entity
=
getSceneScriptManager
().
createGadget
(
group
.
get
().
id
,
group
.
get
().
block_id
,
gadget
);
getSceneScriptManager
().
addEntity
(
entity
);
return
0
;
}
public
int
CheckRemainGadgetCountByGroupId
(
LuaTable
table
){
logger
.
debug
(
"[LUA] Call CheckRemainGadgetCountByGroupId with {}"
,
printTable
(
table
));
var
groupId
=
table
.
get
(
"group_id"
).
toint
();
var
count
=
getSceneScriptManager
().
getScene
().
getEntities
().
values
().
stream
()
.
filter
(
g
->
g
instanceof
EntityGadget
entityGadget
&&
entityGadget
.
getGroupId
()
==
groupId
)
.
count
();
return
(
int
)
count
;
}
public
int
GetGadgetStateByConfigId
(
int
groupId
,
int
configId
){
logger
.
debug
(
"[LUA] Call GetGadgetStateByConfigId with {},{}"
,
groupId
,
configId
);
if
(
groupId
==
0
){
groupId
=
getCurrentGroup
().
get
().
id
;
}
final
int
realGroupId
=
groupId
;
var
gadget
=
getSceneScriptManager
().
getScene
().
getEntities
().
values
().
stream
()
.
filter
(
g
->
g
instanceof
EntityGadget
entityGadget
&&
entityGadget
.
getGroupId
()
==
realGroupId
)
.
filter
(
g
->
g
.
getConfigId
()
==
configId
)
.
findFirst
();
if
(
gadget
.
isEmpty
()){
return
1
;
}
return
((
EntityGadget
)
gadget
.
get
()).
getState
();
}
public
int
MarkPlayerAction
(
int
var1
,
int
var2
,
int
var3
,
int
var4
){
logger
.
debug
(
"[LUA] Call MarkPlayerAction with {},{},{},{}"
,
var1
,
var2
,
var3
,
var4
);
return
0
;
}
public
int
AddQuestProgress
(
String
var1
){
logger
.
debug
(
"[LUA] Call AddQuestProgress with {}"
,
var1
);
return
0
;
}
/**
* change the state of gadget
*/
public
int
ChangeGroupGadget
(
LuaTable
table
){
logger
.
debug
(
"[LUA] Call ChangeGroupGadget with {}"
,
printTable
(
table
));
var
configId
=
table
.
get
(
"config_id"
).
toint
();
var
state
=
table
.
get
(
"state"
).
toint
();
var
entity
=
getSceneScriptManager
().
getScene
().
getEntityByConfigId
(
configId
);
if
(
entity
==
null
){
return
1
;
}
if
(
entity
instanceof
EntityGadget
entityGadget
)
{
entityGadget
.
updateState
(
state
);
return
0
;
}
return
1
;
}
}
src/main/java/emu/grasscutter/scripts/ScriptLoader.java
View file @
30c7bb94
package
emu.grasscutter.scripts
;
import
java.io.File
;
import
java.io.FileNotFoundException
;
import
java.io.FileReader
;
import
java.io.IOException
;
import
java.util.Arrays
;
import
java.util.HashMap
;
import
java.util.Map
;
import
javax.script.Compilable
;
import
javax.script.CompiledScript
;
import
javax.script.ScriptEngine
;
import
javax.script.ScriptEngineFactory
;
import
javax.script.ScriptEngineManager
;
import
org.luaj.vm2.LuaTable
;
import
org.luaj.vm2.LuaValue
;
import
org.luaj.vm2.lib.OneArgFunction
;
import
org.luaj.vm2.lib.jse.CoerceJavaToLua
;
import
org.luaj.vm2.script.LuajContext
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.game.props.EntityType
;
import
emu.grasscutter.scripts.constants.EventType
;
import
emu.grasscutter.scripts.constants.ScriptGadgetState
;
import
emu.grasscutter.scripts.constants.ScriptRegionShape
;
import
emu.grasscutter.scripts.data.SceneMeta
;
import
emu.grasscutter.scripts.serializer.LuaSerializer
;
import
emu.grasscutter.scripts.serializer.Serializer
;
import
org.luaj.vm2.LuaTable
;
import
org.luaj.vm2.LuaValue
;
import
org.luaj.vm2.lib.OneArgFunction
;
import
org.luaj.vm2.lib.jse.CoerceJavaToLua
;
import
org.luaj.vm2.script.LuajContext
;
import
javax.script.*
;
import
java.io.File
;
import
java.io.FileReader
;
import
java.lang.ref.SoftReference
;
import
java.util.Arrays
;
import
java.util.Map
;
import
java.util.Optional
;
import
java.util.concurrent.ConcurrentHashMap
;
public
class
ScriptLoader
{
private
static
ScriptEngineManager
sm
;
...
...
@@ -34,9 +29,17 @@ public class ScriptLoader {
private
static
ScriptEngineFactory
factory
;
private
static
String
fileType
;
private
static
Serializer
serializer
;
private
static
Map
<
String
,
CompiledScript
>
scripts
=
new
HashMap
<>();
private
static
ScriptLib
scriptLib
;
private
static
LuaValue
scriptLibLua
;
/**
* suggest GC to remove it if the memory is less
*/
private
static
Map
<
String
,
SoftReference
<
CompiledScript
>>
scriptsCache
=
new
ConcurrentHashMap
<>();
/**
* sceneId - SceneMeta
*/
private
static
Map
<
Integer
,
SoftReference
<
SceneMeta
>>
sceneMetaCache
=
new
ConcurrentHashMap
<>();
public
synchronized
static
void
init
()
throws
Exception
{
if
(
sm
!=
null
)
{
throw
new
Exception
(
"Script loader already initialized"
);
...
...
@@ -67,6 +70,10 @@ public class ScriptLoader {
ctx
.
globals
.
set
(
"EventType"
,
CoerceJavaToLua
.
coerce
(
new
EventType
()));
// TODO - make static class to avoid instantiating a new class every scene
ctx
.
globals
.
set
(
"GadgetState"
,
CoerceJavaToLua
.
coerce
(
new
ScriptGadgetState
()));
ctx
.
globals
.
set
(
"RegionShape"
,
CoerceJavaToLua
.
coerce
(
new
ScriptRegionShape
()));
scriptLib
=
new
ScriptLib
();
scriptLibLua
=
CoerceJavaToLua
.
coerce
(
scriptLib
);
ctx
.
globals
.
set
(
"ScriptLib"
,
scriptLibLua
);
}
public
static
ScriptEngine
getEngine
()
{
...
...
@@ -81,25 +88,50 @@ public class ScriptLoader {
return
serializer
;
}
public
static
ScriptLib
getScriptLib
()
{
return
scriptLib
;
}
public
static
LuaValue
getScriptLibLua
()
{
return
scriptLibLua
;
}
public
static
<
T
>
Optional
<
T
>
tryGet
(
SoftReference
<
T
>
softReference
){
try
{
return
Optional
.
ofNullable
(
softReference
.
get
());
}
catch
(
NullPointerException
npe
){
return
Optional
.
empty
();
}
}
public
static
CompiledScript
getScriptByPath
(
String
path
)
{
CompiledScript
sc
=
scripts
.
get
(
path
);
Grasscutter
.
getLogger
().
info
(
"Loaded "
+
path
);
if
(
sc
==
null
)
{
File
file
=
new
File
(
path
);
if
(!
file
.
exists
())
return
null
;
try
(
FileReader
fr
=
new
FileReader
(
file
))
{
sc
=
((
Compilable
)
getEngine
()).
compile
(
fr
);
scripts
.
put
(
path
,
sc
);
}
catch
(
Exception
e
)
{
//e.printStackTrace();
return
null
;
}
var
sc
=
tryGet
(
scriptsCache
.
get
(
path
));
if
(
sc
.
isPresent
())
{
return
sc
.
get
();
}
return
sc
;
Grasscutter
.
getLogger
().
info
(
"Loading script "
+
path
);
File
file
=
new
File
(
path
);
if
(!
file
.
exists
())
return
null
;
try
(
FileReader
fr
=
new
FileReader
(
file
))
{
var
script
=
((
Compilable
)
getEngine
()).
compile
(
fr
);
scriptsCache
.
put
(
path
,
new
SoftReference
<>(
script
));
return
script
;
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
error
(
"Loading script {} failed!"
,
path
,
e
);
return
null
;
}
}
public
static
SceneMeta
getSceneMeta
(
int
sceneId
)
{
return
tryGet
(
sceneMetaCache
.
get
(
sceneId
)).
orElseGet
(()
->
{
var
instance
=
SceneMeta
.
of
(
sceneId
);
sceneMetaCache
.
put
(
sceneId
,
new
SoftReference
<>(
instance
));
return
instance
;
});
}
}
Prev
1
2
3
4
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment