Fix grid loading and use rtree for getNearbyGroups

This commit is contained in:
StartForKiller 2023-04-18 03:54:51 +02:00
parent a7f14a9cd8
commit e4c46c704e
No known key found for this signature in database
GPG Key ID: CE5EA6FC54AAB4F0
5 changed files with 40 additions and 42 deletions

View File

@ -87,7 +87,7 @@ public class ConfigContainer {
public String packets = "./packets/";
public String scripts = "resources:Scripts/";
public String plugins = "./plugins/";
public String cache = "./cache/";
public String cache = "./server/cache/";
// UNUSED (potentially added later?)
// public String dumps = "./dumps/";

View File

@ -1,49 +1,36 @@
package emu.grasscutter.data.server;
import java.util.*;
import java.util.Map.Entry;
import emu.grasscutter.Grasscutter;
import emu.grasscutter.scripts.SceneIndexManager;
import emu.grasscutter.utils.GridPosition;
import emu.grasscutter.utils.Position;
import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import com.github.davidmoten.rtreemulti.RTree;
import com.github.davidmoten.rtreemulti.geometry.Geometry;
import lombok.val;
public class Grid {
public Map<GridPosition, Set<Integer>> grid;
public Int2ObjectMap<Int2ObjectMap<Set<Integer>>> gridOptimized;
public transient RTree<Entry<GridPosition, Set<Integer>>, Geometry> gridOptimized = null;
private HashSet<Integer> nearbyGroups = new HashSet<>(100);
private transient HashSet<Integer> nearbyGroups = new HashSet<>(100);
private void Optimize() {
if(gridOptimized == null) {
gridOptimized = new Int2ObjectOpenHashMap<>();
List<Entry<GridPosition, Set<Integer>>> gridValues = new ArrayList<>();
grid.forEach((k, v) -> {
int x = k.getX() & 0xFFFF;
int z = k.getZ() & 0xFFFF;
if(!gridOptimized.containsKey(x)) {
gridOptimized.put(x, new Int2ObjectOpenHashMap<>());
gridOptimized.get(x).put(z, v);
} else {
val zG = gridOptimized.get(x);
if(!zG.containsKey(z)) {
zG.put(z, v);
} else {
zG.get(z).addAll(v);
}
}
gridValues.add(new AbstractMap.SimpleEntry<>(k, v));
});
gridOptimized = SceneIndexManager.buildIndex(2, gridValues, entry -> entry.getKey().toPoint());
}
}
public Set<Integer> GetGroup(GridPosition pos) {
int x = pos.getX() & 0xFFFF;
int z = pos.getZ() & 0xFFFF;
if(!gridOptimized.containsKey(x)) return new HashSet<>();
val xG = gridOptimized.get(x);
if(!xG.containsKey(z)) return new HashSet<>();
return xG.get(z);
}
public Set<Integer> getNearbyGroups(int vision_level, Position position) {
@ -56,19 +43,18 @@ public class Grid {
GridPosition pos = new GridPosition(position, width);
nearbyGroups.clear();
//construct a nearby pisition list, add 1 more because a player can be in an edge case, this should not affect much the loading
for(int x = 0; x < vision_range_grid + 1; x++) {
for(int z = 0; z < vision_range_grid + 1; z++) {
nearbyGroups.addAll(GetGroup(pos.addClone( x, z)));
nearbyGroups.addAll(GetGroup(pos.addClone(-x, z)));
nearbyGroups.addAll(GetGroup(pos.addClone( x, -z)));
nearbyGroups.addAll(GetGroup(pos.addClone(-x, -z)));
//nearbyGroups.addAll(grid.getOrDefault(pos.addClone( x, z), new HashSet<>()));
//nearbyGroups.addAll(grid.getOrDefault(pos.addClone(-x, z), new HashSet<>()));
//nearbyGroups.addAll(grid.getOrDefault(pos.addClone( x, -z), new HashSet<>()));
//nearbyGroups.addAll(grid.getOrDefault(pos.addClone(-x, -z), new HashSet<>()));
}
}
//construct a nearby position list, add 1 more because a player can be in an edge case, this should not affect much the loading
//for(int x = 0; x < vision_range_grid + 1; x++) {
// for(int z = 0; z < vision_range_grid + 1; z++) {
// //nearbyGroups.addAll(grid.getOrDefault(pos.addClone( x, z), new HashSet<>()));
// //nearbyGroups.addAll(grid.getOrDefault(pos.addClone(-x, z), new HashSet<>()));
// //nearbyGroups.addAll(grid.getOrDefault(pos.addClone( x, -z), new HashSet<>()));
// //nearbyGroups.addAll(grid.getOrDefault(pos.addClone(-x, -z), new HashSet<>()));
// }
//}
//Optimized version
SceneIndexManager.queryNeighbors(gridOptimized, pos.toDoubleArray(), vision_range_grid + 1).forEach(e -> nearbyGroups.addAll(e.getValue()));
return nearbyGroups;
}

View File

@ -390,16 +390,16 @@ public class SceneScriptManager {
public List<Grid> getGroupGrids() {
int sceneId = scene.getId();
if (groupGridsCache.containsKey(sceneId)) {
if (groupGridsCache.containsKey(sceneId) && groupGridsCache.get(sceneId) != null) {
Grasscutter.getLogger().debug("Hit cache for scene {}",sceneId);
return groupGridsCache.get(sceneId);
} else {
var path = FileUtils.getCachePath("Grids/scene" + sceneId + "_grid.json");
var path = FileUtils.getCachePath("scene" + sceneId + "_grid.json");
if (path.toFile().isFile() && !Grasscutter.config.server.game.cacheSceneEntitiesEveryRun) {
try {
var groupGrids = JsonUtils.loadToList(path, Grid.class);
groupGridsCache.put(sceneId, groupGrids);
return groupGrids;
if(groupGrids != null) return groupGrids;
} catch (IOException e) {
e.printStackTrace();
}

View File

@ -19,7 +19,7 @@ public final class FileUtils {
private static final Path DATA_USER_PATH = Path.of(Grasscutter.config.folderStructure.data);
private static final Path PACKETS_PATH = Path.of(Grasscutter.config.folderStructure.packets);
private static final Path PLUGINS_PATH = Path.of(Grasscutter.config.folderStructure.plugins);
private static final Path CACHE_PATH = Path.of(Grasscutter.config.folderStructure.cache);
private static final Path CACHE_PATH;
private static final Path RESOURCES_PATH;
private static final Path SCRIPTS_PATH;
static {
@ -87,6 +87,8 @@ public final class FileUtils {
SCRIPTS_PATH = (scripts.startsWith("resources:"))
? RESOURCES_PATH.resolve(scripts.substring("resources:".length()))
: Path.of(scripts);
CACHE_PATH = RESOURCES_PATH.resolve(Grasscutter.config.folderStructure.cache);
};
private static final String[] TSJ_JSON_TSV = {"tsj", "json", "tsv"};

View File

@ -4,6 +4,8 @@ import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import com.github.davidmoten.rtreemulti.geometry.Point;
import dev.morphia.annotations.Entity;
import lombok.Getter;
import lombok.Setter;
@ -90,10 +92,18 @@ public class GridPosition implements Serializable {
return new int[]{ x, z, width };
}
public double[] toDoubleArray() {
return new double[]{ x, z };
}
public int[] toXZIntArray() {
return new int[]{ x, z };
}
public Point toPoint() {
return Point.create(x,z);
}
@Override
public int hashCode()
{