Skip to content

Commit 09ec1e1

Browse files
committed
Fixed issue with FAWE generating random blocks when generating duplicates
1 parent 2c13f40 commit 09ec1e1

6 files changed

Lines changed: 36 additions & 37 deletions

File tree

Plugin/src/main/java/dev/lrxh/neptune/feature/customkit/CustomKit.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,6 @@ private static HashMap<KitRule, Boolean> defaultRules() {
7878
return r;
7979
}
8080

81-
// Player-inventory contents layout (getContents()): 0-8 hotbar, 9-35 storage,
82-
// 36 boots, 37 leggings, 38 chestplate, 39 helmet, 40 offhand.
8381
public static final int CONTENTS_SIZE = 41;
8482

8583
private static List<ItemStack> defaultTemplate() {
@@ -116,11 +114,6 @@ public void toggleArena(String arenaName) {
116114
if (!arenaNames.remove(arenaName)) arenaNames.add(arenaName);
117115
}
118116

119-
/**
120-
* Builds a throwaway {@link Kit} for a single custom match. Uses Kit's all-args constructor,
121-
* which does NOT register the kit on every profile. HIDDEN is forced so it never leaks into the
122-
* normal queue (e.g. via the play-again item).
123-
*/
124117
public Kit toTransientKit() {
125118
HashSet<Arena> arenas = new HashSet<>();
126119
for (String n : arenaNames) {

Plugin/src/main/java/dev/lrxh/neptune/feature/customkit/CustomKitService.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
public class CustomKitService {
77
private static CustomKitService instance;
88

9-
/** Max custom kits a player may own. */
109
public static int MAX_KITS = 5;
1110

1211
private final Map<UUID, List<CustomKit>> kits = new ConcurrentHashMap<>();
@@ -41,7 +40,6 @@ public void delete(UUID uuid, CustomKit kit) {
4140
get(uuid).remove(kit);
4241
}
4342

44-
// Persistence (mirrors the profile 'history' List<String> pattern)
4543
public List<String> serialize(UUID uuid) {
4644
List<String> out = new ArrayList<>();
4745
for (CustomKit k : get(uuid)) out.add(k.serialize());
@@ -59,7 +57,6 @@ public void load(UUID uuid, List<String> data) {
5957
kits.put(uuid, list);
6058
}
6159

62-
// Chat-input tracking
6360
public void await(UUID uuid, Input type, CustomKit kit) {
6461
inputType.put(uuid, type);
6562
if (kit != null) inputKit.put(uuid, kit);

Plugin/src/main/java/dev/lrxh/neptune/feature/customkit/menu/CustomKitEditorMenu.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,11 @@ public CustomKitEditorMenu(CustomKit kit) {
3838
public List<Button> getButtons(Player player) {
3939
List<Button> buttons = new ArrayList<>();
4040

41-
// Main inventory: storage (editor 0-26 -> contents 9-35), hotbar (editor 27-35 -> contents 0-8)
4241
for (int es = 0; es <= 35; es++) {
4342
int ci = es <= 26 ? es + 9 : es - 27;
4443
buttons.add(slot(es, ci, MenusLocale.CUSTOM_KIT_EDITOR_EMPTY_MATERIAL.getString(),
4544
MenusLocale.CUSTOM_KIT_EDITOR_EMPTY_NAME.getString(), "items"));
4645
}
47-
// Armor + offhand (bottom row), each filtered to its item type
4846
String armor = MenusLocale.CUSTOM_KIT_EDITOR_SLOT_MATERIAL.getString();
4947
buttons.add(slot(45, 39, armor, MenusLocale.CUSTOM_KIT_EDITOR_HELMET_NAME.getString(), "helmet"));
5048
buttons.add(slot(46, 38, armor, MenusLocale.CUSTOM_KIT_EDITOR_CHESTPLATE_NAME.getString(), "chestplate"));

Plugin/src/main/java/dev/lrxh/neptune/feature/customkit/queue/CustomKitQueueService.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
public class CustomKitQueueService {
2020
private static CustomKitQueueService instance;
2121

22-
/** host UUID -> the kit they are hosting (one open listing per host). */
2322
private final Map<UUID, CustomKit> listings = new ConcurrentHashMap<>();
2423

2524
public static CustomKitQueueService get() {
@@ -79,7 +78,6 @@ public void join(Player joiner, UUID hostUUID) {
7978
start(joiner, host, kit);
8079
}
8180

82-
/** Builds a throwaway kit and starts an unranked (duel) match so no stats are touched. */
8381
private void start(Player joiner, Player host, CustomKit kit) {
8482
Kit transientKit = kit.toTransientKit();
8583
transientKit.getRandomArena().thenAccept(arena -> Bukkit.getScheduler().runTask(Neptune.get(), () -> {

Plugin/src/main/java/dev/lrxh/neptune/feature/itembrowser/ItemBrowserService.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ private List<Material> computeSection(String section) {
4545
};
4646
}
4747

48-
/** Precomputes every built-in section so the first browser open isn't doing the work. */
4948
public void preloadSections() {
5049
for (String section : new String[]{"blocks", "items", "helmet", "chestplate", "leggings", "boots"}) {
5150
computed.computeIfAbsent(section, this::computeSection);

Plugin/src/main/java/dev/lrxh/neptune/game/arena/ArenaDuplicator.java

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.sk89q.worldedit.math.BlockVector3;
1111
import com.sk89q.worldedit.regions.CuboidRegion;
1212
import com.sk89q.worldedit.session.ClipboardHolder;
13+
import org.bukkit.Bukkit;
1314
import org.bukkit.Location;
1415
import org.bukkit.World;
1516

@@ -19,8 +20,15 @@
1920
*/
2021
public final class ArenaDuplicator {
2122

23+
/**
24+
* FAWE corrupts chunk data when multiple EditSessions edit a world concurrently. Batch duplicate creation
25+
* spawns one async task per duplicate, so all FAWE work is serialized through this lock to prevent the
26+
* "random blocks" corruption.
27+
*/
28+
private static final Object FAWE_LOCK = new Object();
29+
2230
public static boolean isAvailable() {
23-
return org.bukkit.Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit") != null;
31+
return Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit") != null;
2432
}
2533

2634
public static void copyPaste(World sourceWorld, Location min, Location max, World targetWorld, int tx, int ty, int tz) {
@@ -30,18 +38,20 @@ public static void copyPaste(World sourceWorld, Location min, Location max, Worl
3038
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
3139
clipboard.setOrigin(region.getMinimumPoint());
3240

33-
try (EditSession source = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(sourceWorld))) {
34-
ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard, region.getMinimumPoint());
35-
copy.setCopyingEntities(false);
36-
Operations.complete(copy);
37-
}
41+
synchronized (FAWE_LOCK) {
42+
try (EditSession source = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(sourceWorld))) {
43+
ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard, region.getMinimumPoint());
44+
copy.setCopyingEntities(false);
45+
Operations.complete(copy);
46+
}
3847

39-
try (EditSession target = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(targetWorld))) {
40-
Operations.complete(new ClipboardHolder(clipboard)
41-
.createPaste(target)
42-
.to(BlockVector3.at(tx, ty, tz))
43-
.ignoreAirBlocks(false)
44-
.build());
48+
try (EditSession target = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(targetWorld))) {
49+
Operations.complete(new ClipboardHolder(clipboard)
50+
.createPaste(target)
51+
.to(BlockVector3.at(tx, ty, tz))
52+
.ignoreAirBlocks(false)
53+
.build());
54+
}
4555
}
4656
}
4757

@@ -55,10 +65,12 @@ public static Object capture(World world, Location min, Location max) {
5565
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
5666
clipboard.setOrigin(region.getMinimumPoint());
5767

58-
try (EditSession source = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(world))) {
59-
ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard, region.getMinimumPoint());
60-
copy.setCopyingEntities(false);
61-
Operations.complete(copy);
68+
synchronized (FAWE_LOCK) {
69+
try (EditSession source = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(world))) {
70+
ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard, region.getMinimumPoint());
71+
copy.setCopyingEntities(false);
72+
Operations.complete(copy);
73+
}
6274
}
6375
return clipboard;
6476
}
@@ -68,12 +80,14 @@ public static Object capture(World world, Location min, Location max) {
6880
*/
6981
public static void restore(World world, Object clipboard) {
7082
Clipboard clip = (Clipboard) clipboard;
71-
try (EditSession target = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(world))) {
72-
Operations.complete(new ClipboardHolder(clip)
73-
.createPaste(target)
74-
.to(clip.getOrigin())
75-
.ignoreAirBlocks(false)
76-
.build());
83+
synchronized (FAWE_LOCK) {
84+
try (EditSession target = WorldEdit.getInstance().newEditSession(BukkitAdapter.adapt(world))) {
85+
Operations.complete(new ClipboardHolder(clip)
86+
.createPaste(target)
87+
.to(clip.getOrigin())
88+
.ignoreAirBlocks(false)
89+
.build());
90+
}
7791
}
7892
}
7993
}

0 commit comments

Comments
 (0)