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
9951bec6
Commit
9951bec6
authored
Jul 02, 2022
by
Akka
Committed by
Melledy
Jul 01, 2022
Browse files
optimize npc group load & fix some NPE in suite
parent
bd40ecee
Changes
6
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/game/world/Scene.java
View file @
9951bec6
...
@@ -3,6 +3,7 @@ package emu.grasscutter.game.world;
...
@@ -3,6 +3,7 @@ package emu.grasscutter.game.world;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameDepot
;
import
emu.grasscutter.data.GameDepot
;
import
emu.grasscutter.data.binout.SceneNpcBornEntry
;
import
emu.grasscutter.data.excels.*
;
import
emu.grasscutter.data.excels.*
;
import
emu.grasscutter.game.dungeons.DungeonSettleListener
;
import
emu.grasscutter.game.dungeons.DungeonSettleListener
;
import
emu.grasscutter.game.entity.*
;
import
emu.grasscutter.game.entity.*
;
...
@@ -53,6 +54,7 @@ public class Scene {
...
@@ -53,6 +54,7 @@ public class Scene {
private
DungeonData
dungeonData
;
private
DungeonData
dungeonData
;
private
int
prevScene
;
// Id of the previous scene
private
int
prevScene
;
// Id of the previous scene
private
int
prevScenePoint
;
private
int
prevScenePoint
;
private
Set
<
SceneNpcBornEntry
>
npcBornEntrySet
;
public
Scene
(
World
world
,
SceneData
sceneData
)
{
public
Scene
(
World
world
,
SceneData
sceneData
)
{
this
.
world
=
world
;
this
.
world
=
world
;
this
.
sceneData
=
sceneData
;
this
.
sceneData
=
sceneData
;
...
@@ -65,6 +67,7 @@ public class Scene {
...
@@ -65,6 +67,7 @@ public class Scene {
this
.
spawnedEntities
=
ConcurrentHashMap
.
newKeySet
();
this
.
spawnedEntities
=
ConcurrentHashMap
.
newKeySet
();
this
.
deadSpawnedEntities
=
ConcurrentHashMap
.
newKeySet
();
this
.
deadSpawnedEntities
=
ConcurrentHashMap
.
newKeySet
();
this
.
loadedBlocks
=
ConcurrentHashMap
.
newKeySet
();
this
.
loadedBlocks
=
ConcurrentHashMap
.
newKeySet
();
this
.
npcBornEntrySet
=
ConcurrentHashMap
.
newKeySet
();
this
.
scriptManager
=
new
SceneScriptManager
(
this
);
this
.
scriptManager
=
new
SceneScriptManager
(
this
);
}
}
...
@@ -426,6 +429,8 @@ public class Scene {
...
@@ -426,6 +429,8 @@ public class Scene {
if
(
challenge
!=
null
){
if
(
challenge
!=
null
){
challenge
.
onCheckTimeOut
();
challenge
.
onCheckTimeOut
();
}
}
checkNpcGroup
();
}
}
public
int
getEntityLevel
(
int
baseLevel
,
int
worldLevelOverride
)
{
public
int
getEntityLevel
(
int
baseLevel
,
int
worldLevelOverride
)
{
...
@@ -435,6 +440,25 @@ public class Scene {
...
@@ -435,6 +440,25 @@ public class Scene {
return
level
;
return
level
;
}
}
public
void
checkNpcGroup
(){
Set
<
SceneNpcBornEntry
>
npcBornEntries
=
ConcurrentHashMap
.
newKeySet
();
for
(
Player
player
:
this
.
getPlayers
())
{
npcBornEntries
.
addAll
(
loadNpcForPlayer
(
player
));
}
// clear the unreachable group for client
var
toUnload
=
this
.
npcBornEntrySet
.
stream
()
.
filter
(
i
->
!
npcBornEntries
.
contains
(
i
))
.
map
(
SceneNpcBornEntry:
:
getGroupId
)
.
toList
();
if
(
toUnload
.
size
()
>
0
){
broadcastPacket
(
new
PacketGroupUnloadNotify
(
toUnload
));
Grasscutter
.
getLogger
().
debug
(
"Unload NPC Group {}"
,
toUnload
);
}
// exchange the new npcBornEntry Set
this
.
npcBornEntrySet
=
npcBornEntries
;
}
// TODO - Test
// TODO - Test
public
synchronized
void
checkSpawns
()
{
public
synchronized
void
checkSpawns
()
{
...
@@ -569,9 +593,6 @@ public class Scene {
...
@@ -569,9 +593,6 @@ public class Scene {
.
toList
();
.
toList
();
onLoadGroup
(
toLoad
);
onLoadGroup
(
toLoad
);
}
}
for
(
Player
player
:
this
.
getPlayers
())
{
getScriptManager
().
meetEntities
(
loadNpcForPlayer
(
player
,
block
));
}
}
}
}
}
...
@@ -754,47 +775,27 @@ public class Scene {
...
@@ -754,47 +775,27 @@ public class Scene {
addEntity
(
entity
);
addEntity
(
entity
);
}
}
}
}
public
List
<
EntityNPC
>
loadNpcForPlayer
(
Player
player
,
SceneBlock
block
){
public
void
loadNpcForPlayerEnter
(
Player
player
){
if
(!
block
.
contains
(
player
.
getPos
())){
this
.
npcBornEntrySet
.
addAll
(
loadNpcForPlayer
(
player
));
return
List
.
of
();
}
}
private
List
<
SceneNpcBornEntry
>
loadNpcForPlayer
(
Player
player
){
var
pos
=
player
.
getPos
();
var
pos
=
player
.
getPos
();
var
data
=
GameData
.
getSceneNpcBornData
().
get
(
getId
());
var
data
=
GameData
.
getSceneNpcBornData
().
get
(
getId
());
if
(
data
==
null
){
if
(
data
==
null
){
return
List
.
of
();
return
List
.
of
();
}
}
var
npc
s
=
SceneIndexManager
.
queryNeighbors
(
data
.
getIndex
(),
pos
.
toDoubleArray
(),
var
npc
List
=
SceneIndexManager
.
queryNeighbors
(
data
.
getIndex
(),
pos
.
toDoubleArray
(),
Grasscutter
.
getConfig
().
server
.
game
.
loadEntitiesForPlayerRange
);
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
){
var
sceneNpcBornEntries
=
npcList
.
stream
()
broadcastPacket
(
new
PacketGroupSuiteNotify
(
entityNPCS
))
;
.
filter
(
i
->
!
this
.
npcBornEntrySet
.
contains
(
i
))
}
.
toList
();
return
entityNPCS
;
if
(
sceneNpcBornEntries
.
size
()
>
0
){
this
.
broadcastPacket
(
new
PacketGroupSuiteNotify
(
sceneNpcBornEntries
));
Grasscutter
.
getLogger
().
debug
(
"Loaded Npc Group Suite {}"
,
sceneNpcBornEntries
);
}
return
npcList
;
}
}
}
}
src/main/java/emu/grasscutter/scripts/data/SceneGroup.java
View file @
9951bec6
...
@@ -5,15 +5,11 @@ import emu.grasscutter.scripts.ScriptLoader;
...
@@ -5,15 +5,11 @@ import emu.grasscutter.scripts.ScriptLoader;
import
emu.grasscutter.utils.Position
;
import
emu.grasscutter.utils.Position
;
import
lombok.Setter
;
import
lombok.Setter
;
import
lombok.ToString
;
import
lombok.ToString
;
import
org.luaj.vm2.LuaValue
;
import
javax.script.Bindings
;
import
javax.script.Bindings
;
import
javax.script.CompiledScript
;
import
javax.script.CompiledScript
;
import
javax.script.ScriptException
;
import
javax.script.ScriptException
;
import
org.luaj.vm2.LuaTable
;
import
org.luaj.vm2.LuaValue
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.Optional
;
import
java.util.Optional
;
...
@@ -33,7 +29,6 @@ public class SceneGroup {
...
@@ -33,7 +29,6 @@ public class SceneGroup {
public
Map
<
Integer
,
SceneMonster
>
monsters
;
// <ConfigId, Monster>
public
Map
<
Integer
,
SceneMonster
>
monsters
;
// <ConfigId, Monster>
public
Map
<
Integer
,
SceneGadget
>
gadgets
;
// <ConfigId, Gadgets>
public
Map
<
Integer
,
SceneGadget
>
gadgets
;
// <ConfigId, Gadgets>
public
Map
<
String
,
SceneTrigger
>
triggers
;
public
Map
<
String
,
SceneTrigger
>
triggers
;
public
Map
<
Integer
,
SceneNPC
>
npc
;
// <NpcId, NPC>
public
Map
<
Integer
,
SceneRegion
>
regions
;
public
Map
<
Integer
,
SceneRegion
>
regions
;
public
List
<
SceneSuite
>
suites
;
public
List
<
SceneSuite
>
suites
;
public
List
<
SceneVar
>
variables
;
public
List
<
SceneVar
>
variables
;
...
@@ -132,42 +127,10 @@ public class SceneGroup {
...
@@ -132,42 +127,10 @@ public class SceneGroup {
}
}
// Add variables to suite
// Add variables to suite
this
.
variables
=
ScriptLoader
.
getSerializer
().
toList
(
SceneVar
.
class
,
this
.
bindings
.
get
(
"variables"
));
this
.
variables
=
ScriptLoader
.
getSerializer
().
toList
(
SceneVar
.
class
,
this
.
bindings
.
get
(
"variables"
));
// NPC in groups
this
.
npc
=
ScriptLoader
.
getSerializer
().
toList
(
SceneNPC
.
class
,
this
.
bindings
.
get
(
"npcs"
)).
stream
()
.
collect
(
Collectors
.
toMap
(
x
->
x
.
npc_id
,
y
->
y
));
this
.
npc
.
values
().
forEach
(
n
->
n
.
group
=
this
);
// Add monsters and gadgets to suite
// Add monsters and gadgets to suite
for
(
SceneSuite
suite
:
this
.
suites
)
{
this
.
suites
.
forEach
(
i
->
i
.
init
(
this
));
suite
.
sceneMonsters
=
new
ArrayList
<>(
suite
.
monsters
.
stream
()
.
filter
(
this
.
monsters
::
containsKey
)
.
map
(
this
.
monsters
::
get
)
.
toList
()
);
suite
.
sceneGadgets
=
new
ArrayList
<>(
suite
.
gadgets
.
stream
()
.
filter
(
this
.
gadgets
::
containsKey
)
.
map
(
this
.
gadgets
::
get
)
.
toList
()
);
suite
.
sceneTriggers
=
new
ArrayList
<>(
suite
.
triggers
.
stream
()
.
filter
(
this
.
triggers
::
containsKey
)
.
map
(
this
.
triggers
::
get
)
.
toList
()
);
suite
.
sceneRegions
=
new
ArrayList
<>(
suite
.
regions
.
stream
()
.
filter
(
this
.
regions
::
containsKey
)
.
map
(
this
.
regions
::
get
)
.
toList
()
);
}
}
catch
(
ScriptException
e
)
{
}
catch
(
ScriptException
e
)
{
Grasscutter
.
getLogger
().
error
(
"An error occurred while loading group "
+
this
.
id
+
" in scene "
+
sceneId
+
"."
,
e
);
Grasscutter
.
getLogger
().
error
(
"An error occurred while loading group "
+
this
.
id
+
" in scene "
+
sceneId
+
"."
,
e
);
...
...
src/main/java/emu/grasscutter/scripts/data/SceneSuite.java
View file @
9951bec6
package
emu.grasscutter.scripts.data
;
package
emu.grasscutter.scripts.data
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
lombok.Setter
;
import
lombok.Setter
;
...
@@ -8,15 +9,53 @@ import lombok.ToString;
...
@@ -8,15 +9,53 @@ import lombok.ToString;
@ToString
@ToString
@Setter
@Setter
public
class
SceneSuite
{
public
class
SceneSuite
{
public
List
<
Integer
>
monsters
;
// make it refer the default empty list to avoid NPE caused by some group
public
List
<
Integer
>
gadgets
;
public
List
<
Integer
>
monsters
=
List
.
of
();
public
List
<
String
>
triggers
;
public
List
<
Integer
>
gadgets
=
List
.
of
();
public
List
<
Integer
>
regions
;
public
List
<
String
>
triggers
=
List
.
of
();
public
List
<
Integer
>
regions
=
List
.
of
();
public
int
rand_weight
;
public
int
rand_weight
;
public
transient
List
<
SceneMonster
>
sceneMonsters
;
public
transient
List
<
SceneMonster
>
sceneMonsters
=
List
.
of
()
;
public
transient
List
<
SceneGadget
>
sceneGadgets
;
public
transient
List
<
SceneGadget
>
sceneGadgets
=
List
.
of
()
;
public
transient
List
<
SceneTrigger
>
sceneTriggers
;
public
transient
List
<
SceneTrigger
>
sceneTriggers
=
List
.
of
()
;
public
transient
List
<
SceneRegion
>
sceneRegions
;
public
transient
List
<
SceneRegion
>
sceneRegions
=
List
.
of
()
;
public
void
init
(
SceneGroup
sceneGroup
)
{
if
(
sceneGroup
.
monsters
!=
null
){
this
.
sceneMonsters
=
new
ArrayList
<>(
this
.
monsters
.
stream
()
.
filter
(
sceneGroup
.
monsters
::
containsKey
)
.
map
(
sceneGroup
.
monsters
::
get
)
.
toList
()
);
}
if
(
sceneGroup
.
gadgets
!=
null
){
this
.
sceneGadgets
=
new
ArrayList
<>(
this
.
gadgets
.
stream
()
.
filter
(
sceneGroup
.
gadgets
::
containsKey
)
.
map
(
sceneGroup
.
gadgets
::
get
)
.
toList
()
);
}
if
(
sceneGroup
.
triggers
!=
null
)
{
this
.
sceneTriggers
=
new
ArrayList
<>(
this
.
triggers
.
stream
()
.
filter
(
sceneGroup
.
triggers
::
containsKey
)
.
map
(
sceneGroup
.
triggers
::
get
)
.
toList
()
);
}
if
(
sceneGroup
.
regions
!=
null
)
{
this
.
sceneRegions
=
new
ArrayList
<>(
this
.
regions
.
stream
()
.
filter
(
sceneGroup
.
regions
::
containsKey
)
.
map
(
sceneGroup
.
regions
::
get
)
.
toList
()
);
}
}
}
}
src/main/java/emu/grasscutter/server/packet/recv/HandlerEnterSceneDoneReq.java
View file @
9951bec6
...
@@ -5,35 +5,33 @@ import emu.grasscutter.net.packet.Opcodes;
...
@@ -5,35 +5,33 @@ import emu.grasscutter.net.packet.Opcodes;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.net.packet.PacketHandler
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.game.GameSession
;
import
emu.grasscutter.server.packet.send.PacketEnterSceneDoneRsp
;
import
emu.grasscutter.server.packet.send.*
;
import
emu.grasscutter.server.packet.send.PacketPlayerTimeNotify
;
import
emu.grasscutter.server.packet.send.PacketScenePlayerLocationNotify
;
import
emu.grasscutter.server.packet.send.PacketWorldPlayerLocationNotify
;
import
emu.grasscutter.server.packet.send.PacketWorldPlayerRTTNotify
;
@Opcodes
(
PacketOpcodes
.
EnterSceneDoneReq
)
@Opcodes
(
PacketOpcodes
.
EnterSceneDoneReq
)
public
class
HandlerEnterSceneDoneReq
extends
PacketHandler
{
public
class
HandlerEnterSceneDoneReq
extends
PacketHandler
{
@Override
@Override
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
public
void
handle
(
GameSession
session
,
byte
[]
header
,
byte
[]
payload
)
throws
Exception
{
// Finished loading
// Finished loading
session
.
getPlayer
().
setSceneLoadState
(
SceneLoadState
.
LOADED
);
session
.
getPlayer
().
setSceneLoadState
(
SceneLoadState
.
LOADED
);
// Done
// Done
session
.
send
(
new
PacketEnterSceneDoneRsp
(
session
.
getPlayer
()));
session
.
send
(
new
PacketEnterSceneDoneRsp
(
session
.
getPlayer
()));
session
.
send
(
new
PacketPlayerTimeNotify
(
session
.
getPlayer
()));
// Probably not the right place
session
.
send
(
new
PacketPlayerTimeNotify
(
session
.
getPlayer
()));
// Probably not the right place
// Spawn player in world
// Spawn player in world
session
.
getPlayer
().
getScene
().
spawnPlayer
(
session
.
getPlayer
());
session
.
getPlayer
().
getScene
().
spawnPlayer
(
session
.
getPlayer
());
// Spawn other entites already in world
// Spawn other entites already in world
session
.
getPlayer
().
getScene
().
showOtherEntities
(
session
.
getPlayer
());
session
.
getPlayer
().
getScene
().
showOtherEntities
(
session
.
getPlayer
());
// Locations
// Locations
session
.
send
(
new
PacketWorldPlayerLocationNotify
(
session
.
getPlayer
().
getWorld
()));
session
.
send
(
new
PacketWorldPlayerLocationNotify
(
session
.
getPlayer
().
getWorld
()));
session
.
send
(
new
PacketScenePlayerLocationNotify
(
session
.
getPlayer
().
getScene
()));
session
.
send
(
new
PacketScenePlayerLocationNotify
(
session
.
getPlayer
().
getScene
()));
session
.
send
(
new
PacketWorldPlayerRTTNotify
(
session
.
getPlayer
().
getWorld
()));
session
.
send
(
new
PacketWorldPlayerRTTNotify
(
session
.
getPlayer
().
getWorld
()));
// spawn NPC
session
.
getPlayer
().
getScene
().
loadNpcForPlayerEnter
(
session
.
getPlayer
());
// Reset timer for sending player locations
// Reset timer for sending player locations
session
.
getPlayer
().
resetSendPlayerLocTime
();
session
.
getPlayer
().
resetSendPlayerLocTime
();
}
}
...
...
src/main/java/emu/grasscutter/server/packet/send/PacketGroupSuiteNotify.java
View file @
9951bec6
package
emu.grasscutter.server.packet.send
;
package
emu.grasscutter.server.packet.send
;
import
emu.grasscutter.
game.entity.EntityNPC
;
import
emu.grasscutter.
data.binout.SceneNpcBornEntry
;
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.net.proto.GroupSuiteNotifyOuterClass
;
import
emu.grasscutter.net.proto.GroupSuiteNotifyOuterClass
;
...
@@ -10,14 +10,18 @@ import java.util.List;
...
@@ -10,14 +10,18 @@ import java.util.List;
public
class
PacketGroupSuiteNotify
extends
BasePacket
{
public
class
PacketGroupSuiteNotify
extends
BasePacket
{
/**
/**
* control which npc suite is loaded
* Real control which npc suite is loaded
* EntityNPC is useless
*/
*/
public
PacketGroupSuiteNotify
(
List
<
EntityNPC
>
list
)
{
public
PacketGroupSuiteNotify
(
List
<
SceneNpcBornEntry
>
npcBornEntries
)
{
super
(
PacketOpcodes
.
GroupSuiteNotify
);
super
(
PacketOpcodes
.
GroupSuiteNotify
);
var
proto
=
GroupSuiteNotifyOuterClass
.
GroupSuiteNotify
.
newBuilder
();
var
proto
=
GroupSuiteNotifyOuterClass
.
GroupSuiteNotify
.
newBuilder
();
list
.
forEach
(
item
->
proto
.
putGroupMap
(
item
.
getGroupId
(),
item
.
getSuiteId
()));
npcBornEntries
.
forEach
(
x
->
x
.
getSuiteIdList
().
forEach
(
y
->
proto
.
putGroupMap
(
x
.
getGroupId
(),
y
)
));
this
.
setData
(
proto
);
this
.
setData
(
proto
);
...
...
src/main/java/emu/grasscutter/server/packet/send/PacketGroupUnloadNotify.java
0 → 100644
View file @
9951bec6
package
emu.grasscutter.server.packet.send
;
import
emu.grasscutter.net.packet.BasePacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
import
emu.grasscutter.net.proto.GroupUnloadNotifyOuterClass
;
import
java.util.List
;
public
class
PacketGroupUnloadNotify
extends
BasePacket
{
public
PacketGroupUnloadNotify
(
List
<
Integer
>
groupList
)
{
super
(
PacketOpcodes
.
GroupUnloadNotify
);
var
proto
=
GroupUnloadNotifyOuterClass
.
GroupUnloadNotify
.
newBuilder
();
proto
.
addAllGroupList
(
groupList
);
this
.
setData
(
proto
);
}
}
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