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
593de838
Commit
593de838
authored
May 17, 2022
by
Akka
Committed by
Melledy
May 16, 2022
Browse files
optimized the lua serializer
parent
1925bf64
Changes
15
Hide whitespace changes
Inline
Side-by-side
build.gradle
View file @
593de838
...
...
@@ -87,6 +87,7 @@ dependencies {
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'
protobuf
files
(
'proto/'
)
...
...
src/main/java/emu/grasscutter/scripts/SceneScriptManager.java
View file @
593de838
...
...
@@ -241,7 +241,7 @@ public class SceneScriptManager {
}
public
void
spawnGadgetsInGroup
(
SceneGroup
group
,
SceneSuite
suite
)
{
List
<
SceneGadget
>
gadgets
=
group
.
gadgets
;
var
gadgets
=
group
.
gadgets
.
values
()
;
if
(
suite
!=
null
)
{
gadgets
=
suite
.
sceneGadgets
;
...
...
src/main/java/emu/grasscutter/scripts/data/SceneBlock.java
View file @
593de838
...
...
@@ -6,6 +6,8 @@ import emu.grasscutter.Grasscutter;
import
emu.grasscutter.scripts.SceneIndexManager
;
import
emu.grasscutter.scripts.ScriptLoader
;
import
emu.grasscutter.utils.Position
;
import
lombok.Setter
;
import
lombok.ToString
;
import
javax.script.Bindings
;
import
javax.script.CompiledScript
;
...
...
@@ -14,6 +16,8 @@ import java.util.List;
import
static
emu
.
grasscutter
.
Configuration
.
SCRIPT
;
@ToString
@Setter
public
class
SceneBlock
{
public
int
id
;
public
Position
max
;
...
...
src/main/java/emu/grasscutter/scripts/data/SceneConfig.java
View file @
593de838
package
emu.grasscutter.scripts.data
;
import
emu.grasscutter.utils.Position
;
import
lombok.Setter
;
import
lombok.ToString
;
@ToString
@Setter
public
class
SceneConfig
{
public
Position
vision_anchor
;
public
Position
born_pos
;
...
...
src/main/java/emu/grasscutter/scripts/data/SceneGadget.java
View file @
593de838
package
emu.grasscutter.scripts.data
;
import
lombok.Setter
;
import
lombok.ToString
;
@ToString
@Setter
public
class
SceneGadget
extends
SceneObject
{
public
int
gadget_id
;
public
int
state
;
...
...
src/main/java/emu/grasscutter/scripts/data/SceneGroup.java
View file @
593de838
...
...
@@ -3,19 +3,22 @@ package emu.grasscutter.scripts.data;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.scripts.ScriptLoader
;
import
emu.grasscutter.utils.Position
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
import
lombok.Setter
;
import
lombok.ToString
;
import
javax.script.Bindings
;
import
javax.script.CompiledScript
;
import
javax.script.ScriptException
;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.stream.Collectors
;
import
static
emu
.
grasscutter
.
Configuration
.
SCRIPTS_FOLDER
;
@ToString
@Setter
public
class
SceneGroup
{
public
transient
int
block_id
;
// Not an actual variable in the scripts but we will keep it here for reference
...
...
@@ -27,7 +30,10 @@ public class SceneGroup {
* ConfigId - Monster
*/
public
Map
<
Integer
,
SceneMonster
>
monsters
;
public
List
<
SceneGadget
>
gadgets
;
/**
* ConfigId - Gadget
*/
public
Map
<
Integer
,
SceneGadget
>
gadgets
;
public
List
<
SceneTrigger
>
triggers
;
public
List
<
SceneRegion
>
regions
;
public
List
<
SceneSuite
>
suites
;
...
...
@@ -76,8 +82,15 @@ public class SceneGroup {
// Set
monsters
=
ScriptLoader
.
getSerializer
().
toList
(
SceneMonster
.
class
,
bindings
.
get
(
"monsters"
)).
stream
()
.
collect
(
Collectors
.
toMap
(
x
->
x
.
config_id
,
y
->
y
));
gadgets
=
ScriptLoader
.
getSerializer
().
toList
(
SceneGadget
.
class
,
bindings
.
get
(
"gadgets"
));
monsters
.
values
().
forEach
(
m
->
m
.
groupId
=
id
);
gadgets
=
ScriptLoader
.
getSerializer
().
toList
(
SceneGadget
.
class
,
bindings
.
get
(
"gadgets"
)).
stream
()
.
collect
(
Collectors
.
toMap
(
x
->
x
.
config_id
,
y
->
y
));
gadgets
.
values
().
forEach
(
m
->
m
.
groupId
=
id
);
triggers
=
ScriptLoader
.
getSerializer
().
toList
(
SceneTrigger
.
class
,
bindings
.
get
(
"triggers"
));
triggers
.
forEach
(
t
->
t
.
currentGroup
=
this
);
suites
=
ScriptLoader
.
getSerializer
().
toList
(
SceneSuite
.
class
,
bindings
.
get
(
"suites"
));
regions
=
ScriptLoader
.
getSerializer
().
toList
(
SceneRegion
.
class
,
bindings
.
get
(
"regions"
));
init_config
=
ScriptLoader
.
getSerializer
().
toObject
(
SceneInitConfig
.
class
,
bindings
.
get
(
"init_config"
));
...
...
@@ -85,35 +98,21 @@ public class SceneGroup {
// Add variables to suite
variables
=
ScriptLoader
.
getSerializer
().
toList
(
SceneVar
.
class
,
bindings
.
get
(
"variables"
));
// Add monsters to suite TODO optimize
Int2ObjectMap
<
Object
>
map
=
new
Int2ObjectOpenHashMap
<>();
monsters
.
entrySet
().
forEach
(
m
->
map
.
put
(
m
.
getValue
().
config_id
,
m
));
monsters
.
values
().
forEach
(
m
->
m
.
groupId
=
id
);
gadgets
.
forEach
(
m
->
map
.
put
(
m
.
config_id
,
m
));
gadgets
.
forEach
(
m
->
m
.
groupId
=
id
);
// Add monsters to suite
for
(
SceneSuite
suite
:
suites
)
{
suite
.
sceneMonsters
=
new
ArrayList
<>(
suite
.
monsters
.
size
());
suite
.
monsters
.
forEach
(
id
->
{
Object
objEntry
=
map
.
get
(
id
.
intValue
());
if
(
objEntry
instanceof
Map
.
Entry
<?,?>
monsterEntry
)
{
Object
monster
=
monsterEntry
.
getValue
();
if
(
monster
instanceof
SceneMonster
sceneMonster
){
suite
.
sceneMonsters
.
add
(
sceneMonster
);
}
}
});
suite
.
sceneGadgets
=
new
ArrayList
<>(
suite
.
gadgets
.
size
());
for
(
int
id
:
suite
.
gadgets
)
{
try
{
SceneGadget
gadget
=
(
SceneGadget
)
map
.
get
(
id
);
if
(
gadget
!=
null
)
{
suite
.
sceneGadgets
.
add
(
gadget
);
}
}
catch
(
Exception
ignored
)
{
}
}
suite
.
sceneMonsters
=
new
ArrayList
<>(
suite
.
monsters
.
stream
()
.
filter
(
monsters:
:
containsKey
)
.
map
(
monsters:
:
get
)
.
toList
()
);
suite
.
sceneGadgets
=
new
ArrayList
<>(
suite
.
gadgets
.
stream
()
.
filter
(
gadgets:
:
containsKey
)
.
map
(
gadgets:
:
get
)
.
toList
()
);
}
}
catch
(
ScriptException
e
)
{
...
...
src/main/java/emu/grasscutter/scripts/data/SceneInitConfig.java
View file @
593de838
package
emu.grasscutter.scripts.data
;
import
emu.grasscutter.utils.Position
;
import
lombok.Setter
;
import
lombok.ToString
;
@ToString
@Setter
public
class
SceneInitConfig
{
public
int
suite
;
public
int
end_suite
;
...
...
src/main/java/emu/grasscutter/scripts/data/SceneMeta.java
View file @
593de838
...
...
@@ -5,6 +5,9 @@ import ch.ethz.globis.phtree.v16.PhTree16;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.scripts.SceneIndexManager
;
import
emu.grasscutter.scripts.ScriptLoader
;
import
lombok.Data
;
import
lombok.Setter
;
import
lombok.ToString
;
import
javax.script.Bindings
;
import
javax.script.CompiledScript
;
...
...
@@ -15,6 +18,8 @@ import java.util.stream.Collectors;
import
static
emu
.
grasscutter
.
Configuration
.
SCRIPT
;
@ToString
@Setter
public
class
SceneMeta
{
public
SceneConfig
config
;
...
...
src/main/java/emu/grasscutter/scripts/data/SceneMonster.java
View file @
593de838
package
emu.grasscutter.scripts.data
;
import
lombok.Setter
;
import
lombok.ToString
;
@ToString
@Setter
public
class
SceneMonster
extends
SceneObject
{
public
int
monster_id
;
}
\ No newline at end of file
src/main/java/emu/grasscutter/scripts/data/SceneObject.java
View file @
593de838
package
emu.grasscutter.scripts.data
;
import
emu.grasscutter.utils.Position
;
import
lombok.Setter
;
import
lombok.ToString
;
@ToString
@Setter
public
class
SceneObject
{
public
int
level
;
public
int
config_id
;
...
...
@@ -11,5 +15,5 @@ public class SceneObject {
/**
* not set by lua
*/
public
int
groupId
;
public
transient
int
groupId
;
}
src/main/java/emu/grasscutter/scripts/data/SceneRegion.java
View file @
593de838
...
...
@@ -5,7 +5,12 @@ import emu.grasscutter.scripts.constants.ScriptRegionShape;
import
emu.grasscutter.utils.Position
;
import
it.unimi.dsi.fastutil.ints.IntOpenHashSet
;
import
it.unimi.dsi.fastutil.ints.IntSet
;
import
lombok.Data
;
import
lombok.Setter
;
import
lombok.ToString
;
@ToString
@Setter
public
class
SceneRegion
{
public
int
config_id
;
public
int
shape
;
...
...
src/main/java/emu/grasscutter/scripts/data/SceneSuite.java
View file @
593de838
...
...
@@ -2,8 +2,11 @@ package emu.grasscutter.scripts.data;
import
java.util.List
;
import
emu.grasscutter.utils.Position
;
import
lombok.Setter
;
import
lombok.ToString
;
@ToString
@Setter
public
class
SceneSuite
{
public
List
<
Integer
>
monsters
;
public
List
<
Integer
>
gadgets
;
...
...
src/main/java/emu/grasscutter/scripts/data/SceneTrigger.java
View file @
593de838
package
emu.grasscutter.scripts.data
;
import
lombok.Setter
;
@Setter
public
class
SceneTrigger
{
public
String
name
;
public
int
config_id
;
...
...
@@ -8,6 +11,7 @@ public class SceneTrigger {
public
String
condition
;
public
String
action
;
public
SceneGroup
currentGroup
;
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
obj
instanceof
SceneTrigger
sceneTrigger
){
...
...
src/main/java/emu/grasscutter/scripts/data/SceneVar.java
View file @
593de838
package
emu.grasscutter.scripts.data
;
import
lombok.Setter
;
import
lombok.ToString
;
@ToString
@Setter
public
class
SceneVar
{
public
String
name
;
public
int
value
;
...
...
src/main/java/emu/grasscutter/scripts/serializer/LuaSerializer.java
View file @
593de838
package
emu.grasscutter.scripts.serializer
;
import
java.lang.reflect.Field
;
import
java.util.ArrayList
;
import
java.util.List
;
import
com.esotericsoftware.reflectasm.ConstructorAccess
;
import
com.esotericsoftware.reflectasm.MethodAccess
;
import
lombok.AccessLevel
;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.experimental.FieldDefaults
;
import
org.luaj.vm2.LuaTable
;
import
org.luaj.vm2.LuaValue
;
import
java.util.*
;
import
java.util.concurrent.ConcurrentHashMap
;
public
class
LuaSerializer
implements
Serializer
{
private
final
static
Map
<
Class
<?>,
MethodAccess
>
methodAccessCache
=
new
ConcurrentHashMap
<>();
private
final
static
Map
<
Class
<?>,
ConstructorAccess
<?>>
constructorCache
=
new
ConcurrentHashMap
<>();
private
final
static
Map
<
Class
<?>,
Map
<
String
,
FieldMeta
>>
fieldMetaCache
=
new
ConcurrentHashMap
<>();
@Override
public
<
T
>
List
<
T
>
toList
(
Class
<
T
>
type
,
Object
obj
)
{
return
serializeList
(
type
,
(
LuaTable
)
obj
);
...
...
@@ -20,7 +29,7 @@ public class LuaSerializer implements Serializer {
}
public
<
T
>
List
<
T
>
serializeList
(
Class
<
T
>
type
,
LuaTable
table
)
{
List
<
T
>
list
=
new
ArrayList
();
List
<
T
>
list
=
new
ArrayList
<>
();
try
{
LuaValue
[]
keys
=
table
.
keys
();
...
...
@@ -55,7 +64,7 @@ public class LuaSerializer implements Serializer {
return
list
;
}
public
<
T
>
T
serialize
(
Class
<
T
>
type
,
LuaTable
table
)
{
T
object
=
null
;
...
...
@@ -70,30 +79,34 @@ public class LuaSerializer implements Serializer {
}
try
{
//noinspection ConfusingArgumentToVarargsMethod
object
=
type
.
getDeclaredConstructor
().
newInstance
(
null
);
if
(!
methodAccessCache
.
containsKey
(
type
)){
cacheType
(
type
);
}
var
methodAccess
=
methodAccessCache
.
get
(
type
);
var
fieldMetaMap
=
fieldMetaCache
.
get
(
type
);
object
=
(
T
)
constructorCache
.
get
(
type
).
newInstance
();
LuaValue
[]
keys
=
table
.
keys
();
for
(
LuaValue
k
:
keys
)
{
try
{
Field
field
=
getField
(
object
.
getClass
(),
k
.
checkjstring
()
)
;
if
(
field
==
null
)
{
var
keyName
=
k
.
checkjstring
();
if
(
!
field
MetaMap
.
containsKey
(
keyName
))
{
continue
;
}
field
.
setAccessible
(
true
);
var
fieldMeta
=
fieldMetaMap
.
get
(
keyName
);
LuaValue
keyValue
=
table
.
get
(
k
);
if
(
keyValue
.
istable
())
{
field
.
set
(
object
,
serialize
(
field
.
getType
(),
keyValue
.
checktable
()));
}
else
if
(
field
.
getType
().
equals
(
float
.
class
))
{
field
.
setFloat
(
object
,
keyValue
.
tofloat
());
}
else
if
(
field
.
getType
().
equals
(
int
.
class
))
{
field
.
setInt
(
object
,
keyValue
.
toint
());
}
else
if
(
field
.
getType
().
equals
(
String
.
class
))
{
field
.
set
(
object
,
keyValue
.
tojstring
());
methodAccess
.
invoke
(
object
,
fieldMeta
.
index
,
serialize
(
field
Meta
.
getType
(),
keyValue
.
checktable
()));
}
else
if
(
field
Meta
.
getType
().
equals
(
float
.
class
))
{
methodAccess
.
invoke
(
object
,
fieldMeta
.
index
,
keyValue
.
tofloat
());
}
else
if
(
field
Meta
.
getType
().
equals
(
int
.
class
))
{
methodAccess
.
invoke
(
object
,
fieldMeta
.
index
,
keyValue
.
toint
());
}
else
if
(
field
Meta
.
getType
().
equals
(
String
.
class
))
{
methodAccess
.
invoke
(
object
,
fieldMeta
.
index
,
keyValue
.
tojstring
());
}
else
{
field
.
set
(
object
,
keyValue
);
methodAccess
.
invoke
(
object
,
fieldMeta
.
index
,
keyValue
.
tojstring
()
);
}
}
catch
(
Exception
ex
)
{
//ex.printStackTrace();
...
...
@@ -107,16 +120,57 @@ public class LuaSerializer implements Serializer {
return
object
;
}
public
<
T
>
Field
getField
(
Class
<
T
>
clazz
,
String
name
){
try
{
return
clazz
.
getField
(
name
);
}
catch
(
NoSuchFieldException
ex
)
{
try
{
return
clazz
.
getDeclaredField
(
name
);
}
catch
(
NoSuchFieldException
e
)
{
// ignore
return
null
;
}
public
<
T
>
Map
<
String
,
FieldMeta
>
cacheType
(
Class
<
T
>
type
){
if
(
fieldMetaCache
.
containsKey
(
type
))
{
return
fieldMetaCache
.
get
(
type
);
}
if
(!
constructorCache
.
containsKey
(
type
)){
constructorCache
.
putIfAbsent
(
type
,
ConstructorAccess
.
get
(
type
));
}
var
methodAccess
=
Optional
.
ofNullable
(
methodAccessCache
.
get
(
type
)).
orElse
(
MethodAccess
.
get
(
type
));
methodAccessCache
.
putIfAbsent
(
type
,
methodAccess
);
var
fieldMetaMap
=
new
HashMap
<
String
,
FieldMeta
>();
var
methodNameSet
=
new
HashSet
<>(
Arrays
.
stream
(
methodAccess
.
getMethodNames
()).
toList
());
Arrays
.
stream
(
type
.
getDeclaredFields
())
.
filter
(
field
->
methodNameSet
.
contains
(
getSetterName
(
field
.
getName
())))
.
forEach
(
field
->
{
var
setter
=
getSetterName
(
field
.
getName
());
var
index
=
methodAccess
.
getIndex
(
setter
);
fieldMetaMap
.
put
(
field
.
getName
(),
new
FieldMeta
(
field
.
getName
(),
setter
,
index
,
field
.
getType
()));
});
Arrays
.
stream
(
type
.
getFields
())
.
filter
(
field
->
!
fieldMetaMap
.
containsKey
(
field
.
getName
()))
.
filter
(
field
->
methodNameSet
.
contains
(
getSetterName
(
field
.
getName
())))
.
forEach
(
field
->
{
var
setter
=
getSetterName
(
field
.
getName
());
var
index
=
methodAccess
.
getIndex
(
setter
);
fieldMetaMap
.
put
(
field
.
getName
(),
new
FieldMeta
(
field
.
getName
(),
setter
,
index
,
field
.
getType
()));
});
fieldMetaCache
.
put
(
type
,
fieldMetaMap
);
return
fieldMetaMap
;
}
public
String
getSetterName
(
String
fieldName
){
if
(
fieldName
==
null
||
fieldName
.
length
()
==
0
){
return
null
;
}
if
(
fieldName
.
length
()
==
1
){
return
"set"
+
fieldName
.
toUpperCase
();
}
return
"set"
+
Character
.
toUpperCase
(
fieldName
.
charAt
(
0
))
+
fieldName
.
substring
(
1
);
}
@Data
@AllArgsConstructor
@FieldDefaults
(
level
=
AccessLevel
.
PRIVATE
)
static
class
FieldMeta
{
String
name
;
String
setter
;
int
index
;
Class
<?>
type
;
}
}
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