mirror of
https://github.com/Minestom/Minestom.git
synced 2024-11-05 18:32:28 +01: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.Player;
|
||||
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.block.BlockManager;
|
||||
import net.minestom.server.listener.manager.PacketListenerManager;
|
||||
@ -91,6 +92,7 @@ public class MinecraftServer {
|
||||
private static ResponseDataConsumer responseDataConsumer;
|
||||
private static Difficulty difficulty = Difficulty.NORMAL;
|
||||
private static LootTableManager lootTableManager;
|
||||
private static TagManager tagManager;
|
||||
|
||||
public static MinecraftServer init() {
|
||||
connectionManager = new ConnectionManager();
|
||||
@ -111,6 +113,7 @@ public class MinecraftServer {
|
||||
updateManager = new UpdateManager();
|
||||
|
||||
lootTableManager = new LootTableManager();
|
||||
tagManager = new TagManager();
|
||||
|
||||
nettyServer = new NettyServer(packetProcessor);
|
||||
|
||||
@ -208,6 +211,10 @@ public class MinecraftServer {
|
||||
return lootTableManager;
|
||||
}
|
||||
|
||||
public static TagManager getTagManager() {
|
||||
return tagManager;
|
||||
}
|
||||
|
||||
public void start(String address, int port, ResponseDataConsumer responseDataConsumer) {
|
||||
LOGGER.info("Starting Minestom server.");
|
||||
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