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
5a3e9bc3
Commit
5a3e9bc3
authored
May 25, 2022
by
Akka
Committed by
Melledy
May 25, 2022
Browse files
Fixed excessive memory usage of Spatial Index
parent
d95708ec
Changes
10
Hide whitespace changes
Inline
Side-by-side
build.gradle
View file @
5a3e9bc3
...
@@ -86,8 +86,8 @@ dependencies {
...
@@ -86,8 +86,8 @@ dependencies {
implementation
group:
'org.luaj'
,
name:
'luaj-jse'
,
version:
'3.0.1'
implementation
group:
'org.luaj'
,
name:
'luaj-jse'
,
version:
'3.0.1'
implementation
group:
'ch.ethz.globis.phtree'
,
name
:
'phtree'
,
version:
'2.5.0'
implementation
group:
'com.esotericsoftware'
,
name
:
'reflectasm'
,
version:
'1.11.9'
implementation
group:
'com.esotericsoftware'
,
name
:
'reflectasm'
,
version:
'1.11.9'
implementation
group:
'com.github.davidmoten'
,
name
:
'rtree-multi'
,
version:
'0.1'
protobuf
files
(
'proto/'
)
protobuf
files
(
'proto/'
)
...
...
src/main/java/emu/grasscutter/data/ResourceLoader.java
View file @
5a3e9bc3
...
@@ -8,10 +8,9 @@ import java.util.Map.Entry;
...
@@ -8,10 +8,9 @@ import java.util.Map.Entry;
import
java.util.regex.Matcher
;
import
java.util.regex.Matcher
;
import
java.util.regex.Pattern
;
import
java.util.regex.Pattern
;
import
ch.ethz.globis.phtree.PhTree
;
import
ch.ethz.globis.phtree.v16.PhTree16
;
import
com.google.gson.Gson
;
import
com.google.gson.Gson
;
import
emu.grasscutter.data.custom.*
;
import
emu.grasscutter.data.custom.*
;
import
emu.grasscutter.scripts.SceneIndexManager
;
import
emu.grasscutter.utils.Utils
;
import
emu.grasscutter.utils.Utils
;
import
lombok.SneakyThrows
;
import
lombok.SneakyThrows
;
import
org.reflections.Reflections
;
import
org.reflections.Reflections
;
...
@@ -428,15 +427,12 @@ public class ResourceLoader {
...
@@ -428,15 +427,12 @@ public class ResourceLoader {
continue
;
continue
;
}
}
PhTree
<
SceneNpcBornEntry
>
index
=
new
PhTree16
<>(
3
);
var
data
=
Grasscutter
.
getGsonFactory
().
fromJson
(
Files
.
readString
(
file
),
SceneNpcBornData
.
class
);
var
data
=
Grasscutter
.
getGsonFactory
().
fromJson
(
Files
.
readString
(
file
),
SceneNpcBornData
.
class
);
if
(
data
.
getBornPosList
()
==
null
||
data
.
getBornPosList
().
size
()
==
0
){
if
(
data
.
getBornPosList
()
==
null
||
data
.
getBornPosList
().
size
()
==
0
){
continue
;
continue
;
}
}
data
.
getBornPosList
().
forEach
(
item
->
index
.
put
(
item
.
getPos
().
toLongArray
(),
item
));
data
.
setIndex
(
index
);
data
.
setIndex
(
SceneIndexManager
.
buildIndex
(
3
,
data
.
getBornPosList
(),
item
->
item
.
getPos
().
toPoint
())
);
GameData
.
getSceneNpcBornData
().
put
(
data
.
getSceneId
(),
data
);
GameData
.
getSceneNpcBornData
().
put
(
data
.
getSceneId
(),
data
);
}
}
...
...
src/main/java/emu/grasscutter/data/custom/SceneNpcBornData.java
View file @
5a3e9bc3
package
emu.grasscutter.data.custom
;
package
emu.grasscutter.data.custom
;
import
ch.ethz.globis.phtree.PhTree
;
import
com.github.davidmoten.rtreemulti.RTree
;
import
com.github.davidmoten.rtreemulti.geometry.Geometry
;
import
emu.grasscutter.scripts.data.SceneGroup
;
import
emu.grasscutter.scripts.data.SceneGroup
;
import
lombok.AccessLevel
;
import
lombok.AccessLevel
;
import
lombok.Data
;
import
lombok.Data
;
...
@@ -19,7 +20,7 @@ public class SceneNpcBornData {
...
@@ -19,7 +20,7 @@ public class SceneNpcBornData {
/**
/**
* Spatial Index For NPC
* Spatial Index For NPC
*/
*/
transient
Ph
Tree
<
SceneNpcBornEntry
>
index
;
transient
R
Tree
<
SceneNpcBornEntry
,
Geometry
>
index
;
/**
/**
* npc groups
* npc groups
...
...
src/main/java/emu/grasscutter/game/world/Scene.java
View file @
5a3e9bc3
...
@@ -498,11 +498,11 @@ public class Scene {
...
@@ -498,11 +498,11 @@ public class Scene {
this
.
broadcastPacket
(
new
PacketSceneEntityDisappearNotify
(
toRemove
,
VisionType
.
VISION_REMOVE
));
this
.
broadcastPacket
(
new
PacketSceneEntityDisappearNotify
(
toRemove
,
VisionType
.
VISION_REMOVE
));
}
}
}
}
public
Set
<
SceneBlock
>
getPlayerActiveBlocks
(
Player
player
){
// TODO consider the borders of blocks
public
List
<
SceneBlock
>
getPlayerActiveBlocks
(
Player
player
){
return
getScriptManager
().
getBlocks
().
values
().
stream
()
// consider the borders' entities of blocks, so we check if contains by index
.
filter
(
block
->
block
.
contains
(
player
.
getPos
()))
return
SceneIndexManager
.
queryNeighbors
(
getScriptManager
().
getBlocksIndex
(),
.
collect
(
Collectors
.
toSet
()
);
player
.
getPos
().
toXZDoubleArray
(),
Grasscutter
.
getConfig
().
server
.
game
.
loadEntitiesForPlayerRange
);
}
}
public
void
checkBlocks
()
{
public
void
checkBlocks
()
{
Set
<
SceneBlock
>
visible
=
new
HashSet
<>();
Set
<
SceneBlock
>
visible
=
new
HashSet
<>();
...
@@ -542,9 +542,8 @@ public class Scene {
...
@@ -542,9 +542,8 @@ public class Scene {
}
}
public
List
<
SceneGroup
>
playerMeetGroups
(
Player
player
,
SceneBlock
block
){
public
List
<
SceneGroup
>
playerMeetGroups
(
Player
player
,
SceneBlock
block
){
int
RANGE
=
100
;
List
<
SceneGroup
>
sceneGroups
=
SceneIndexManager
.
queryNeighbors
(
block
.
sceneGroupIndex
,
player
.
getPos
().
toDoubleArray
(),
Grasscutter
.
getConfig
().
server
.
game
.
loadEntitiesForPlayerRange
);
List
<
SceneGroup
>
sceneGroups
=
SceneIndexManager
.
queryNeighbors
(
block
.
sceneGroupIndex
,
player
.
getPos
(),
RANGE
);
List
<
SceneGroup
>
groups
=
sceneGroups
.
stream
()
List
<
SceneGroup
>
groups
=
sceneGroups
.
stream
()
.
filter
(
group
->
!
scriptManager
.
getLoadedGroupSetPerBlock
().
get
(
block
.
id
).
contains
(
group
))
.
filter
(
group
->
!
scriptManager
.
getLoadedGroupSetPerBlock
().
get
(
block
.
id
).
contains
(
group
))
...
@@ -732,14 +731,14 @@ public class Scene {
...
@@ -732,14 +731,14 @@ public class Scene {
return
List
.
of
();
return
List
.
of
();
}
}
int
RANGE
=
100
;
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
npcs
=
SceneIndexManager
.
queryNeighbors
(
data
.
getIndex
(),
pos
.
toLongArray
(),
RANGE
);
var
npcs
=
SceneIndexManager
.
queryNeighbors
(
data
.
getIndex
(),
pos
.
toDoubleArray
(),
Grasscutter
.
getConfig
().
server
.
game
.
loadEntitiesForPlayerRange
);
var
entityNPCS
=
npcs
.
stream
().
map
(
item
->
{
var
entityNPCS
=
npcs
.
stream
().
map
(
item
->
{
var
group
=
data
.
getGroups
().
get
(
item
.
getGroupId
());
var
group
=
data
.
getGroups
().
get
(
item
.
getGroupId
());
if
(
group
==
null
){
if
(
group
==
null
){
...
...
src/main/java/emu/grasscutter/scripts/SceneIndexManager.java
View file @
5a3e9bc3
package
emu.grasscutter.scripts
;
package
emu.grasscutter.scripts
;
import
ch.ethz.globis.phtree.PhTree
;
import
com.github.davidmoten.rtreemulti.Entry
;
import
emu.grasscutter.utils.Position
;
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.ArrayList
;
import
java.util.Collection
;
import
java.util.Collection
;
...
@@ -10,31 +12,20 @@ import java.util.function.Function;
...
@@ -10,31 +12,20 @@ import java.util.function.Function;
public
class
SceneIndexManager
{
public
class
SceneIndexManager
{
public
static
<
T
>
void
buildIndex
(
PhTree
<
T
>
tree
,
Collection
<
T
>
elements
,
Function
<
T
,
long
[]>
extractor
){
public
static
<
T
>
RTree
<
T
,
Geometry
>
buildIndex
(
int
dimensions
,
Collection
<
T
>
elements
,
Function
<
T
,
Geometry
>
extractor
){
elements
.
forEach
(
e
->
tree
.
put
(
extractor
.
apply
(
e
),
e
));
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
(
Ph
Tree
<
T
>
tree
,
Position
position
,
int
range
){
public
static
<
T
>
List
<
T
>
queryNeighbors
(
R
Tree
<
T
,
Geometry
>
tree
,
double
[]
position
,
int
range
){
var
result
=
new
ArrayList
<
T
>();
var
result
=
new
ArrayList
<
T
>();
var
arrPos
=
position
.
toLongArray
();
Rectangle
rectangle
=
Rectangle
.
create
(
calRange
(
position
,
-
range
),
calRange
(
position
,
range
));
var
query
=
tree
.
query
(
calRange
(
arrPos
,
-
range
),
calRange
(
arrPos
,
range
));
var
queryResult
=
tree
.
search
(
rectangle
);
while
(
query
.
hasNext
()){
queryResult
.
forEach
(
q
->
result
.
add
(
q
.
value
()));
var
element
=
query
.
next
();
result
.
add
(
element
);
}
return
result
;
}
public
static
<
T
>
List
<
T
>
queryNeighbors
(
PhTree
<
T
>
tree
,
long
[]
position
,
int
range
){
var
result
=
new
ArrayList
<
T
>();
var
query
=
tree
.
query
(
calRange
(
position
,
-
range
),
calRange
(
position
,
range
));
while
(
query
.
hasNext
()){
var
element
=
query
.
next
();
result
.
add
(
element
);
}
return
result
;
return
result
;
}
}
private
static
long
[]
calRange
(
long
[]
position
,
int
range
){
private
static
double
[]
calRange
(
double
[]
position
,
int
range
){
var
newPos
=
position
.
clone
();
var
newPos
=
position
.
clone
();
for
(
int
i
=
0
;
i
<
position
.
length
;
i
++){
for
(
int
i
=
0
;
i
<
newPos
.
length
;
i
++){
newPos
[
i
]
+=
range
;
newPos
[
i
]
+=
range
;
}
}
return
newPos
;
return
newPos
;
...
...
src/main/java/emu/grasscutter/scripts/SceneScriptManager.java
View file @
5a3e9bc3
package
emu.grasscutter.scripts
;
package
emu.grasscutter.scripts
;
import
ch.ethz.globis.phtree.PhTree
;
import
com.github.davidmoten.rtreemulti.RTree
;
import
com.github.davidmoten.rtreemulti.geometry.Geometry
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.GameData
;
import
emu.grasscutter.data.def.MonsterData
;
import
emu.grasscutter.data.def.MonsterData
;
...
@@ -420,7 +421,7 @@ public class SceneScriptManager {
...
@@ -420,7 +421,7 @@ public class SceneScriptManager {
getScene
().
addEntities
(
gameEntity
);
getScene
().
addEntities
(
gameEntity
);
}
}
public
Ph
Tree
<
SceneBlock
>
getBlocksIndex
()
{
public
R
Tree
<
SceneBlock
,
Geometry
>
getBlocksIndex
()
{
return
meta
.
sceneBlockIndex
;
return
meta
.
sceneBlockIndex
;
}
}
public
void
removeMonstersInGroup
(
SceneGroup
group
,
SceneSuite
suite
)
{
public
void
removeMonstersInGroup
(
SceneGroup
group
,
SceneSuite
suite
)
{
...
...
src/main/java/emu/grasscutter/scripts/data/SceneBlock.java
View file @
5a3e9bc3
package
emu.grasscutter.scripts.data
;
package
emu.grasscutter.scripts.data
;
import
ch.ethz.globis.phtree.PhTree
;
import
com.github.davidmoten.rtreemulti.RTree
;
import
ch.ethz.globis.phtree.v16.PhTree16
;
import
com.github.davidmoten.rtreemulti.geometry.Geometry
;
import
com.github.davidmoten.rtreemulti.geometry.Rectangle
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.scripts.SceneIndexManager
;
import
emu.grasscutter.scripts.SceneIndexManager
;
import
emu.grasscutter.scripts.ScriptLoader
;
import
emu.grasscutter.scripts.ScriptLoader
;
...
@@ -12,7 +13,6 @@ import lombok.ToString;
...
@@ -12,7 +13,6 @@ import lombok.ToString;
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
java.util.List
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.stream.Collectors
;
import
java.util.stream.Collectors
;
...
@@ -27,7 +27,7 @@ public class SceneBlock {
...
@@ -27,7 +27,7 @@ public class SceneBlock {
public
int
sceneId
;
public
int
sceneId
;
public
Map
<
Integer
,
SceneGroup
>
groups
;
public
Map
<
Integer
,
SceneGroup
>
groups
;
public
Ph
Tree
<
SceneGroup
>
sceneGroupIndex
=
new
PhTree16
<>(
3
)
;
public
R
Tree
<
SceneGroup
,
Geometry
>
sceneGroupIndex
;
private
transient
boolean
loaded
;
// Not an actual variable in the scripts either
private
transient
boolean
loaded
;
// Not an actual variable in the scripts either
...
@@ -67,11 +67,15 @@ public class SceneBlock {
...
@@ -67,11 +67,15 @@ public class SceneBlock {
.
collect
(
Collectors
.
toMap
(
x
->
x
.
id
,
y
->
y
));
.
collect
(
Collectors
.
toMap
(
x
->
x
.
id
,
y
->
y
));
groups
.
values
().
forEach
(
g
->
g
.
block_id
=
id
);
groups
.
values
().
forEach
(
g
->
g
.
block_id
=
id
);
SceneIndexManager
.
buildIndex
(
this
.
sceneGroupIndex
,
groups
.
values
(),
g
->
g
.
pos
.
to
LongArray
());
this
.
sceneGroupIndex
=
SceneIndexManager
.
buildIndex
(
3
,
groups
.
values
(),
g
->
g
.
pos
.
to
Point
());
}
catch
(
ScriptException
e
)
{
}
catch
(
ScriptException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading block "
+
id
+
" in scene "
+
sceneId
,
e
);
Grasscutter
.
getLogger
().
error
(
"Error loading block "
+
id
+
" in scene "
+
sceneId
,
e
);
}
}
Grasscutter
.
getLogger
().
info
(
"scene {} block {} is loaded successfully."
,
sceneId
,
id
);
Grasscutter
.
getLogger
().
info
(
"scene {} block {} is loaded successfully."
,
sceneId
,
id
);
return
this
;
return
this
;
}
}
public
Rectangle
toRectangle
()
{
return
Rectangle
.
create
(
min
.
toXZDoubleArray
(),
max
.
toXZDoubleArray
());
}
}
}
\ No newline at end of file
src/main/java/emu/grasscutter/scripts/data/SceneMeta.java
View file @
5a3e9bc3
package
emu.grasscutter.scripts.data
;
package
emu.grasscutter.scripts.data
;
import
c
h.ethz.globis.phtree.Ph
Tree
;
import
c
om.github.davidmoten.rtreemulti.R
Tree
;
import
c
h.ethz.globis.phtree.v16.PhTree16
;
import
c
om.github.davidmoten.rtreemulti.geometry.Geometry
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.scripts.SceneIndexManager
;
import
emu.grasscutter.scripts.SceneIndexManager
;
import
emu.grasscutter.scripts.ScriptLoader
;
import
emu.grasscutter.scripts.ScriptLoader
;
import
lombok.Data
;
import
lombok.Setter
;
import
lombok.Setter
;
import
lombok.ToString
;
import
lombok.ToString
;
...
@@ -27,7 +26,7 @@ public class SceneMeta {
...
@@ -27,7 +26,7 @@ public class SceneMeta {
public
Bindings
context
;
public
Bindings
context
;
public
Ph
Tree
<
SceneBlock
>
sceneBlockIndex
=
new
PhTree16
<>(
2
)
;
public
R
Tree
<
SceneBlock
,
Geometry
>
sceneBlockIndex
;
public
static
SceneMeta
of
(
int
sceneId
)
{
public
static
SceneMeta
of
(
int
sceneId
)
{
return
new
SceneMeta
().
load
(
sceneId
);
return
new
SceneMeta
().
load
(
sceneId
);
...
@@ -64,8 +63,8 @@ public class SceneMeta {
...
@@ -64,8 +63,8 @@ public class SceneMeta {
}
}
this
.
blocks
=
blocks
.
stream
().
collect
(
Collectors
.
toMap
(
b
->
b
.
id
,
b
->
b
));
this
.
blocks
=
blocks
.
stream
().
collect
(
Collectors
.
toMap
(
b
->
b
.
id
,
b
->
b
));
SceneIndexManager
.
buildIndex
(
this
.
sceneBlockIndex
,
blocks
,
g
->
g
.
min
.
toXZLongArray
()
);
this
.
sceneBlockIndex
=
SceneIndexManager
.
buildIndex
(
2
,
blocks
,
SceneBlock:
:
toRectangle
);
SceneIndexManager
.
buildIndex
(
this
.
sceneBlockIndex
,
blocks
,
g
->
g
.
max
.
toXZLongArray
());
}
catch
(
ScriptException
e
)
{
}
catch
(
ScriptException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error running script"
,
e
);
Grasscutter
.
getLogger
().
error
(
"Error running script"
,
e
);
return
null
;
return
null
;
...
...
src/main/java/emu/grasscutter/utils/ConfigContainer.java
View file @
5a3e9bc3
...
@@ -135,7 +135,8 @@ public class ConfigContainer {
...
@@ -135,7 +135,8 @@ public class ConfigContainer {
public
int
bindPort
=
22102
;
public
int
bindPort
=
22102
;
/* This is the port used in the default region. */
/* This is the port used in the default region. */
public
int
accessPort
=
0
;
public
int
accessPort
=
0
;
/* Entities within a certain range will be loaded for the player */
public
int
loadEntitiesForPlayerRange
=
100
;
public
boolean
enableScriptInBigWorld
=
false
;
public
boolean
enableScriptInBigWorld
=
false
;
public
boolean
enableConsole
=
true
;
public
boolean
enableConsole
=
true
;
public
GameOptions
gameOptions
=
new
GameOptions
();
public
GameOptions
gameOptions
=
new
GameOptions
();
...
...
src/main/java/emu/grasscutter/utils/Position.java
View file @
5a3e9bc3
...
@@ -2,6 +2,7 @@ package emu.grasscutter.utils;
...
@@ -2,6 +2,7 @@ package emu.grasscutter.utils;
import
java.io.Serializable
;
import
java.io.Serializable
;
import
com.github.davidmoten.rtreemulti.geometry.Point
;
import
dev.morphia.annotations.Entity
;
import
dev.morphia.annotations.Entity
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
import
emu.grasscutter.net.proto.VectorOuterClass.Vector
;
...
@@ -155,10 +156,20 @@ public class Position implements Serializable {
...
@@ -155,10 +156,20 @@ public class Position implements Serializable {
.
setZ
(
this
.
getZ
())
.
setZ
(
this
.
getZ
())
.
build
();
.
build
();
}
}
public
long
[]
toLongArray
(){
public
Point
toPoint
(){
return
new
long
[]{(
long
)
x
,
(
long
)
y
,
(
long
)
z
}
;
return
Point
.
create
(
x
,
y
,
z
)
;
}
}
public
long
[]
toXZLongArray
(){
return
new
long
[]{(
long
)
x
,
(
long
)
z
};
/**
* To XYZ array for Spatial Index
*/
public
double
[]
toDoubleArray
(){
return
new
double
[]{
x
,
y
,
z
};
}
/**
* To XZ array for Spatial Index (Blocks)
*/
public
double
[]
toXZDoubleArray
(){
return
new
double
[]{
x
,
z
};
}
}
}
}
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