Skip to content

Commit

Permalink
优化缓存领地搜索算法,提速300%
Browse files Browse the repository at this point in the history
  • Loading branch information
ColdeZhang committed Jul 17, 2024
1 parent 0fe7f28 commit b3934b9
Show file tree
Hide file tree
Showing 12 changed files with 175 additions and 99 deletions.
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

### [统计页面](https://bstats.org/plugin/bukkit/Dominion/21445) | [Hangar](https://hangar.papermc.io/zhangyuheng/Dominion)

[![CodeFactor](https://www.codefactor.io/repository/github/deergiteamirror/dominion/badge/master)](https://www.codefactor.io/repository/github/deergiteamirror/dominion/overview/master)

</div>

## 简介
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>cn.lunadeer</groupId>
<artifactId>Dominion</artifactId>
<version>1.36.1-beta</version>
<version>1.37.0-beta</version>
<packaging>jar</packaging>

<name>Dominion</name>
Expand Down
160 changes: 124 additions & 36 deletions src/main/java/cn/lunadeer/dominion/Cache.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;

import javax.annotation.Nullable;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

import static cn.lunadeer.dominion.DominionNode.getLocInDominionDTO;
import static cn.lunadeer.dominion.DominionNode.getLocInDominionNode;

public class Cache {

Expand Down Expand Up @@ -62,25 +64,21 @@ private void loadDominionsExecution(Integer idToLoad) {
int count = 0;
if (idToLoad == null) {
id_dominions = new ConcurrentHashMap<>();
world_dominion_tree = new ConcurrentHashMap<>();
dominion_children = new ConcurrentHashMap<>();

List<DominionDTO> dominions = DominionDTO.selectAll();
CompletableFuture<Void> res = dominion_trees.initAsync(dominions);
count = dominions.size();
Map<String, List<DominionDTO>> world_dominions = new HashMap<>();

for (DominionDTO d : dominions) {
if (!world_dominions.containsKey(d.getWorld())) {
world_dominions.put(d.getWorld(), new ArrayList<>());
}
world_dominions.get(d.getWorld()).add(d);
id_dominions.put(d.getId(), d);
if (!dominion_children.containsKey(d.getParentDomId())) {
dominion_children.put(d.getParentDomId(), new ArrayList<>());
}
dominion_children.get(d.getParentDomId()).add(d.getId());
}
for (Map.Entry<String, List<DominionDTO>> entry : world_dominions.entrySet()) {
world_dominion_tree.put(entry.getKey(), DominionNode.BuildNodeTree(-1, entry.getValue()));
}

res.join(); // 等待树的构建完成
} else {
DominionDTO dominion = DominionDTO.select(idToLoad);
if (dominion == null && id_dominions.containsKey(idToLoad)) {
Expand Down Expand Up @@ -225,7 +223,7 @@ public DominionDTO getPlayerCurrentDominion(Player player) {
return last_dominion;
}
}
DominionDTO current_dominion = getLocInDominionDTO(world_dominion_tree.get(player.getWorld().getName()), player.getLocation());
DominionDTO current_dominion = dominion_trees.getLocInDominionDTO(player.getLocation());
int last_dom_id = last_dominion == null ? -1 : last_dominion.getId();
int current_dom_id = current_dominion == null ? -1 : current_dominion.getId();
if (last_dom_id == current_dom_id) {
Expand Down Expand Up @@ -337,30 +335,8 @@ private void flyOrNot(Player player, DominionDTO dominion) {
}
}

public DominionDTO getDominion(Location loc) {
return getLocInDominionDTO(world_dominion_tree.get(loc.getWorld().getName()), loc);
}

public List<DominionNode> getDominionTreeByPlayer(String player_name) {
List<DominionNode> dominionTree = new ArrayList<>();
PlayerDTO player = PlayerDTO.select(player_name);
if (player == null) return dominionTree;
for (List<DominionNode> tree : world_dominion_tree.values()) {
for (DominionNode node : tree) {
if (node.getDominion().getOwner().equals(player.getUuid())) {
dominionTree.add(node);
}
}
}
return dominionTree;
}

public List<DominionNode> getAllDominionTree() {
List<DominionNode> dominionTree = new ArrayList<>();
for (List<DominionNode> tree : world_dominion_tree.values()) {
dominionTree.addAll(tree);
}
return dominionTree;
public DominionDTO getDominionByLoc(Location loc) {
return dominion_trees.getLocInDominionDTO(loc);
}

public GroupDTO getGroup(Integer id) {
Expand Down Expand Up @@ -451,8 +427,8 @@ public int getGroupCounts() {

public static Cache instance;
private ConcurrentHashMap<Integer, DominionDTO> id_dominions;
private ConcurrentHashMap<String, List<DominionNode>> world_dominion_tree;
private ConcurrentHashMap<Integer, GroupDTO> id_groups;
private final WorldDominionTreeSectored dominion_trees = new WorldDominionTreeSectored();
private ConcurrentHashMap<UUID, ConcurrentHashMap<Integer, MemberDTO>> player_uuid_to_member; // 玩家所有的特权
private final Map<UUID, Integer> player_current_dominion_id; // 玩家当前所在领地
private ConcurrentHashMap<Integer, List<Integer>> dominion_children;
Expand All @@ -467,4 +443,116 @@ public int getGroupCounts() {
public final Map<UUID, LocalDateTime> NextTimeAllowTeleport = new java.util.HashMap<>();

private Map<UUID, List<ResMigration.ResidenceNode>> residence_data = null;

private static class WorldDominionTreeSectored {
/*
D | C
--+--
B | A
*/

private ConcurrentHashMap<String, List<DominionNode>> world_dominion_tree_sector_a; // x >= 0, z >= 0
private ConcurrentHashMap<String, List<DominionNode>> world_dominion_tree_sector_b; // x <= 0, z >= 0
private ConcurrentHashMap<String, List<DominionNode>> world_dominion_tree_sector_c; // x >= 0, z <= 0
private ConcurrentHashMap<String, List<DominionNode>> world_dominion_tree_sector_d; // x <= 0, z <= 0

public DominionDTO getLocInDominionDTO(@NotNull Location loc) {
List<DominionNode> nodes = getNodes(loc);
if (nodes == null) return null;
if (nodes.isEmpty()) return null;
DominionNode dominionNode = getLocInDominionNode(nodes, loc);
return dominionNode == null ? null : dominionNode.getDominion();
}


public List<DominionNode> getNodes(Location loc) {
return getNodes(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockZ());
}

public List<DominionNode> getNodes(String world, int x, int z) {
if (x >= 0 && z >= 0) {
return world_dominion_tree_sector_a.get(world);
}
if (x <= 0 && z >= 0) {
return world_dominion_tree_sector_b.get(world);
}
if (x >= 0) {
return world_dominion_tree_sector_c.get(world);
}
return world_dominion_tree_sector_d.get(world);
}

public CompletableFuture<Void> initAsync(List<DominionDTO> dominions) {
return CompletableFuture.runAsync(() -> init(dominions));
}


private void init(List<DominionDTO> dominions) {
world_dominion_tree_sector_a = new ConcurrentHashMap<>();
world_dominion_tree_sector_b = new ConcurrentHashMap<>();
world_dominion_tree_sector_c = new ConcurrentHashMap<>();
world_dominion_tree_sector_d = new ConcurrentHashMap<>();

Map<String, List<DominionDTO>> world_dominions_sector_a = new HashMap<>();
Map<String, List<DominionDTO>> world_dominions_sector_b = new HashMap<>();
Map<String, List<DominionDTO>> world_dominions_sector_c = new HashMap<>();
Map<String, List<DominionDTO>> world_dominions_sector_d = new HashMap<>();
for (DominionDTO d : dominions) {
// 对每个世界的领地进行四个象限的划分
if (!world_dominions_sector_a.containsKey(d.getWorld()) ||
!world_dominions_sector_b.containsKey(d.getWorld()) ||
!world_dominions_sector_c.containsKey(d.getWorld()) ||
!world_dominions_sector_d.containsKey(d.getWorld())) {
world_dominions_sector_a.put(d.getWorld(), new ArrayList<>());
world_dominions_sector_b.put(d.getWorld(), new ArrayList<>());
world_dominions_sector_c.put(d.getWorld(), new ArrayList<>());
world_dominions_sector_d.put(d.getWorld(), new ArrayList<>());
}
if (d.getX1() >= 0 && d.getZ1() >= 0) {
world_dominions_sector_a.get(d.getWorld()).add(d);
} else if (d.getX1() <= 0 && d.getZ1() >= 0) {
if (d.getX2() >= 0) {
world_dominions_sector_a.get(d.getWorld()).add(d);
world_dominions_sector_b.get(d.getWorld()).add(d);
} else {
world_dominions_sector_b.get(d.getWorld()).add(d);
}
} else if (d.getX1() >= 0 && d.getZ1() <= 0) {
if (d.getZ2() >= 0) {
world_dominions_sector_a.get(d.getWorld()).add(d);
world_dominions_sector_c.get(d.getWorld()).add(d);
} else {
world_dominions_sector_c.get(d.getWorld()).add(d);
}
} else {
if (d.getX2() >= 0 && d.getZ2() >= 0) {
world_dominions_sector_a.get(d.getWorld()).add(d);
world_dominions_sector_b.get(d.getWorld()).add(d);
world_dominions_sector_c.get(d.getWorld()).add(d);
world_dominions_sector_d.get(d.getWorld()).add(d);
} else if (d.getX2() >= 0 && d.getZ2() <= 0) {
world_dominions_sector_c.get(d.getWorld()).add(d);
world_dominions_sector_d.get(d.getWorld()).add(d);
} else if (d.getZ2() >= 0 && d.getX2() <= 0) {
world_dominions_sector_b.get(d.getWorld()).add(d);
world_dominions_sector_d.get(d.getWorld()).add(d);
} else {
world_dominions_sector_d.get(d.getWorld()).add(d);
}
}
}
for (Map.Entry<String, List<DominionDTO>> entry : world_dominions_sector_a.entrySet()) {
world_dominion_tree_sector_a.put(entry.getKey(), DominionNode.BuildNodeTree(-1, entry.getValue()));
}
for (Map.Entry<String, List<DominionDTO>> entry : world_dominions_sector_b.entrySet()) {
world_dominion_tree_sector_b.put(entry.getKey(), DominionNode.BuildNodeTree(-1, entry.getValue()));
}
for (Map.Entry<String, List<DominionDTO>> entry : world_dominions_sector_c.entrySet()) {
world_dominion_tree_sector_c.put(entry.getKey(), DominionNode.BuildNodeTree(-1, entry.getValue()));
}
for (Map.Entry<String, List<DominionDTO>> entry : world_dominions_sector_d.entrySet()) {
world_dominion_tree_sector_d.put(entry.getKey(), DominionNode.BuildNodeTree(-1, entry.getValue()));
}
}
}
}
7 changes: 0 additions & 7 deletions src/main/java/cn/lunadeer/dominion/DominionNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,6 @@ public static DominionNode getLocInDominionNode(@NotNull List<DominionNode> node
return null;
}

public static DominionDTO getLocInDominionDTO(@Nullable List<DominionNode> nodes, @NotNull Location loc) {
if (nodes == null) return null;
if (nodes.isEmpty()) return null;
DominionNode dominionNode = getLocInDominionNode(nodes, loc);
return dominionNode == null ? null : dominionNode.getDominion();
}

public static boolean isInDominion(@Nullable DominionDTO dominion, Location location) {
if (dominion == null) return false;
if (!Objects.equals(dominion.getWorld(), location.getWorld().getName())) return false;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/cn/lunadeer/dominion/controllers/Apis.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static DominionDTO getPlayerCurrentDominion(AbstractOperator player) {
player.setResponse(new AbstractOperator.Result(AbstractOperator.Result.FAILURE, "无法获取你的位置信息"));
return null;
}
DominionDTO dominion = Cache.instance.getDominion(location);
DominionDTO dominion = Cache.instance.getDominionByLoc(location);
if (dominion == null) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
public class DominionController {

public static List<DominionDTO> all(Player owner) {
return DominionDTO.selectAll(owner.getUniqueId());
return DominionDTO.selectByOwner(owner.getUniqueId());
}

public static List<DominionDTO> all() {
Expand Down
9 changes: 2 additions & 7 deletions src/main/java/cn/lunadeer/dominion/dtos/DominionDTO.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,13 @@ public static List<DominionDTO> selectAll() {
return query(sql);
}

public static List<DominionDTO> selectAll(String world) {
String sql = "SELECT * FROM dominion WHERE world = ? AND id > 0;";
return query(sql, world);
}

public static List<DominionDTO> search(String name) {
String sql = "SELECT * FROM dominion WHERE name LIKE ? AND id > 0;";
return query(sql, "%" + name + "%");
}

public static List<DominionDTO> selectAll(UUID owner) {
String sql = "SELECT * FROM dominion WHERE owner = ? AND id > 0;";
public static List<DominionDTO> selectByOwner(UUID owner) {
String sql = "SELECT * FROM dominion WHERE owner = ? AND id > 0 ORDER BY id DESC;";
return query(sql, owner.toString());
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/cn/lunadeer/dominion/events/Apis.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static DominionDTO getInvDominion(Player bukkitPlayer, Inventory inv) {
if (inv.getLocation() == null) {
return null;
} else {
return Cache.instance.getDominion(inv.getLocation());
return Cache.instance.getDominionByLoc(inv.getLocation());
}
}

Expand Down
Loading

0 comments on commit b3934b9

Please sign in to comment.