Skip to content

Commit 219ffbb

Browse files
authored
GH-959 Move warp contents from language files. (#1172)
* GH-959 Move warp contents from language files. * Fix. * Improve error handling. use `ReentrantReadWriteLock` * Apply review feedback. * Refactor WarpInventory and WarpInventoryConfigService for improved async handling and configuration managementRemove `WarpInventoryRepository` and migrate its responsibilities to `WarpInventoryConfigService`. * Refactor Warp-related classes and services for improved configuration, maintainability, and structure * Refactor WarpInventory-related components for consistent formatting, improved async handling, and better configuration management; introduce Warp interface and enhance migration logging.
1 parent cd19923 commit 219ffbb

20 files changed

+852
-551
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package com.eternalcode.core.configuration.migrations;
2+
3+
import eu.okaeri.configs.OkaeriConfig;
4+
import eu.okaeri.configs.migrate.ConfigMigration;
5+
import eu.okaeri.configs.migrate.view.RawConfigView;
6+
import java.io.File;
7+
import java.io.FileReader;
8+
import java.io.FileWriter;
9+
import java.io.IOException;
10+
import java.util.LinkedHashMap;
11+
import java.util.Map;
12+
import java.util.logging.Level;
13+
import java.util.logging.Logger;
14+
import lombok.NonNull;
15+
import org.yaml.snakeyaml.DumperOptions;
16+
import org.yaml.snakeyaml.Yaml;
17+
18+
public class Migration_0035_Move_warp_inventory_to_dedicated_file implements ConfigMigration {
19+
20+
private static final Logger LOGGER = Logger
21+
.getLogger(Migration_0035_Move_warp_inventory_to_dedicated_file.class.getName());
22+
private static final String ROOT_KEY = "warpInventory";
23+
private static final String NESTED_KEY = "warp.warpInventory";
24+
private static final String NESTED_SECTION = "warp";
25+
26+
@Override
27+
public boolean migrate(@NonNull OkaeriConfig config, @NonNull RawConfigView view) {
28+
String foundKey = null;
29+
Map<String, Object> warpInventory = this.getFromView(view, ROOT_KEY);
30+
31+
if (warpInventory != null) {
32+
foundKey = ROOT_KEY;
33+
} else {
34+
warpInventory = this.getFromView(view, NESTED_KEY);
35+
if (warpInventory != null) {
36+
foundKey = NESTED_KEY;
37+
}
38+
}
39+
40+
if (warpInventory == null) {
41+
warpInventory = this.getFromFileFallback(config);
42+
}
43+
44+
if (warpInventory == null) {
45+
return false;
46+
}
47+
48+
Map<String, Object> newContent = this.transformData(warpInventory);
49+
50+
if (!this.saveNewConfig(config, newContent)) {
51+
return false;
52+
}
53+
54+
if (foundKey != null) {
55+
view.remove(foundKey);
56+
} else {
57+
view.remove(ROOT_KEY);
58+
view.remove(NESTED_KEY);
59+
}
60+
61+
return true;
62+
}
63+
64+
private Map<String, Object> getFromView(RawConfigView view, String key) {
65+
if (!view.exists(key)) {
66+
return null;
67+
}
68+
Object obj = view.get(key);
69+
return obj instanceof Map ? (Map<String, Object>) obj : null;
70+
}
71+
72+
private Map<String, Object> getFromFileFallback(OkaeriConfig config) {
73+
File bindFile = config.getBindFile().toFile();
74+
if (bindFile == null || !bindFile.exists()) {
75+
return null;
76+
}
77+
78+
try (FileReader reader = new FileReader(bindFile)) {
79+
Map<String, Object> content = new Yaml().load(reader);
80+
if (content == null) {
81+
return null;
82+
}
83+
84+
if (content.containsKey(ROOT_KEY) && content.get(ROOT_KEY) instanceof Map) {
85+
return (Map<String, Object>) content.get(ROOT_KEY);
86+
}
87+
88+
if (content.containsKey(NESTED_SECTION) && content.get(NESTED_SECTION) instanceof Map) {
89+
Map<String, Object> warpSection = (Map<String, Object>) content.get(NESTED_SECTION);
90+
if (warpSection.containsKey(ROOT_KEY) && warpSection.get(ROOT_KEY) instanceof Map) {
91+
return (Map<String, Object>) warpSection.get(ROOT_KEY);
92+
}
93+
}
94+
} catch (Exception exception) {
95+
LOGGER.log(Level.SEVERE, "Failed to read configuration file: " + bindFile.getAbsolutePath(), exception);
96+
}
97+
return null;
98+
}
99+
100+
private Map<String, Object> transformData(Map<String, Object> source) {
101+
Map<String, Object> result = new LinkedHashMap<>();
102+
103+
if (source.containsKey("title")) {
104+
Map<String, Object> display = new LinkedHashMap<>();
105+
display.put("title", source.get("title"));
106+
result.put("display", display);
107+
}
108+
109+
this.copyIfPresent(source, result, "items");
110+
this.copyIfPresent(source, result, "border");
111+
this.copyIfPresent(source, result, "decorationItems");
112+
113+
return result;
114+
}
115+
116+
private void copyIfPresent(Map<String, Object> source, Map<String, Object> target, String key) {
117+
if (source.containsKey(key)) {
118+
target.put(key, source.get(key));
119+
}
120+
}
121+
122+
private boolean saveNewConfig(OkaeriConfig config, Map<String, Object> content) {
123+
File destFile = this.getDestinationFile(config);
124+
if (destFile == null) {
125+
return false;
126+
}
127+
128+
if (destFile.exists() && !this.targetIsSafeToWrite(destFile)) {
129+
return true;
130+
}
131+
132+
if (!destFile.getParentFile().exists()) {
133+
destFile.getParentFile().mkdirs();
134+
}
135+
136+
DumperOptions options = new DumperOptions();
137+
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
138+
options.setPrettyFlow(true);
139+
options.setIndent(2);
140+
options.setIndicatorIndent(0);
141+
options.setSplitLines(false);
142+
143+
try (FileWriter writer = new FileWriter(destFile)) {
144+
new Yaml(options).dump(content, writer);
145+
return true;
146+
} catch (IOException e) {
147+
LOGGER.log(Level.SEVERE, "Failed to save new configuration file: " + destFile.getAbsolutePath(), e);
148+
return false;
149+
}
150+
}
151+
152+
private File getDestinationFile(OkaeriConfig config) {
153+
File bindFile = config.getBindFile().toFile();
154+
if (bindFile == null) {
155+
return null;
156+
}
157+
File dataFolder = bindFile.getParentFile();
158+
if ("lang".equals(dataFolder.getName())) {
159+
dataFolder = dataFolder.getParentFile();
160+
}
161+
return new File(dataFolder, "warp-inventory.yml");
162+
}
163+
164+
private boolean targetIsSafeToWrite(File file) {
165+
try (FileReader reader = new FileReader(file)) {
166+
Map<String, Object> existing = new Yaml().load(reader);
167+
if (existing == null || !existing.containsKey("items")) {
168+
return true;
169+
}
170+
Object items = existing.get("items");
171+
return items instanceof Map && ((Map<?, ?>) items).isEmpty();
172+
} catch (Exception exception) {
173+
LOGGER.log(Level.SEVERE, "Failed to check if target file is safe to write: " + file.getAbsolutePath(),
174+
exception);
175+
return false;
176+
}
177+
}
178+
}

eternalcore-core/src/main/java/com/eternalcode/core/configuration/migrations/Migrations.java

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,38 @@
55
public class Migrations {
66

77
public static final ConfigMigration[] ALL = new ConfigMigration[] {
8-
new Migration_0001_Rename_privateChat_to_msg(),
9-
new Migration_0002_Move_Spawn_Settings_to_spawn_config_section(),
10-
new Migration_0003_Move_tprp_to_dedicated_section(),
11-
new Migration_0006_Move_alert_to_broadcast_section(),
12-
new Migration_0007_Move_clear_to_dedicated_section(),
13-
new Migration_0008_Move_repair_to_dedicated_section(),
14-
new Migration_0009_Improve_Homes_Config(),
15-
new Migration_0010_Move_give_to_dedicated_section(),
16-
new Migration_0011_Move_enchant_to_dedicated_section(),
17-
new Migration_0012_Move_repair_argument_messages_to_dedicated_section(),
18-
new Migration_0013_Move_enchant_messages_to_dedicated_section(),
19-
new Migration_0014_Move_butcher_argument_messages_to_dedicated_section(),
20-
new Migration_0016_Move_feed_messages_to_dedicated_section(),
21-
new Migration_0017_Move_heal_messages_to_dedicated_section(),
22-
new Migration_0018_Move_kill_messages_to_dedicated_section(),
23-
new Migration_0019_Move_speed_messages_to_dedicated_section(),
24-
new Migration_0020_Move_godmode_messages_to_dedicated_section(),
25-
new Migration_0021_Move_fly_messages_to_dedicated_section(),
26-
new Migration_0022_Move_ping_messages_to_dedicated_section(),
27-
new Migration_0023_Move_gamemode_messages_to_dedicated_section(),
28-
new Migration_0024_Move_online_messages_to_dedicated_section(),
29-
new Migration_0025_Move_whois_messages_to_dedicated_section(),
30-
new Migration_0026_Move_butcher_messages_to_dedicated_section(),
31-
new Migration_0027_Move_give_messages_to_dedicated_section(),
32-
new Migration_0028_Move_skull_messages_to_dedicated_section(),
33-
new Migration_0029_Move_enchant_messages_to_dedicated_section(),
34-
new Migration_0015_Move_ignore_messages_to_dedicated_section(),
35-
new Migration_0030_Move_back_to_dedicated_section(),
36-
new Migration_0031_Move_death_messages_to_dedicated_section(),
37-
new Migration_0032_Move_join_quit_messages_to_dedicated_section(),
38-
new Migration_0033_Move_disposal_messages_to_dedicated_section(),
39-
new Migration_0034_Move_chat_settings_messages_to_dedicated_section(),
40-
};
8+
new Migration_0001_Rename_privateChat_to_msg(),
9+
new Migration_0002_Move_Spawn_Settings_to_spawn_config_section(),
10+
new Migration_0003_Move_tprp_to_dedicated_section(),
11+
new Migration_0006_Move_alert_to_broadcast_section(),
12+
new Migration_0007_Move_clear_to_dedicated_section(),
13+
new Migration_0008_Move_repair_to_dedicated_section(),
14+
new Migration_0009_Improve_Homes_Config(),
15+
new Migration_0010_Move_give_to_dedicated_section(),
16+
new Migration_0011_Move_enchant_to_dedicated_section(),
17+
new Migration_0012_Move_repair_argument_messages_to_dedicated_section(),
18+
new Migration_0013_Move_enchant_messages_to_dedicated_section(),
19+
new Migration_0014_Move_butcher_argument_messages_to_dedicated_section(),
20+
new Migration_0016_Move_feed_messages_to_dedicated_section(),
21+
new Migration_0017_Move_heal_messages_to_dedicated_section(),
22+
new Migration_0018_Move_kill_messages_to_dedicated_section(),
23+
new Migration_0019_Move_speed_messages_to_dedicated_section(),
24+
new Migration_0020_Move_godmode_messages_to_dedicated_section(),
25+
new Migration_0021_Move_fly_messages_to_dedicated_section(),
26+
new Migration_0022_Move_ping_messages_to_dedicated_section(),
27+
new Migration_0023_Move_gamemode_messages_to_dedicated_section(),
28+
new Migration_0024_Move_online_messages_to_dedicated_section(),
29+
new Migration_0025_Move_whois_messages_to_dedicated_section(),
30+
new Migration_0026_Move_butcher_messages_to_dedicated_section(),
31+
new Migration_0027_Move_give_messages_to_dedicated_section(),
32+
new Migration_0028_Move_skull_messages_to_dedicated_section(),
33+
new Migration_0029_Move_enchant_messages_to_dedicated_section(),
34+
new Migration_0015_Move_ignore_messages_to_dedicated_section(),
35+
new Migration_0030_Move_back_to_dedicated_section(),
36+
new Migration_0031_Move_death_messages_to_dedicated_section(),
37+
new Migration_0032_Move_join_quit_messages_to_dedicated_section(),
38+
new Migration_0033_Move_disposal_messages_to_dedicated_section(),
39+
new Migration_0034_Move_chat_settings_messages_to_dedicated_section(),
40+
new Migration_0035_Move_warp_inventory_to_dedicated_file(),
41+
};
4142
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.eternalcode.core.feature.warp;
2+
3+
import org.bukkit.Location;
4+
import org.bukkit.entity.Player;
5+
import java.util.List;
6+
7+
public interface Warp {
8+
9+
String getName();
10+
11+
Location getLocation();
12+
13+
List<String> getPermissions();
14+
15+
default boolean hasPermissions(Player player) {
16+
if (this.getPermissions().isEmpty()) {
17+
return true;
18+
}
19+
20+
for (String permission : this.getPermissions()) {
21+
if (player.hasPermission(permission)) {
22+
return true;
23+
}
24+
}
25+
26+
return false;
27+
}
28+
29+
}

eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpConfig.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
package com.eternalcode.core.feature.warp;
22

3+
import com.eternalcode.commons.bukkit.position.Position;
34
import eu.okaeri.configs.OkaeriConfig;
45
import eu.okaeri.configs.annotation.Comment;
5-
import java.time.Duration;
6+
import lombok.AllArgsConstructor;
67
import lombok.Getter;
8+
import lombok.NoArgsConstructor;
79
import lombok.experimental.Accessors;
810
import org.bukkit.Material;
911

12+
import java.time.Duration;
13+
import java.util.ArrayList;
14+
import java.util.List;
15+
import java.util.Map;
16+
import java.util.concurrent.ConcurrentHashMap;
17+
1018
@Getter
1119
@Accessors(fluent = true)
1220
public class WarpConfig extends OkaeriConfig implements WarpSettings {
@@ -19,8 +27,8 @@ public class WarpConfig extends OkaeriConfig implements WarpSettings {
1927
@Comment("# Warp inventory auto add new warps")
2028
public boolean autoAddNewWarps = true;
2129

22-
@Comment({"# Options below allow you to customize item representing warp added to GUI, ",
23-
"# you can change almost everything inside language files, after the warp has been added to the inventory."})
30+
@Comment({ "# Options below allow you to customize item representing warp added to GUI, ",
31+
"# you can change almost everything inside language files, after the warp has been added to the inventory." })
2432
public String itemNamePrefix = "&8» &6Warp: &f";
2533

2634
public String itemLore = "&7Click to teleport!";
@@ -29,4 +37,15 @@ public class WarpConfig extends OkaeriConfig implements WarpSettings {
2937

3038
@Comment("# Texture of the item (only for PLAYER_HEAD material)")
3139
public String itemTexture = "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzk4ODVlODIzZmYxNTkyNjdjYmU4MDkwOTNlMzNhNDc2ZTI3NDliNjU5OGNhNGEyYTgxZWU2OTczODAzZmI2NiJ9fX0=";
40+
41+
public Map<String, WarpConfigEntry> warps = new ConcurrentHashMap<>();
42+
43+
@Getter
44+
@Accessors(fluent = true)
45+
@NoArgsConstructor
46+
@AllArgsConstructor
47+
public static class WarpConfigEntry extends OkaeriConfig {
48+
public Position position;
49+
public List<String> permissions = new ArrayList<>();
50+
}
3251
}

eternalcore-core/src/main/java/com/eternalcode/core/feature/warp/WarpImpl.java

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,15 @@
22

33
import com.eternalcode.commons.bukkit.position.Position;
44
import com.eternalcode.commons.bukkit.position.PositionAdapter;
5-
import java.util.ArrayList;
65
import org.bukkit.Location;
76

87
import java.util.Collections;
98
import java.util.List;
109

11-
public class WarpImpl implements Warp {
10+
public record WarpImpl(String name, Position position, List<String> permissions) implements Warp {
1211

13-
private final String name;
14-
private final Position position;
15-
private final List<String> permissions;
16-
17-
public WarpImpl(String name, Position position, List<String> permissions) {
18-
this.name = name;
19-
this.position = position;
20-
this.permissions = new ArrayList<>(permissions);
12+
public WarpImpl {
13+
permissions = Collections.unmodifiableList(permissions);
2114
}
2215

2316
@Override
@@ -32,7 +25,7 @@ public Location getLocation() {
3225

3326
@Override
3427
public List<String> getPermissions() {
35-
return Collections.unmodifiableList(this.permissions);
28+
return this.permissions;
3629
}
3730

3831
}

0 commit comments

Comments
 (0)