Send tags to player on connection

This commit is contained in:
jglrxavpok 2020-06-30 20:38:42 +02:00
parent ef8c275c4d
commit 2303b98024
13 changed files with 298 additions and 14 deletions

View File

@ -0,0 +1,37 @@
//==============================
// AUTOGENERATED BY EnumGenerator
//==============================
package net.minestom.server.fluids;
import net.minestom.server.registry.Registries;
import net.minestom.server.utils.NamespaceID;
@SuppressWarnings({"deprecation"})
public enum Fluid {
EMPTY("minecraft:empty"),
FLOWING_WATER("minecraft:flowing_water"),
WATER("minecraft:water"),
FLOWING_LAVA("minecraft:flowing_lava"),
LAVA("minecraft:lava"),
;
private String namespaceID;
Fluid(String namespaceID) {
this.namespaceID = namespaceID;
Registries.fluids.put(NamespaceID.from(namespaceID), this);
}
public int getId() {
return ordinal();
}
public String getNamespaceID() {
return namespaceID;
}
public static Fluid fromId(int id) {
if(id >= 0 && id < values().length) {
return values()[id];
}
return EMPTY;
}
}

View File

@ -11,6 +11,7 @@ import net.minestom.server.particle.Particle;
import net.minestom.server.potion.PotionType;
import net.minestom.server.sound.Sound;
import net.minestom.server.stat.StatisticType;
import net.minestom.server.fluids.Fluid;
// AUTOGENERATED
public class Registries {
@ -50,6 +51,10 @@ public class Registries {
@Deprecated
public static final HashMap<NamespaceID, StatisticType> statisticTypes = new HashMap<>();
/** Should only be used for internal code, please use the get* methods. */
@Deprecated
public static final HashMap<NamespaceID, Fluid> fluids = new HashMap<>();
/** Returns the corresponding Block matching the given id. Returns 'AIR' if none match. */
public static Block getBlock(String id) {
@ -141,5 +146,15 @@ public class Registries {
return statisticTypes.get(id);
}
/** Returns the corresponding Fluid matching the given id. Returns 'EMPTY' if none match. */
public static Fluid getFluid(String id) {
return getFluid(NamespaceID.from(id));
}
/** Returns the corresponding Fluid matching the given id. Returns 'EMPTY' if none match. */
public static Fluid getFluid(NamespaceID id) {
return fluids.getOrDefault(id, Fluid.EMPTY);
}
}

View File

@ -3,6 +3,7 @@ package net.minestom.codegen;
import net.minestom.codegen.blocks.BlockEnumGenerator;
import net.minestom.codegen.enchantment.EnchantmentEnumGenerator;
import net.minestom.codegen.entitytypes.EntityTypeEnumGenerator;
import net.minestom.codegen.fluids.FluidEnumGenerator;
import net.minestom.codegen.items.ItemEnumGenerator;
import net.minestom.codegen.particles.ParticleEnumGenerator;
import net.minestom.codegen.potions.PotionEnumGenerator;
@ -24,6 +25,7 @@ public class AllGenerators {
ParticleEnumGenerator.main(args);
StatsEnumGenerator.main(args);
BiomesEnumGenerator.main(args);
FluidEnumGenerator.main(args);
RegistriesGenerator.main(args);
}
}

View File

@ -1,6 +1,7 @@
package net.minestom.codegen;
import net.minestom.server.entity.EntityType;
import net.minestom.server.fluids.Fluid;
import net.minestom.server.instance.Biome;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.Enchantment;
@ -37,6 +38,7 @@ public class RegistriesGenerator implements CodeGenerator {
PotionType.class.getCanonicalName(),
Sound.class.getCanonicalName(),
StatisticType.class.getCanonicalName(),
Fluid.class.getCanonicalName(),
};
private static final String[] defaults = {
"AIR",
@ -47,7 +49,8 @@ public class RegistriesGenerator implements CodeGenerator {
null,
null,
null,
null
null,
"EMPTY"
};
@Override

View File

@ -0,0 +1,56 @@
package net.minestom.codegen.fluids;
import net.minestom.codegen.BasicEnumGenerator;
import net.minestom.server.registry.ResourceGatherer;
import java.io.File;
import java.io.IOException;
public class FluidEnumGenerator extends BasicEnumGenerator {
public static void main(String[] args) throws IOException {
String targetVersion;
if(args.length < 1) {
System.err.println("Usage: <MC version> [target folder]");
return;
}
targetVersion = args[0];
try {
ResourceGatherer.ensureResourcesArePresent(targetVersion, null); // TODO
} catch (IOException e) {
e.printStackTrace();
}
String targetPart = DEFAULT_TARGET_PATH;
if(args.length >= 2) {
targetPart = args[1];
}
File targetFolder = new File(targetPart);
if(!targetFolder.exists()) {
targetFolder.mkdirs();
}
new FluidEnumGenerator(targetFolder);
}
private FluidEnumGenerator(File targetFolder) throws IOException {
super(targetFolder);
}
@Override
protected String getCategoryID() {
return "minecraft:fluid";
}
@Override
public String getPackageName() {
return "net.minestom.server.fluids";
}
@Override
public String getClassName() {
return "Fluid";
}
}

View File

@ -15,6 +15,7 @@ import net.minestom.server.event.item.ItemDropEvent;
import net.minestom.server.event.item.ItemUpdateStateEvent;
import net.minestom.server.event.item.PickupItemEvent;
import net.minestom.server.event.player.*;
import net.minestom.server.gamedata.tags.TagManager;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceContainer;
@ -27,15 +28,18 @@ import net.minestom.server.item.ItemFlag;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.server.play.TagsPacket;
import net.minestom.server.ping.ResponseDataConsumer;
import net.minestom.server.timer.TaskRunnable;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.Vector;
import net.minestom.server.utils.time.TimeUnit;
import net.minestom.server.utils.time.UpdateOption;
import net.minestom.server.world.Dimension;
import java.io.FileNotFoundException;
import java.util.Map;
import java.util.UUID;
@ -115,7 +119,6 @@ public class PlayerInit {
});
connectionManager.addPlayerInitialization(player -> {
player.addEventCallback(EntityAttackEvent.class, event -> {
Entity entity = event.getTarget();
if (entity instanceof EntityCreature) {

View File

@ -27,7 +27,7 @@ public class NoiseTestGenerator extends ChunkGenerator {
if (random.nextInt(100) > 10) {
batch.setCustomBlock(x, y, z, "custom_block");
} else {
batch.setBlock(x, y, z, Block.DIAMOND_BLOCK);
batch.setBlock(x, y, z, Block.LAVA);
}
}
}

View File

@ -17,6 +17,7 @@ import net.minestom.server.event.item.ItemDropEvent;
import net.minestom.server.event.item.ItemUpdateStateEvent;
import net.minestom.server.event.item.PickupExperienceEvent;
import net.minestom.server.event.player.*;
import net.minestom.server.gamedata.tags.TagManager;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.CustomBlock;
@ -38,15 +39,13 @@ import net.minestom.server.scoreboard.Team;
import net.minestom.server.sound.Sound;
import net.minestom.server.sound.SoundCategory;
import net.minestom.server.stat.PlayerStatistic;
import net.minestom.server.utils.ArrayUtils;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.*;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.utils.validate.Check;
import net.minestom.server.world.Dimension;
import net.minestom.server.world.LevelType;
import java.io.FileNotFoundException;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArraySet;
@ -237,6 +236,16 @@ public class Player extends LivingEntity implements CommandSender {
}
// Recipes end
// Send server tags
TagsPacket tags = new TagsPacket();
TagManager tagManager = MinecraftServer.getTagManager();
tagManager.addRequiredTagsToPacket(tags);
UpdateTagListEvent event = new UpdateTagListEvent(tags);
callEvent(UpdateTagListEvent.class,event);
sendPacketToViewersAndSelf(tags);
// Some client update
playerConnection.sendPacket(getPropertiesPacket()); // Send default properties
refreshHealth(); // Heal and send health packet

View File

@ -0,0 +1,17 @@
package net.minestom.server.event.player;
import net.minestom.server.event.Event;
import net.minestom.server.network.packet.server.play.TagsPacket;
public class UpdateTagListEvent extends Event {
private TagsPacket packet;
public UpdateTagListEvent(TagsPacket packet) {
this.packet = packet;
}
public TagsPacket getTags() {
return packet;
}
}

View File

@ -0,0 +1,21 @@
package net.minestom.server.gamedata.tags;
import net.minestom.server.utils.NamespaceID;
public class RequiredTag {
private final Tag.BasicTypes type;
private final NamespaceID name;
public RequiredTag(Tag.BasicTypes type, NamespaceID name) {
this.type = type;
this.name = name;
}
public NamespaceID getName() {
return name;
}
public Tag.BasicTypes getType() {
return type;
}
}

View File

@ -13,14 +13,16 @@ import java.util.Set;
*/
public class Tag {
public static final Tag EMPTY = new Tag();
public static final Tag EMPTY = new Tag(NamespaceID.from("minestom:empty"));
private final NamespaceID name;
private Set<NamespaceID> values;
/**
* Creates a new empty tag
*/
public Tag() {
public Tag(NamespaceID name) {
this.name = name;
values = new HashSet<>();
lockValues();
}
@ -32,7 +34,8 @@ public class Tag {
* 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 {
public Tag(TagManager manager, NamespaceID name, String type, Tag lowerPriority, TagContainer container) throws FileNotFoundException {
this.name = name;
values = new HashSet<>();
if(!container.replace) {
values.addAll(lowerPriority.values);
@ -70,4 +73,19 @@ public class Tag {
public Set<NamespaceID> getValues() {
return values;
}
/**
* Returns the name of this tag
* @return
*/
public NamespaceID getName() {
return name;
}
public enum BasicTypes {
BLOCKS,
ITEMS,
FLUIDS,
ENTITY_TYPES
}
}

View File

@ -2,13 +2,17 @@ package net.minestom.server.gamedata.tags;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.minestom.server.network.packet.server.play.TagsPacket;
import net.minestom.server.registry.ResourceGatherer;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.NamespaceID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
@ -19,10 +23,14 @@ public class TagManager {
private static final Logger LOGGER = LoggerFactory.getLogger(TagManager.class);
private final Gson gson;
private Map<NamespaceID, Tag> cache = new HashMap<>();
private List<RequiredTag> requiredTags = new LinkedList<>();
public TagManager() {
gson = new GsonBuilder()
.create();
addRequiredTag(Tag.BasicTypes.FLUIDS, NamespaceID.from("lava"));
addRequiredTag(Tag.BasicTypes.FLUIDS, NamespaceID.from("water"));
}
/**
@ -57,7 +65,7 @@ public class TagManager {
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);
Tag result = create(prev, name, tagType, readerSupplier);
cache.put(name, result);
return result;
}
@ -74,7 +82,7 @@ public class TagManager {
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);
return create(prev, name, tagType, readerSupplier);
} catch (FileNotFoundException e) {
ex[0] = e;
return Tag.EMPTY;
@ -86,16 +94,61 @@ public class TagManager {
return result;
}
private Tag create(Tag prev, String tagType, ReaderSupplierWithFileNotFound reader) throws FileNotFoundException {
private Tag create(Tag prev, NamespaceID name, String tagType, ReaderSupplierWithFileNotFound reader) throws FileNotFoundException {
TagContainer container = gson.fromJson(reader.get(), TagContainer.class);
try {
return new Tag(this, tagType, prev, container);
return new Tag(this, name, tagType, prev, container);
} catch (FileNotFoundException e) {
LOGGER.error("Failed to load tag due to error", e);
return Tag.EMPTY;
}
}
/**
* Adds the required tags for the game to function correctly
* @param tags the packet to add the tags to
*/
public void addRequiredTagsToPacket(TagsPacket tags) {
for(RequiredTag requiredTag : requiredTags) {
Tag tag = silentLoad(requiredTag.getName(), requiredTag.getType().name().toLowerCase());
switch (requiredTag.getType()) {
case BLOCKS:
tags.blockTags.add(tag);
break;
case ITEMS:
tags.itemTags.add(tag);
break;
case FLUIDS:
tags.fluidTags.add(tag);
break;
case ENTITY_TYPES:
tags.entityTags.add(tag);
break;
}
}
}
/**
* Adds a required tag to send to players when they connect
* @param type type of tag to send. Required so the client knows its use
* @param name the name of the tag to load
*/
public void addRequiredTag(Tag.BasicTypes type, NamespaceID name) {
requiredTags.add(new RequiredTag(type, name));
}
private Tag silentLoad(NamespaceID name, String type) {
try {
return load(name, type);
} catch (FileNotFoundException e) {
e.printStackTrace();
return Tag.EMPTY;
}
}
public interface ReaderSupplierWithFileNotFound {
Reader get() throws FileNotFoundException;
}

View File

@ -0,0 +1,50 @@
package net.minestom.server.network.packet.server.play;
import net.minestom.server.gamedata.tags.Tag;
import net.minestom.server.network.packet.PacketWriter;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
import net.minestom.server.registry.Registries;
import net.minestom.server.utils.NamespaceID;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
public class TagsPacket implements ServerPacket {
public List<Tag> blockTags = new LinkedList<>();
public List<Tag> itemTags = new LinkedList<>();
public List<Tag> fluidTags = new LinkedList<>();
public List<Tag> entityTags = new LinkedList<>();
@Override
public void write(PacketWriter writer) {
writeTags(writer, blockTags, name -> Registries.getBlock(name).ordinal());
writeTags(writer, itemTags, name -> Registries.getMaterial(name).ordinal());
writeTags(writer, fluidTags, name -> Registries.getFluid(name).ordinal());
writeTags(writer, entityTags, name -> Registries.getEntityType(name).ordinal());
}
private void writeTags(PacketWriter writer, List<Tag> tags, Function<NamespaceID, Integer> idSupplier) {
writer.writeVarInt(tags.size());
for (Tag tag : tags) {
// name
writer.writeSizedString(tag.getName().toString());
Set<NamespaceID> values = tag.getValues();
// count
writer.writeVarInt(values.size());
// entries
for (NamespaceID name : values) {
writer.writeVarInt(idSupplier.apply(name));
}
}
}
@Override
public int getId() {
return ServerPacketIdentifier.TAGS;
}
}