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
Hide whitespace changes
Inline
Side-by-side
src/main/java/emu/grasscutter/scripts/ScriptUtils.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.scripts
;
import
java.util.HashMap
;
import
org.luaj.vm2.LuaTable
;
import
org.luaj.vm2.LuaValue
;
import
emu.grasscutter.Grasscutter
;
public
class
ScriptUtils
{
public
static
HashMap
<
Object
,
Object
>
toMap
(
LuaTable
table
)
{
HashMap
<
Object
,
Object
>
map
=
new
HashMap
<>();
LuaValue
[]
rootKeys
=
table
.
keys
();
for
(
LuaValue
k
:
rootKeys
)
{
if
(
table
.
get
(
k
).
istable
())
{
map
.
put
(
k
,
toMap
(
table
.
get
(
k
).
checktable
()));
}
else
{
map
.
put
(
k
,
table
.
get
(
k
));
}
}
return
map
;
}
public
static
void
print
(
LuaTable
table
)
{
Grasscutter
.
getLogger
().
info
(
toMap
(
table
).
toString
());
}
}
src/main/java/emu/grasscutter/scripts/constants/EventType.java
View file @
30c7bb94
...
...
@@ -2,6 +2,9 @@ package emu.grasscutter.scripts.constants;
public
class
EventType
{
public
static
final
int
EVENT_NONE
=
0
;
/**
* param1: monster.configId
*/
public
static
final
int
EVENT_ANY_MONSTER_DIE
=
1
;
public
static
final
int
EVENT_ANY_GADGET_DIE
=
2
;
public
static
final
int
EVENT_VARIABLE_CHANGE
=
3
;
...
...
src/main/java/emu/grasscutter/scripts/data/SceneBlock.java
View file @
30c7bb94
package
emu.grasscutter.scripts.data
;
import
java.util.List
;
import
com.github.davidmoten.rtreemulti.RTree
;
import
com.github.davidmoten.rtreemulti.geometry.Geometry
;
import
com.github.davidmoten.rtreemulti.geometry.Rectangle
;
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
;
import
javax.script.ScriptException
;
import
java.util.Map
;
import
java.util.stream.Collectors
;
import
static
emu
.
grasscutter
.
Configuration
.
SCRIPT
;
@ToString
@Setter
public
class
SceneBlock
{
public
int
id
;
public
Position
max
;
public
Position
min
;
public
List
<
SceneGroup
>
groups
;
public
int
sceneId
;
public
Map
<
Integer
,
SceneGroup
>
groups
;
public
RTree
<
SceneGroup
,
Geometry
>
sceneGroupIndex
;
private
transient
boolean
loaded
;
// Not an actual variable in the scripts either
public
boolean
isLoaded
()
{
return
loaded
;
}
public
void
setLoaded
(
boolean
loaded
)
{
this
.
loaded
=
loaded
;
}
public
boolean
contains
(
Position
pos
)
{
return
pos
.
getX
()
<=
max
.
getX
()
&&
pos
.
getX
()
>=
min
.
getX
()
&&
pos
.
getZ
()
<=
max
.
getZ
()
&&
pos
.
getZ
()
>=
min
.
getZ
();
}
}
public
SceneBlock
load
(
int
sceneId
,
Bindings
bindings
){
if
(
loaded
){
return
this
;
}
this
.
sceneId
=
sceneId
;
setLoaded
(
true
);
CompiledScript
cs
=
ScriptLoader
.
getScriptByPath
(
SCRIPT
(
"Scene/"
+
sceneId
+
"/scene"
+
sceneId
+
"_block"
+
id
+
"."
+
ScriptLoader
.
getScriptType
()));
if
(
cs
==
null
)
{
return
null
;
}
// Eval script
try
{
cs
.
eval
(
bindings
);
// Set groups
groups
=
ScriptLoader
.
getSerializer
().
toList
(
SceneGroup
.
class
,
bindings
.
get
(
"groups"
)).
stream
()
.
collect
(
Collectors
.
toMap
(
x
->
x
.
id
,
y
->
y
));
groups
.
values
().
forEach
(
g
->
g
.
block_id
=
id
);
this
.
sceneGroupIndex
=
SceneIndexManager
.
buildIndex
(
3
,
groups
.
values
(),
g
->
g
.
pos
.
toPoint
());
}
catch
(
ScriptException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading block "
+
id
+
" in scene "
+
sceneId
,
e
);
}
Grasscutter
.
getLogger
().
info
(
"scene {} block {} is loaded successfully."
,
sceneId
,
id
);
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/SceneBossChest.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.scripts.data
;
import
lombok.Setter
;
import
lombok.ToString
;
@Setter
@ToString
public
class
SceneBossChest
{
public
int
life_time
;
public
int
monster_config_id
;
public
int
resin
;
public
int
take_num
;
}
src/main/java/emu/grasscutter/scripts/data/SceneBusiness.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.scripts.data
;
import
lombok.Setter
;
import
lombok.ToString
;
@ToString
@Setter
public
class
SceneBusiness
{
public
int
type
;
}
src/main/java/emu/grasscutter/scripts/data/SceneConfig.java
View file @
30c7bb94
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 @
30c7bb94
package
emu.grasscutter.scripts.data
;
import
emu.grasscutter.utils.Position
;
import
lombok.Setter
;
import
lombok.ToString
;
public
class
SceneGadget
{
public
int
level
;
public
int
config_id
;
@ToString
@Setter
public
class
SceneGadget
extends
SceneObject
{
public
int
gadget_id
;
public
int
state
;
public
Position
pos
;
public
Position
rot
;
public
int
point_type
;
public
SceneBossChest
boss_chest
;
public
int
interact_id
;
}
src/main/java/emu/grasscutter/scripts/data/SceneGarbage.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.scripts.data
;
import
java.util.List
;
import
lombok.Setter
;
import
lombok.ToString
;
@ToString
@Setter
public
class
SceneGarbage
{
public
List
<
SceneGadget
>
gadgets
;
}
src/main/java/emu/grasscutter/scripts/data/SceneGroup.java
View file @
30c7bb94
package
emu.grasscutter.scripts.data
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.scripts.ScriptLoader
;
import
emu.grasscutter.utils.Position
;
import
lombok.Setter
;
import
lombok.ToString
;
import
javax.script.Bindings
;
import
javax.script.CompiledScript
;
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.Map
;
import
java.util.stream.Collectors
;
import
static
emu
.
grasscutter
.
Configuration
.
SCRIPT
;
@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
...
...
@@ -12,27 +29,140 @@ public class SceneGroup {
public
int
refresh_id
;
public
Position
pos
;
/**
* ConfigId - Monster
*/
public
Map
<
Integer
,
SceneMonster
>
monsters
;
public
List
<
SceneGadget
>
gadgets
;
public
List
<
SceneTrigger
>
triggers
;
public
Map
<
Integer
,
SceneMonster
>
monsters
;
// <ConfigId, Monster>
public
Map
<
Integer
,
SceneGadget
>
gadgets
;
// <ConfigId, Gadgets>
public
Map
<
String
,
SceneTrigger
>
triggers
;
public
Map
<
Integer
,
SceneNPC
>
npc
;
// <NpcId, NPC>
public
List
<
SceneRegion
>
regions
;
public
List
<
SceneSuite
>
suites
;
public
SceneInitConfig
init_config
;
public
List
<
SceneVar
>
variables
;
private
transient
boolean
isLoaded
;
// Not an actual variable in the scripts either
public
SceneBusiness
business
;
public
SceneGarbage
garbages
;
public
SceneInitConfig
init_config
;
private
transient
boolean
loaded
;
// Not an actual variable in the scripts either
private
transient
CompiledScript
script
;
private
transient
Bindings
bindings
;
public
static
SceneGroup
of
(
int
groupId
)
{
var
group
=
new
SceneGroup
();
group
.
id
=
groupId
;
return
group
;
}
public
boolean
isLoaded
()
{
return
isL
oaded
;
return
l
oaded
;
}
public
boolean
setLoaded
(
boolean
loaded
)
{
return
loaded
;
public
void
setLoaded
(
boolean
loaded
)
{
this
.
loaded
=
loaded
;
}
public
int
getBusinessType
()
{
return
this
.
business
==
null
?
0
:
this
.
business
.
type
;
}
public
List
<
SceneGadget
>
getGarbageGadgets
()
{
return
this
.
garbages
==
null
?
null
:
this
.
garbages
.
gadgets
;
}
public
CompiledScript
getScript
()
{
return
script
;
}
public
SceneSuite
getSuiteByIndex
(
int
index
)
{
return
suites
.
get
(
index
-
1
);
}
public
Bindings
getBindings
()
{
return
bindings
;
}
public
synchronized
SceneGroup
load
(
int
sceneId
){
if
(
loaded
){
return
this
;
}
// Set flag here so if there is no script, we dont call this function over and over again.
setLoaded
(
true
);
this
.
bindings
=
ScriptLoader
.
getEngine
().
createBindings
();
CompiledScript
cs
=
ScriptLoader
.
getScriptByPath
(
SCRIPT
(
"Scene/"
+
sceneId
+
"/scene"
+
sceneId
+
"_group"
+
id
+
"."
+
ScriptLoader
.
getScriptType
()));
if
(
cs
==
null
)
{
return
this
;
}
this
.
script
=
cs
;
// Eval script
try
{
cs
.
eval
(
bindings
);
// Set
monsters
=
ScriptLoader
.
getSerializer
().
toList
(
SceneMonster
.
class
,
bindings
.
get
(
"monsters"
)).
stream
()
.
collect
(
Collectors
.
toMap
(
x
->
x
.
config_id
,
y
->
y
));
monsters
.
values
().
forEach
(
m
->
m
.
group
=
this
);
gadgets
=
ScriptLoader
.
getSerializer
().
toList
(
SceneGadget
.
class
,
bindings
.
get
(
"gadgets"
)).
stream
()
.
collect
(
Collectors
.
toMap
(
x
->
x
.
config_id
,
y
->
y
));
gadgets
.
values
().
forEach
(
m
->
m
.
group
=
this
);
triggers
=
ScriptLoader
.
getSerializer
().
toList
(
SceneTrigger
.
class
,
bindings
.
get
(
"triggers"
)).
stream
()
.
collect
(
Collectors
.
toMap
(
x
->
x
.
name
,
y
->
y
));
triggers
.
values
().
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"
));
// Garbages TODO fix properly later
Object
garbagesValue
=
bindings
.
get
(
"garbages"
);
if
(
garbagesValue
!=
null
&&
garbagesValue
instanceof
LuaValue
garbagesTable
)
{
garbages
=
new
SceneGarbage
();
if
(
garbagesTable
.
checktable
().
get
(
"gadgets"
)
!=
LuaValue
.
NIL
)
{
garbages
.
gadgets
=
ScriptLoader
.
getSerializer
().
toList
(
SceneGadget
.
class
,
garbagesTable
.
checktable
().
get
(
"gadgets"
).
checktable
());
garbages
.
gadgets
.
forEach
(
m
->
m
.
group
=
this
);
}
}
// Add variables to suite
variables
=
ScriptLoader
.
getSerializer
().
toList
(
SceneVar
.
class
,
bindings
.
get
(
"variables"
));
// NPC in groups
npc
=
ScriptLoader
.
getSerializer
().
toList
(
SceneNPC
.
class
,
bindings
.
get
(
"npcs"
)).
stream
()
.
collect
(
Collectors
.
toMap
(
x
->
x
.
npc_id
,
y
->
y
));
npc
.
values
().
forEach
(
n
->
n
.
group
=
this
);
// Add monsters and gadgets to suite
for
(
SceneSuite
suite
:
suites
)
{
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
()
);
suite
.
sceneTriggers
=
new
ArrayList
<>(
suite
.
triggers
.
stream
()
.
filter
(
triggers:
:
containsKey
)
.
map
(
triggers:
:
get
)
.
toList
()
);
}
}
catch
(
ScriptException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error loading group "
+
id
+
" in scene "
+
sceneId
,
e
);
}
Grasscutter
.
getLogger
().
info
(
"group {} in scene {} is loaded successfully."
,
id
,
sceneId
);
return
this
;
}
}
src/main/java/emu/grasscutter/scripts/data/SceneInitConfig.java
View file @
30c7bb94
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
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.scripts.data
;
import
com.github.davidmoten.rtreemulti.RTree
;
import
com.github.davidmoten.rtreemulti.geometry.Geometry
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.scripts.SceneIndexManager
;
import
emu.grasscutter.scripts.ScriptLoader
;
import
lombok.Setter
;
import
lombok.ToString
;
import
javax.script.Bindings
;
import
javax.script.CompiledScript
;
import
javax.script.ScriptException
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.stream.Collectors
;
import
static
emu
.
grasscutter
.
Configuration
.
SCRIPT
;
@ToString
@Setter
public
class
SceneMeta
{
public
SceneConfig
config
;
public
Map
<
Integer
,
SceneBlock
>
blocks
;
public
Bindings
context
;
public
RTree
<
SceneBlock
,
Geometry
>
sceneBlockIndex
;
public
static
SceneMeta
of
(
int
sceneId
)
{
return
new
SceneMeta
().
load
(
sceneId
);
}
public
SceneMeta
load
(
int
sceneId
){
// Get compiled script if cached
CompiledScript
cs
=
ScriptLoader
.
getScriptByPath
(
SCRIPT
(
"Scene/"
+
sceneId
+
"/scene"
+
sceneId
+
"."
+
ScriptLoader
.
getScriptType
()));
if
(
cs
==
null
)
{
Grasscutter
.
getLogger
().
warn
(
"No script found for scene "
+
sceneId
);
return
null
;
}
// Create bindings
context
=
ScriptLoader
.
getEngine
().
createBindings
();
// Eval script
try
{
cs
.
eval
(
context
);
this
.
config
=
ScriptLoader
.
getSerializer
().
toObject
(
SceneConfig
.
class
,
context
.
get
(
"scene_config"
));
// TODO optimize later
// Create blocks
List
<
Integer
>
blockIds
=
ScriptLoader
.
getSerializer
().
toList
(
Integer
.
class
,
context
.
get
(
"blocks"
));
List
<
SceneBlock
>
blocks
=
ScriptLoader
.
getSerializer
().
toList
(
SceneBlock
.
class
,
context
.
get
(
"block_rects"
));
for
(
int
i
=
0
;
i
<
blocks
.
size
();
i
++)
{
SceneBlock
block
=
blocks
.
get
(
i
);
block
.
id
=
blockIds
.
get
(
i
);
}
this
.
blocks
=
blocks
.
stream
().
collect
(
Collectors
.
toMap
(
b
->
b
.
id
,
b
->
b
));
this
.
sceneBlockIndex
=
SceneIndexManager
.
buildIndex
(
2
,
blocks
,
SceneBlock:
:
toRectangle
);
}
catch
(
ScriptException
e
)
{
Grasscutter
.
getLogger
().
error
(
"Error running script"
,
e
);
return
null
;
}
Grasscutter
.
getLogger
().
info
(
"scene {} metadata is loaded successfully."
,
sceneId
);
return
this
;
}
}
src/main/java/emu/grasscutter/scripts/data/SceneMonster.java
View file @
30c7bb94
package
emu.grasscutter.scripts.data
;
import
emu.grasscutter.utils.Position
;
import
lombok.Setter
;
import
lombok.ToString
;
public
class
SceneMonster
{
public
int
level
;
public
int
config_id
;
@ToString
@Setter
public
class
SceneMonster
extends
SceneObject
{
public
int
monster_id
;
public
Position
pos
;
public
Position
rot
;
}
public
int
pose_id
;
public
int
drop_id
;
}
\ No newline at end of file
src/main/java/emu/grasscutter/scripts/data/SceneNPC.java
0 → 100644
View file @
30c7bb94
package
emu.grasscutter.scripts.data
;
import
lombok.Setter
;
import
lombok.ToString
;
@ToString
@Setter
public
class
SceneNPC
extends
SceneObject
{
public
int
npc_id
;
}
\ No newline at end of file
src/main/java/emu/grasscutter/scripts/data/SceneObject.java
0 → 100644
View file @
30c7bb94
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
;
public
int
area_id
;
public
Position
pos
;
public
Position
rot
;
/**
* not set by lua
*/
public
transient
SceneGroup
group
;
}
src/main/java/emu/grasscutter/scripts/data/SceneRegion.java
View file @
30c7bb94
...
...
@@ -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 @
30c7bb94
...
...
@@ -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
;
...
...
@@ -12,4 +15,5 @@ public class SceneSuite {
public
transient
List
<
SceneMonster
>
sceneMonsters
;
public
transient
List
<
SceneGadget
>
sceneGadgets
;
public
transient
List
<
SceneTrigger
>
sceneTriggers
;
}
src/main/java/emu/grasscutter/scripts/data/SceneTrigger.java
View file @
30c7bb94
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
transient
SceneGroup
currentGroup
;
@Override
public
boolean
equals
(
Object
obj
)
{
if
(
obj
instanceof
SceneTrigger
sceneTrigger
){
...
...
src/main/java/emu/grasscutter/scripts/data/SceneVar.java
View file @
30c7bb94
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 @
30c7bb94
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
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.scripts.ScriptUtils
;
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.lang.reflect.ParameterizedType
;
import
java.lang.reflect.Type
;
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 +34,11 @@ 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
<>();
if
(
table
==
null
)
{
return
list
;
}
try
{
LuaValue
[]
keys
=
table
.
keys
();
...
...
@@ -55,7 +73,7 @@ public class LuaSerializer implements Serializer {
return
list
;
}
public
<
T
>
T
serialize
(
Class
<
T
>
type
,
LuaTable
table
)
{
T
object
=
null
;
...
...
@@ -70,27 +88,38 @@ public class LuaSerializer implements Serializer {
}
try
{
//noinspection ConfusingArgumentToVarargsMethod
object
=
type
.
getDeclaredConstructor
().
newInstance
();
if
(!
methodAccessCache
.
containsKey
(
type
))
{
cacheType
(
type
);
}
var
methodAccess
=
methodAccessCache
.
get
(
type
);
var
fieldMetaMap
=
fieldMetaCache
.
get
(
type
);
object
=
(
T
)
constructorCache
.
get
(
type
).
newInstance
();
if
(
table
==
null
)
{
return
object
;
}
LuaValue
[]
keys
=
table
.
keys
();
for
(
LuaValue
k
:
keys
)
{
try
{
Field
field
=
object
.
getClass
().
getDeclaredField
(
k
.
checkjstring
());
field
.
setAccessible
(
true
);
var
keyName
=
k
.
checkjstring
();
if
(!
fieldMetaMap
.
containsKey
(
keyName
)){
continue
;
}
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();
...
...
@@ -98,9 +127,64 @@ public class LuaSerializer implements Serializer {
}
}
}
catch
(
Exception
e
)
{
Grasscutter
.
getLogger
().
info
(
ScriptUtils
.
toMap
(
table
).
toString
());
e
.
printStackTrace
();
}
return
object
;
}
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
;
}
}
src/main/java/emu/grasscutter/scripts/service/ScriptMonsterSpawnService.java
View file @
30c7bb94
...
...
@@ -16,9 +16,9 @@ import java.util.List;
public
class
ScriptMonsterSpawnService
{
private
final
SceneScriptManager
sceneScriptManager
;
p
rivate
final
List
<
ScriptMonsterListener
>
onMonsterCreatedListener
=
new
ArrayList
<>();
p
ublic
final
List
<
ScriptMonsterListener
>
onMonsterCreatedListener
=
new
ArrayList
<>();
p
rivate
final
List
<
ScriptMonsterListener
>
onMonsterDeadListener
=
new
ArrayList
<>();
p
ublic
final
List
<
ScriptMonsterListener
>
onMonsterDeadListener
=
new
ArrayList
<>();
public
ScriptMonsterSpawnService
(
SceneScriptManager
sceneScriptManager
){
this
.
sceneScriptManager
=
sceneScriptManager
;
...
...
@@ -39,40 +39,5 @@ public class ScriptMonsterSpawnService {
public
void
onMonsterDead
(
EntityMonster
entityMonster
){
onMonsterDeadListener
.
forEach
(
l
->
l
.
onNotify
(
entityMonster
));
}
public
void
spawnMonster
(
int
groupId
,
SceneMonster
monster
)
{
if
(
monster
==
null
){
return
;
}
MonsterData
data
=
GameData
.
getMonsterDataMap
().
get
(
monster
.
monster_id
);
if
(
data
==
null
)
{
return
;
}
// Calculate level
int
level
=
monster
.
level
;
if
(
sceneScriptManager
.
getScene
().
getDungeonData
()
!=
null
)
{
level
=
sceneScriptManager
.
getScene
().
getDungeonData
().
getShowLevel
();
}
else
if
(
sceneScriptManager
.
getScene
().
getWorld
().
getWorldLevel
()
>
0
)
{
WorldLevelData
worldLevelData
=
GameData
.
getWorldLevelDataMap
().
get
(
sceneScriptManager
.
getScene
().
getWorld
().
getWorldLevel
());
if
(
worldLevelData
!=
null
)
{
level
=
worldLevelData
.
getMonsterLevel
();
}
}
// Spawn mob
EntityMonster
entity
=
new
EntityMonster
(
sceneScriptManager
.
getScene
(),
data
,
monster
.
pos
,
level
);
entity
.
getRotation
().
set
(
monster
.
rot
);
entity
.
setGroupId
(
groupId
);
entity
.
setConfigId
(
monster
.
config_id
);
onMonsterCreatedListener
.
forEach
(
action
->
action
.
onNotify
(
entity
));
sceneScriptManager
.
getScene
().
addEntity
(
entity
);
sceneScriptManager
.
callEvent
(
EventType
.
EVENT_ANY_MONSTER_LIVE
,
new
ScriptArgs
(
entity
.
getConfigId
()));
}
}
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