mirror of
https://github.com/Minestom/Minestom.git
synced 2024-09-30 23:47:37 +02:00
Merge branch 'tags'
This commit is contained in:
commit
f79cfa8d87
@ -6,6 +6,7 @@ import net.minestom.server.data.DataManager;
|
|||||||
import net.minestom.server.entity.EntityManager;
|
import net.minestom.server.entity.EntityManager;
|
||||||
import net.minestom.server.entity.Player;
|
import net.minestom.server.entity.Player;
|
||||||
import net.minestom.server.gamedata.loottables.LootTableManager;
|
import net.minestom.server.gamedata.loottables.LootTableManager;
|
||||||
|
import net.minestom.server.gamedata.tags.TagManager;
|
||||||
import net.minestom.server.instance.InstanceManager;
|
import net.minestom.server.instance.InstanceManager;
|
||||||
import net.minestom.server.instance.block.BlockManager;
|
import net.minestom.server.instance.block.BlockManager;
|
||||||
import net.minestom.server.listener.manager.PacketListenerManager;
|
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||||
@ -91,6 +92,7 @@ public class MinecraftServer {
|
|||||||
private static ResponseDataConsumer responseDataConsumer;
|
private static ResponseDataConsumer responseDataConsumer;
|
||||||
private static Difficulty difficulty = Difficulty.NORMAL;
|
private static Difficulty difficulty = Difficulty.NORMAL;
|
||||||
private static LootTableManager lootTableManager;
|
private static LootTableManager lootTableManager;
|
||||||
|
private static TagManager tagManager;
|
||||||
|
|
||||||
public static MinecraftServer init() {
|
public static MinecraftServer init() {
|
||||||
connectionManager = new ConnectionManager();
|
connectionManager = new ConnectionManager();
|
||||||
@ -111,6 +113,7 @@ public class MinecraftServer {
|
|||||||
updateManager = new UpdateManager();
|
updateManager = new UpdateManager();
|
||||||
|
|
||||||
lootTableManager = new LootTableManager();
|
lootTableManager = new LootTableManager();
|
||||||
|
tagManager = new TagManager();
|
||||||
|
|
||||||
nettyServer = new NettyServer(packetProcessor);
|
nettyServer = new NettyServer(packetProcessor);
|
||||||
|
|
||||||
@ -208,6 +211,10 @@ public class MinecraftServer {
|
|||||||
return lootTableManager;
|
return lootTableManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TagManager getTagManager() {
|
||||||
|
return tagManager;
|
||||||
|
}
|
||||||
|
|
||||||
public void start(String address, int port, ResponseDataConsumer responseDataConsumer) {
|
public void start(String address, int port, ResponseDataConsumer responseDataConsumer) {
|
||||||
LOGGER.info("Starting Minestom server.");
|
LOGGER.info("Starting Minestom server.");
|
||||||
MinecraftServer.responseDataConsumer = responseDataConsumer;
|
MinecraftServer.responseDataConsumer = responseDataConsumer;
|
||||||
|
73
src/main/java/net/minestom/server/gamedata/tags/Tag.java
Normal file
73
src/main/java/net/minestom/server/gamedata/tags/Tag.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package net.minestom.server.gamedata.tags;
|
||||||
|
|
||||||
|
import net.minestom.server.utils.NamespaceID;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a group of items, blocks, fluids, entity types or function.
|
||||||
|
* Immutable by design
|
||||||
|
*/
|
||||||
|
public class Tag {
|
||||||
|
|
||||||
|
public static final Tag EMPTY = new Tag();
|
||||||
|
|
||||||
|
private Set<NamespaceID> values;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new empty tag
|
||||||
|
*/
|
||||||
|
public Tag() {
|
||||||
|
values = new HashSet<>();
|
||||||
|
lockValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new tag with the contents of the container
|
||||||
|
* @param manager Used to load tag contents (as tags are valid values inside 'values')
|
||||||
|
* @param lowerPriority Tag contents from lower priority data packs. If 'replace' is false in 'container',
|
||||||
|
* appends the contents of that pack to the one being constructed
|
||||||
|
* @param container
|
||||||
|
*/
|
||||||
|
public Tag(TagManager manager, String type, Tag lowerPriority, TagContainer container) throws FileNotFoundException {
|
||||||
|
values = new HashSet<>();
|
||||||
|
if(!container.replace) {
|
||||||
|
values.addAll(lowerPriority.values);
|
||||||
|
}
|
||||||
|
Objects.requireNonNull(container.values, "Attempted to load from a TagContainer with no 'values' array");
|
||||||
|
for(String line : container.values) {
|
||||||
|
if(line.startsWith("#")) { // pull contents from a tag
|
||||||
|
Tag subtag = manager.load(NamespaceID.from(line.substring(1)), type);
|
||||||
|
values.addAll(subtag.values);
|
||||||
|
} else {
|
||||||
|
values.add(NamespaceID.from(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lockValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void lockValues() {
|
||||||
|
values = Set.copyOf(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the given id in inside this tag
|
||||||
|
* @param id the id to check against
|
||||||
|
* @return 'true' iif this tag contains the given id
|
||||||
|
*/
|
||||||
|
public boolean contains(NamespaceID id) {
|
||||||
|
return values.contains(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an immutable set of values present in this tag
|
||||||
|
* @return immutable set of values present in this tag
|
||||||
|
*/
|
||||||
|
public Set<NamespaceID> getValues() {
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package net.minestom.server.gamedata.tags;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Meant only for parsing tag JSON
|
||||||
|
*/
|
||||||
|
public class TagContainer {
|
||||||
|
boolean replace;
|
||||||
|
String[] values;
|
||||||
|
}
|
102
src/main/java/net/minestom/server/gamedata/tags/TagManager.java
Normal file
102
src/main/java/net/minestom/server/gamedata/tags/TagManager.java
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package net.minestom.server.gamedata.tags;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import net.minestom.server.registry.ResourceGatherer;
|
||||||
|
import net.minestom.server.utils.NamespaceID;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles loading and caching of tags
|
||||||
|
*/
|
||||||
|
public class TagManager {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(TagManager.class);
|
||||||
|
private final Gson gson;
|
||||||
|
private Map<NamespaceID, Tag> cache = new HashMap<>();
|
||||||
|
|
||||||
|
public TagManager() {
|
||||||
|
gson = new GsonBuilder()
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a tag with the given name. This method attempts to read from "data/<name.domain>/tags/<tagType>/<name.path>.json" if the given name is not already present in cache
|
||||||
|
* @param name
|
||||||
|
* @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants)
|
||||||
|
* @return
|
||||||
|
* @throws FileNotFoundException if the file does not exist
|
||||||
|
*/
|
||||||
|
public Tag load(NamespaceID name, String tagType) throws FileNotFoundException {
|
||||||
|
return load(name, tagType, () -> new FileReader(new File(ResourceGatherer.DATA_FOLDER, "data/"+name.getDomain()+"/tags/"+tagType+"/"+name.getPath()+".json")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a tag with the given name. This method attempts to read from 'reader' if the given name is not already present in cache
|
||||||
|
* @param name
|
||||||
|
* @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants)
|
||||||
|
* @param reader
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Tag load(NamespaceID name, String tagType, Reader reader) throws FileNotFoundException {
|
||||||
|
return load(name, tagType, () -> reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a tag with the given name. This method reads from 'reader'. This will override the previous tag
|
||||||
|
* @param name
|
||||||
|
* @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants)
|
||||||
|
* @param readerSupplier
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Tag forceLoad(NamespaceID name, String tagType, ReaderSupplierWithFileNotFound readerSupplier) throws FileNotFoundException {
|
||||||
|
Tag prev = cache.getOrDefault(name, Tag.EMPTY);
|
||||||
|
FileNotFoundException[] ex = new FileNotFoundException[1]; // very ugly code but Java does not let its standard interfaces throw exceptions
|
||||||
|
Tag result = create(prev, tagType, readerSupplier);
|
||||||
|
cache.put(name, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a tag with the given name. This method attempts to read from 'reader' if the given name is not already present in cache
|
||||||
|
* @param name
|
||||||
|
* @param tagType the type of the tag to load, used to resolve paths (blocks, items, entity_types, fluids, functions are the vanilla variants)
|
||||||
|
* @param readerSupplier
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Tag load(NamespaceID name, String tagType, ReaderSupplierWithFileNotFound readerSupplier) throws FileNotFoundException {
|
||||||
|
Tag prev = cache.getOrDefault(name, Tag.EMPTY);
|
||||||
|
FileNotFoundException[] ex = new FileNotFoundException[1]; // very ugly code but Java does not let its standard interfaces throw exceptions
|
||||||
|
Tag result = cache.computeIfAbsent(name, _name -> {
|
||||||
|
try {
|
||||||
|
return create(prev, tagType, readerSupplier);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
ex[0] = e;
|
||||||
|
return Tag.EMPTY;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(ex[0] != null) {
|
||||||
|
throw ex[0];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tag create(Tag prev, String tagType, ReaderSupplierWithFileNotFound reader) throws FileNotFoundException {
|
||||||
|
TagContainer container = gson.fromJson(reader.get(), TagContainer.class);
|
||||||
|
try {
|
||||||
|
return new Tag(this, tagType, prev, container);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
LOGGER.error("Failed to load tag due to error", e);
|
||||||
|
return Tag.EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ReaderSupplierWithFileNotFound {
|
||||||
|
Reader get() throws FileNotFoundException;
|
||||||
|
}
|
||||||
|
}
|
104
src/test/java/tags/TestTags.java
Normal file
104
src/test/java/tags/TestTags.java
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package tags;
|
||||||
|
|
||||||
|
import net.minestom.server.gamedata.tags.Tag;
|
||||||
|
import net.minestom.server.gamedata.tags.TagManager;
|
||||||
|
import net.minestom.server.utils.NamespaceID;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
|
public class TestTags {
|
||||||
|
|
||||||
|
private TagManager tags;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
tags = new TagManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSubTag() throws FileNotFoundException {
|
||||||
|
String tag1 = "{\n" +
|
||||||
|
"\t\"replace\": false,\n" +
|
||||||
|
"\t\"values\": [\n" +
|
||||||
|
"\t\t\"minestom:an_item\"\n" +
|
||||||
|
"\t]\n" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
String tag2 = "{\n" +
|
||||||
|
"\t\"replace\": false,\n" +
|
||||||
|
"\t\"values\": [\n" +
|
||||||
|
"\t\t\"#minestom:test_sub\",\n" +
|
||||||
|
"\t\t\"minestom:some_other_item\"\n" +
|
||||||
|
"\t]\n" +
|
||||||
|
"}";
|
||||||
|
Assert.assertNotEquals(Tag.EMPTY, tags.load(NamespaceID.from("minestom:test_sub"), "any", new StringReader(tag1)));
|
||||||
|
Tag loaded = tags.load(NamespaceID.from("minestom:test"), "any", new StringReader(tag2));
|
||||||
|
NamespaceID[] values = loaded.getValues().toArray(new NamespaceID[0]);
|
||||||
|
Assert.assertEquals(2, values.length);
|
||||||
|
Assert.assertTrue(loaded.contains(NamespaceID.from("minestom:an_item")));
|
||||||
|
Assert.assertTrue(loaded.contains(NamespaceID.from("minestom:some_other_item")));
|
||||||
|
Assert.assertFalse(loaded.contains(NamespaceID.from("minestom:some_other_item_that_is_not_in_the_tag")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A value of 'true' in 'replace' should replace previous contents
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testReplacement() throws FileNotFoundException {
|
||||||
|
String tag1 = "{\n" +
|
||||||
|
"\t\"replace\": false,\n" +
|
||||||
|
"\t\"values\": [\n" +
|
||||||
|
"\t\t\"minestom:an_item\"\n" +
|
||||||
|
"\t]\n" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
String tag2 = "{\n" +
|
||||||
|
"\t\"replace\": true,\n" +
|
||||||
|
"\t\"values\": [\n" +
|
||||||
|
"\t\t\"minestom:some_other_item\"\n" +
|
||||||
|
"\t]\n" +
|
||||||
|
"}";
|
||||||
|
Assert.assertNotEquals(Tag.EMPTY, tags.load(NamespaceID.from("minestom:test"), "any", new StringReader(tag1)));
|
||||||
|
Tag loaded = tags.forceLoad(NamespaceID.from("minestom:test"), "any", () -> new StringReader(tag2));
|
||||||
|
Assert.assertNotEquals(Tag.EMPTY, loaded);
|
||||||
|
Assert.assertEquals(1, loaded.getValues().size());
|
||||||
|
Assert.assertTrue(loaded.contains(NamespaceID.from("minestom:some_other_item")));
|
||||||
|
Assert.assertFalse(loaded.contains(NamespaceID.from("minestom:an_item")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A value of 'false' in 'replace' should append to previous contents
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAppend() throws FileNotFoundException {
|
||||||
|
String tag1 = "{\n" +
|
||||||
|
"\t\"replace\": false,\n" +
|
||||||
|
"\t\"values\": [\n" +
|
||||||
|
"\t\t\"minestom:an_item\"\n" +
|
||||||
|
"\t]\n" +
|
||||||
|
"}";
|
||||||
|
|
||||||
|
String tag2 = "{\n" +
|
||||||
|
"\t\"replace\": false,\n" +
|
||||||
|
"\t\"values\": [\n" +
|
||||||
|
"\t\t\"minestom:some_other_item\"\n" +
|
||||||
|
"\t]\n" +
|
||||||
|
"}";
|
||||||
|
Assert.assertNotEquals(Tag.EMPTY, tags.load(NamespaceID.from("minestom:test"), "any", new StringReader(tag1)));
|
||||||
|
Tag loaded = tags.forceLoad(NamespaceID.from("minestom:test"), "any", () -> new StringReader(tag2));
|
||||||
|
Assert.assertNotEquals(Tag.EMPTY, loaded);
|
||||||
|
Assert.assertEquals(2, loaded.getValues().size());
|
||||||
|
Assert.assertTrue(loaded.contains(NamespaceID.from("minestom:some_other_item")));
|
||||||
|
Assert.assertTrue(loaded.contains(NamespaceID.from("minestom:an_item")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanup() {
|
||||||
|
tags = null;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user