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
b8614d63
Commit
b8614d63
authored
Apr 25, 2022
by
Melledy
Browse files
Natural spawn test
(without luas)
parent
d9e1ed50
Changes
11
Hide whitespace changes
Inline
Side-by-side
build.gradle
View file @
b8614d63
...
...
@@ -37,6 +37,7 @@ dependencies {
implementation
group:
'dev.morphia.morphia'
,
name:
'morphia-core'
,
version:
'2.2.6'
implementation
group:
'org.greenrobot'
,
name:
'eventbus-java'
,
version:
'3.3.1'
implementation
group:
'org.danilopianini'
,
name:
'java-quadtree'
,
version:
'0.1.9'
}
application
{
...
...
data/Spawns.json
0 → 100644
View file @
b8614d63
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/main/java/emu/grasscutter/data/GenshinDepot.java
View file @
b8614d63
...
...
@@ -3,9 +3,14 @@ package emu.grasscutter.data;
import
java.util.ArrayList
;
import
java.util.List
;
import
org.danilopianini.util.FlexibleQuadTree
;
import
org.danilopianini.util.SpatialIndex
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.def.ReliquaryAffixData
;
import
emu.grasscutter.data.def.ReliquaryMainPropData
;
import
emu.grasscutter.game.world.SpawnDataEntry
;
import
emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry
;
import
emu.grasscutter.utils.WeightedList
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
...
...
@@ -14,6 +19,8 @@ public class GenshinDepot {
private
static
Int2ObjectMap
<
WeightedList
<
ReliquaryMainPropData
>>
relicMainPropDepot
=
new
Int2ObjectOpenHashMap
<>();
private
static
Int2ObjectMap
<
List
<
ReliquaryAffixData
>>
relicAffixDepot
=
new
Int2ObjectOpenHashMap
<>();
private
static
Int2ObjectMap
<
SpatialIndex
<
SpawnGroupEntry
>>
spawnLists
=
new
Int2ObjectOpenHashMap
<>();
public
static
void
load
()
{
for
(
ReliquaryMainPropData
data
:
GenshinData
.
getReliquaryMainPropDataMap
().
values
())
{
if
(
data
.
getWeight
()
<=
0
||
data
.
getPropDepotId
()
<=
0
)
{
...
...
@@ -46,4 +53,12 @@ public class GenshinDepot {
public
static
List
<
ReliquaryAffixData
>
getRandomRelicAffixList
(
int
depot
)
{
return
relicAffixDepot
.
get
(
depot
);
}
public
static
Int2ObjectMap
<
SpatialIndex
<
SpawnGroupEntry
>>
getSpawnLists
()
{
return
spawnLists
;
}
public
static
SpatialIndex
<
SpawnGroupEntry
>
getSpawnListById
(
int
sceneId
)
{
return
getSpawnLists
().
computeIfAbsent
(
sceneId
,
id
->
new
FlexibleQuadTree
<>());
}
}
src/main/java/emu/grasscutter/data/ResourceLoader.java
View file @
b8614d63
...
...
@@ -19,6 +19,8 @@ import emu.grasscutter.data.common.ScenePointConfig;
import
emu.grasscutter.data.custom.AbilityEmbryoEntry
;
import
emu.grasscutter.data.custom.OpenConfigEntry
;
import
emu.grasscutter.data.custom.ScenePointEntry
;
import
emu.grasscutter.game.world.SpawnDataEntry
;
import
emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
public
class
ResourceLoader
{
...
...
@@ -49,6 +51,8 @@ public class ResourceLoader {
loadScenePoints
();
// Process into depots
GenshinDepot
.
load
();
// Load spawn data
loadSpawnData
();
// Custom - TODO move this somewhere else
try
{
GenshinData
.
getAvatarSkillDepotDataMap
().
get
(
504
).
setAbilities
(
...
...
@@ -233,6 +237,33 @@ public class ResourceLoader {
}
}
private
static
void
loadSpawnData
()
{
// Read from cached file if exists
File
spawnDataEntries
=
new
File
(
Grasscutter
.
getConfig
().
DATA_FOLDER
+
"Spawns.json"
);
List
<
SpawnGroupEntry
>
spawnEntryList
=
null
;
if
(
spawnDataEntries
.
exists
())
{
// Load from cache
try
(
FileReader
fileReader
=
new
FileReader
(
spawnDataEntries
))
{
spawnEntryList
=
Grasscutter
.
getGsonFactory
().
fromJson
(
fileReader
,
TypeToken
.
getParameterized
(
Collection
.
class
,
SpawnGroupEntry
.
class
).
getType
());
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
if
(
spawnEntryList
==
null
||
spawnEntryList
.
isEmpty
())
{
Grasscutter
.
getLogger
().
error
(
"No spawn data loaded!"
);
return
;
}
for
(
SpawnGroupEntry
entry
:
spawnEntryList
)
{
entry
.
getSpawns
().
stream
().
forEach
(
s
->
{
s
.
setGroup
(
entry
);
});
GenshinDepot
.
getSpawnListById
(
entry
.
getSceneId
()).
insert
(
entry
,
entry
.
getPos
().
getX
(),
entry
.
getPos
().
getZ
());
}
}
private
static
void
loadOpenConfig
()
{
// Read from cached file if exists
File
openConfigCache
=
new
File
(
Grasscutter
.
getConfig
().
DATA_FOLDER
+
"OpenConfig.json"
);
...
...
src/main/java/emu/grasscutter/game/GenshinPlayer.java
View file @
b8614d63
...
...
@@ -195,11 +195,11 @@ public class GenshinPlayer {
this
.
world
=
world
;
}
public
GenshinScene
getScene
()
{
public
synchronized
GenshinScene
getScene
()
{
return
scene
;
}
public
void
setScene
(
GenshinScene
scene
)
{
public
synchronized
void
setScene
(
GenshinScene
scene
)
{
this
.
scene
=
scene
;
}
...
...
@@ -695,6 +695,10 @@ public class GenshinPlayer {
it
.
remove
();
}
}
//
if
(
this
.
getScene
()
!=
null
&&
this
.
getSceneLoadState
()
==
SceneLoadState
.
LOADED
)
{
this
.
getScene
().
checkSpawns
(
this
);
}
// Ping
if
(
this
.
getWorld
()
!=
null
)
{
// RTT notify - very important to send this often
...
...
src/main/java/emu/grasscutter/game/GenshinScene.java
View file @
b8614d63
...
...
@@ -3,19 +3,31 @@ package emu.grasscutter.game;
import
java.util.ArrayList
;
import
java.util.Collection
;
import
java.util.Collections
;
import
java.util.HashSet
;
import
java.util.Iterator
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.Set
;
import
org.danilopianini.util.SpatialIndex
;
import
emu.grasscutter.Grasscutter
;
import
emu.grasscutter.data.GenshinData
;
import
emu.grasscutter.data.GenshinDepot
;
import
emu.grasscutter.data.GenshinResource
;
import
emu.grasscutter.data.def.MonsterData
;
import
emu.grasscutter.data.def.SceneData
;
import
emu.grasscutter.game.entity.EntityAvatar
;
import
emu.grasscutter.game.entity.EntityClientGadget
;
import
emu.grasscutter.game.entity.EntityGadget
;
import
emu.grasscutter.game.entity.EntityMonster
;
import
emu.grasscutter.game.entity.GenshinEntity
;
import
emu.grasscutter.game.props.ClimateType
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.game.props.SceneType
;
import
emu.grasscutter.game.world.SpawnDataEntry
;
import
emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry
;
import
emu.grasscutter.net.packet.GenshinPacket
;
import
emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult
;
import
emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType
;
...
...
@@ -23,6 +35,7 @@ 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.utils.Utils
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectMap
;
import
it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
;
...
...
@@ -32,6 +45,9 @@ public class GenshinScene {
private
final
List
<
GenshinPlayer
>
players
;
private
final
Int2ObjectMap
<
GenshinEntity
>
entities
;
private
final
Set
<
SpawnDataEntry
>
spawnedEntities
;
private
final
Set
<
SpawnDataEntry
>
deadSpawnedEntities
;
private
int
time
;
private
ClimateType
climate
;
private
int
weather
;
...
...
@@ -44,6 +60,9 @@ public class GenshinScene {
this
.
time
=
8
*
60
;
this
.
climate
=
ClimateType
.
CLIMATE_SUNNY
;
this
.
spawnedEntities
=
new
HashSet
<>();
this
.
deadSpawnedEntities
=
new
HashSet
<>();
}
public
int
getId
()
{
...
...
@@ -102,6 +121,14 @@ public class GenshinScene {
this
.
weather
=
weather
;
}
public
Set
<
SpawnDataEntry
>
getSpawnedEntities
()
{
return
spawnedEntities
;
}
public
Set
<
SpawnDataEntry
>
getDeadSpawnedEntities
()
{
return
deadSpawnedEntities
;
}
public
boolean
isInScene
(
GenshinEntity
entity
)
{
return
this
.
entities
.
containsKey
(
entity
.
getId
());
}
...
...
@@ -277,6 +304,73 @@ public class GenshinScene {
target
.
onDeath
(
attackerId
);
}
// TODO Do not use yet
public
synchronized
void
onTick
()
{
for
(
GenshinPlayer
player
:
this
.
getPlayers
())
{
this
.
checkSpawns
(
player
);
}
}
// TODO - Test
public
void
checkSpawns
(
GenshinPlayer
player
)
{
SpatialIndex
<
SpawnGroupEntry
>
list
=
GenshinDepot
.
getSpawnListById
(
this
.
getId
());
Set
<
SpawnDataEntry
>
visible
=
new
HashSet
<>();
int
RANGE
=
100
;
Collection
<
SpawnGroupEntry
>
entries
=
list
.
query
(
new
double
[]
{
player
.
getPos
().
getX
()
-
RANGE
,
player
.
getPos
().
getZ
()
-
RANGE
},
new
double
[]
{
player
.
getPos
().
getX
()
+
RANGE
,
player
.
getPos
().
getZ
()
+
RANGE
}
);
for
(
SpawnGroupEntry
entry
:
entries
)
{
for
(
SpawnDataEntry
spawnData
:
entry
.
getSpawns
())
{
visible
.
add
(
spawnData
);
}
}
// Todo
List
<
GenshinEntity
>
toAdd
=
new
LinkedList
<>();
List
<
GenshinEntity
>
toRemove
=
new
LinkedList
<>();
for
(
SpawnDataEntry
entry
:
visible
)
{
if
(!
this
.
getSpawnedEntities
().
contains
(
entry
)
&&
!
this
.
getDeadSpawnedEntities
().
contains
(
entry
))
{
// Spawn entity
MonsterData
data
=
GenshinData
.
getMonsterDataMap
().
get
(
entry
.
getMonsterId
());
if
(
data
==
null
)
{
continue
;
}
EntityMonster
entity
=
new
EntityMonster
(
this
,
data
,
entry
.
getPos
(),
entry
.
getLevel
());
entity
.
getRotation
().
set
(
entry
.
getRot
());
entity
.
setGroupId
(
entry
.
getGroup
().
getGroupId
());
entity
.
setPoseId
(
entry
.
getPoseId
());
entity
.
setConfigId
(
entry
.
getConfigId
());
entity
.
setSpawnEntry
(
entry
);
toAdd
.
add
(
entity
);
this
.
addEntityDirectly
(
entity
);
// Add to spawned list
this
.
getSpawnedEntities
().
add
(
entry
);
}
}
for
(
GenshinEntity
entity
:
this
.
getEntities
().
values
())
{
if
(
entity
.
getSpawnEntry
()
!=
null
&&
!
visible
.
contains
(
entity
.
getSpawnEntry
()))
{
toRemove
.
add
(
entity
);
this
.
removeEntityDirectly
(
entity
);
}
}
if
(
toAdd
.
size
()
>
0
)
{
this
.
broadcastPacket
(
new
PacketSceneEntityAppearNotify
(
toAdd
,
VisionType
.
VisionBorn
));
}
if
(
toRemove
.
size
()
>
0
)
{
this
.
broadcastPacket
(
new
PacketSceneEntityDisappearNotify
(
toRemove
,
VisionType
.
VisionRemove
));
}
}
// Gadgets
public
void
onPlayerCreateGadget
(
EntityClientGadget
gadget
)
{
...
...
src/main/java/emu/grasscutter/game/entity/EntityMonster.java
View file @
b8614d63
...
...
@@ -37,6 +37,10 @@ public class EntityMonster extends GenshinEntity {
private
final
int
level
;
private
int
weaponEntityId
;
private
int
groupId
;
private
int
configId
;
private
int
poseId
;
public
EntityMonster
(
GenshinScene
scene
,
MonsterData
monsterData
,
Position
pos
,
int
level
)
{
super
(
scene
);
this
.
id
=
getWorld
().
getNextEntityId
(
EntityIdType
.
MONSTER
);
...
...
@@ -100,9 +104,35 @@ public class EntityMonster extends GenshinEntity {
return
this
.
getFightProperty
(
FightProperty
.
FIGHT_PROP_CUR_HP
)
>
0
f
;
}
public
int
getGroupId
()
{
return
groupId
;
}
public
void
setGroupId
(
int
groupId
)
{
this
.
groupId
=
groupId
;
}
public
int
getConfigId
()
{
return
configId
;
}
public
void
setConfigId
(
int
configId
)
{
this
.
configId
=
configId
;
}
public
int
getPoseId
()
{
return
poseId
;
}
public
void
setPoseId
(
int
poseId
)
{
this
.
poseId
=
poseId
;
}
@Override
public
void
onDeath
(
int
killerId
)
{
if
(
this
.
getSpawnEntry
()
!=
null
)
{
this
.
getScene
().
getDeadSpawnedEntities
().
add
(
getSpawnEntry
());
}
}
public
void
recalcStats
()
{
...
...
@@ -190,11 +220,11 @@ public class EntityMonster extends GenshinEntity {
SceneMonsterInfo
.
Builder
monsterInfo
=
SceneMonsterInfo
.
newBuilder
()
.
setMonsterId
(
getMonsterId
())
.
setGroupId
(
133003095
)
.
setConfigId
(
95001
)
.
setGroupId
(
this
.
getGroupId
()
)
.
setConfigId
(
this
.
getConfigId
()
)
.
addAllAffixList
(
getMonsterData
().
getAffix
())
.
setAuthorityPeerId
(
getWorld
().
getHostPeerId
())
.
setPoseId
(
0
)
.
setPoseId
(
this
.
getPoseId
()
)
.
setBlockId
(
3001
)
.
setBornType
(
MonsterBornType
.
MonsterBornDefault
)
.
setSpecialNameId
(
40
);
...
...
src/main/java/emu/grasscutter/game/entity/GenshinEntity.java
View file @
b8614d63
...
...
@@ -4,6 +4,7 @@ import emu.grasscutter.game.GenshinScene;
import
emu.grasscutter.game.World
;
import
emu.grasscutter.game.props.FightProperty
;
import
emu.grasscutter.game.props.LifeState
;
import
emu.grasscutter.game.world.SpawnDataEntry
;
import
emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo
;
import
emu.grasscutter.net.proto.MotionStateOuterClass.MotionState
;
import
emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo
;
...
...
@@ -14,6 +15,7 @@ import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap;
public
abstract
class
GenshinEntity
{
protected
int
id
;
private
final
GenshinScene
scene
;
private
SpawnDataEntry
spawnEntry
;
private
MotionState
moveState
;
private
int
lastMoveSceneTimeMs
;
...
...
@@ -104,4 +106,12 @@ public abstract class GenshinEntity {
return
proto
;
}
public
SpawnDataEntry
getSpawnEntry
()
{
return
spawnEntry
;
}
public
void
setSpawnEntry
(
SpawnDataEntry
spawnEntry
)
{
this
.
spawnEntry
=
spawnEntry
;
}
}
src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java
0 → 100644
View file @
b8614d63
package
emu.grasscutter.game.world
;
import
java.util.ArrayList
;
import
java.util.List
;
import
emu.grasscutter.utils.Position
;
public
class
SpawnDataEntry
{
private
transient
SpawnGroupEntry
group
;
private
int
monsterId
;
private
int
configId
;
private
int
level
;
private
int
poseId
;
private
Position
pos
;
private
Position
rot
;
public
SpawnGroupEntry
getGroup
()
{
return
group
;
}
public
void
setGroup
(
SpawnGroupEntry
group
)
{
this
.
group
=
group
;
}
public
int
getMonsterId
()
{
return
monsterId
;
}
public
int
getConfigId
()
{
return
configId
;
}
public
int
getLevel
()
{
return
level
;
}
public
int
getPoseId
()
{
return
poseId
;
}
public
Position
getPos
()
{
return
pos
;
}
public
Position
getRot
()
{
return
rot
;
}
public
static
class
SpawnGroupEntry
{
private
int
sceneId
;
private
int
groupId
;
private
int
blockId
;
private
Position
pos
;
private
List
<
SpawnDataEntry
>
spawns
;
public
int
getSceneId
()
{
return
sceneId
;
}
public
int
getGroupId
()
{
return
groupId
;
}
public
int
getBlockId
()
{
return
blockId
;
}
public
void
setBlockId
(
int
blockId
)
{
this
.
blockId
=
blockId
;
}
public
Position
getPos
()
{
return
pos
;
}
public
List
<
SpawnDataEntry
>
getSpawns
()
{
return
spawns
;
}
}
}
src/main/java/emu/grasscutter/server/packet/send/PacketSceneEntityDisappearNotify.java
View file @
b8614d63
package
emu.grasscutter.server.packet.send
;
import
java.util.Collection
;
import
java.util.List
;
import
emu.grasscutter.game.entity.GenshinEntity
;
import
emu.grasscutter.net.packet.GenshinPacket
;
import
emu.grasscutter.net.packet.PacketOpcodes
;
...
...
@@ -18,4 +21,15 @@ public class PacketSceneEntityDisappearNotify extends GenshinPacket {
this
.
setData
(
proto
);
}
public
PacketSceneEntityDisappearNotify
(
Collection
<
GenshinEntity
>
entities
,
VisionType
disappearType
)
{
super
(
PacketOpcodes
.
SceneEntityDisappearNotify
);
SceneEntityDisappearNotify
.
Builder
proto
=
SceneEntityDisappearNotify
.
newBuilder
()
.
setDisappearType
(
disappearType
);
entities
.
forEach
(
e
->
proto
.
addEntityList
(
e
.
getId
()));
this
.
setData
(
proto
);
}
}
src/main/java/emu/grasscutter/utils/Utils.java
View file @
b8614d63
...
...
@@ -10,6 +10,7 @@ import emu.grasscutter.Grasscutter;
import
io.netty.buffer.ByteBuf
;
import
io.netty.buffer.ByteBufUtil
;
import
io.netty.buffer.Unpooled
;
import
org.slf4j.Logger
;
@SuppressWarnings
({
"UnusedReturnValue"
,
"BooleanMethodIsAlwaysInverted"
})
...
...
@@ -24,6 +25,19 @@ public final class Utils {
return
random
.
nextFloat
()
*
(
max
-
min
)
+
min
;
}
public
static
double
getDist
(
Position
pos1
,
Position
pos2
)
{
double
xs
=
pos1
.
getX
()
-
pos2
.
getX
();
xs
=
xs
*
xs
;
double
ys
=
pos1
.
getY
()
-
pos2
.
getY
();
ys
=
ys
*
ys
;
double
zs
=
pos1
.
getZ
()
-
pos2
.
getZ
();
zs
=
zs
*
zs
;
return
Math
.
sqrt
(
xs
+
zs
+
ys
);
}
public
static
int
getCurrentSeconds
()
{
return
(
int
)
(
System
.
currentTimeMillis
()
/
1000.0
);
}
...
...
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