Advancement API

This commit is contained in:
Felix Cravic 2020-08-05 10:56:16 +02:00
parent 981d247f02
commit 61857bd4b6
7 changed files with 402 additions and 55 deletions

View File

@ -3,7 +3,7 @@ package fr.themode.demo;
import fr.themode.demo.generator.ChunkGeneratorDemo;
import fr.themode.demo.generator.NoiseTestGenerator;
import net.minestom.server.MinecraftServer;
import net.minestom.server.advancements.FrameType;
import net.minestom.server.advancements.*;
import net.minestom.server.benchmark.BenchmarkManager;
import net.minestom.server.benchmark.ThreadResult;
import net.minestom.server.chat.ChatColor;
@ -25,7 +25,6 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.item.metadata.MapMeta;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.server.play.AdvancementsPacket;
import net.minestom.server.ping.ResponseDataConsumer;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.Position;
@ -226,62 +225,21 @@ public class PlayerInit {
scoreboard.setTitle("test");*/
// Testing advancements
AdvancementsPacket advancementsPacket = new AdvancementsPacket();
advancementsPacket.resetAdvancements = true;
AdvancementsPacket.AdvancementMapping firstMapping = new AdvancementsPacket.AdvancementMapping();
{
AdvancementsPacket.Advancement firstAdvancement = new AdvancementsPacket.Advancement();
firstMapping.key = "minestom:advancement";
firstMapping.value = firstAdvancement;
AdvancementManager advancementManager = MinecraftServer.getAdvancementManager();
AdvancementRoot root = new AdvancementRoot(ColoredText.of("title"), ColoredText.of(ChatColor.BLUE + "description"),
Material.APPLE, FrameType.TASK, 0, 0, "minecraft:textures/block/red_wool.png");
AdvancementTab tab = advancementManager.createTab("root", root);
Advancement advancement = new Advancement(ColoredText.of("adv"), ColoredText.of("desc"),
Material.WOODEN_AXE, FrameType.CHALLENGE, 1, 0)
.showToast(true).setHidden(false);
tab.createAdvancement("second", advancement, root);
AdvancementsPacket.DisplayData displayData = new AdvancementsPacket.DisplayData();
displayData.x = 0.0F;
displayData.y = 0.0F;
displayData.title = ColoredText.of("Hello");
displayData.description = ColoredText.of("Hello");
displayData.icon = new ItemStack(Material.DIRT, (byte) 1);
displayData.frameType = FrameType.TASK;
displayData.flags = 0x1;
displayData.backgroundTexture = "minecraft:textures/block/red_wool.png";
firstAdvancement.displayData = displayData;
firstAdvancement.criterions = new String[]{};
firstAdvancement.requirements = new AdvancementsPacket.Requirement[]{};
tab.addViewer(player);
advancement.setTitle(ColoredText.of("test ttlechange"));
//player.getPlayerConnection().sendPacket(tab.removePacket());
}
// This advancement will be to the bottom right of the firstAdvancement
// The background of this advancement is apparentely ignored!
AdvancementsPacket.AdvancementMapping secondMapping = new AdvancementsPacket.AdvancementMapping();
{
AdvancementsPacket.Advancement secondAdvancement = new AdvancementsPacket.Advancement();
secondMapping.key = "minestom:advance";
secondMapping.value = secondAdvancement;
secondAdvancement.parentIdentifier = "minestom:advancement";
AdvancementsPacket.DisplayData displayData = new AdvancementsPacket.DisplayData();
displayData.x = 2.0F;
displayData.y = 2.0F;
displayData.title = ColoredText.of("Hello World");
displayData.description = ColoredText.of("Hello World");
displayData.icon = new ItemStack(Material.DIAMOND, (byte) 1);
displayData.frameType = FrameType.GOAL;
displayData.flags = 0x2;
secondAdvancement.displayData = displayData;
secondAdvancement.criterions = new String[]{};
secondAdvancement.requirements = new AdvancementsPacket.Requirement[]{};
}
advancementsPacket.identifiersToRemove = new String[]{};
advancementsPacket.advancementMappings = new AdvancementsPacket.AdvancementMapping[]{firstMapping, secondMapping};
advancementsPacket.progressMappings = new AdvancementsPacket.ProgressMapping[]{};
player.getPlayerConnection().sendPacket(advancementsPacket);
});
player.addEventCallback(PlayerSpawnEvent.class, event -> {

View File

@ -5,6 +5,7 @@ import com.mojang.authlib.minecraft.MinecraftSessionService;
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
import lombok.Getter;
import lombok.Setter;
import net.minestom.server.advancements.AdvancementManager;
import net.minestom.server.benchmark.BenchmarkManager;
import net.minestom.server.command.CommandManager;
import net.minestom.server.data.DataManager;
@ -107,6 +108,7 @@ public class MinecraftServer {
private static SchedulerManager schedulerManager;
private static BenchmarkManager benchmarkManager;
private static DimensionTypeManager dimensionTypeManager;
private static AdvancementManager advancementManager;
private static UpdateManager updateManager;
private static MinecraftServer minecraftServer;
@ -157,6 +159,7 @@ public class MinecraftServer {
schedulerManager = new SchedulerManager();
benchmarkManager = new BenchmarkManager();
dimensionTypeManager = new DimensionTypeManager();
advancementManager = new AdvancementManager();
updateManager = new UpdateManager();
@ -277,6 +280,10 @@ public class MinecraftServer {
return dimensionTypeManager;
}
public static AdvancementManager getAdvancementManager() {
return advancementManager;
}
public static TagManager getTagManager() {
return tagManager;
}

View File

@ -0,0 +1,209 @@
package net.minestom.server.advancements;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.network.packet.server.play.AdvancementsPacket;
public class Advancement {
protected AdvancementTab tab;
private ColoredText title;
private ColoredText description;
private ItemStack icon;
private FrameType frameType;
private String background; // Only on root
private boolean toast;
private boolean hidden;
private float x, y;
private String identifier;
private Advancement parent;
public Advancement(ColoredText title, ColoredText description,
ItemStack icon, FrameType frameType,
float x, float y) {
this.title = title;
this.description = description;
this.icon = icon;
this.frameType = frameType;
this.x = x;
this.y = y;
}
public Advancement(ColoredText title, ColoredText description,
Material icon, FrameType frameType,
float x, float y) {
this(title, description, new ItemStack(icon, (byte) 1), frameType, x, y);
}
public AdvancementTab getTab() {
return tab;
}
public void setTab(AdvancementTab tab) {
this.tab = tab;
}
public ColoredText getTitle() {
return title;
}
public void setTitle(ColoredText title) {
this.title = title;
update();
}
public ColoredText getDescription() {
return description;
}
public void setDescription(ColoredText description) {
this.description = description;
update();
}
public boolean hasToast() {
return toast;
}
public Advancement showToast(boolean toast) {
this.toast = toast;
return this;
}
public boolean isHidden() {
return hidden;
}
public Advancement setHidden(boolean hidden) {
this.hidden = hidden;
update();
return this;
}
public FrameType getFrameType() {
return frameType;
}
public void setFrameType(FrameType frameType) {
this.frameType = frameType;
update();
}
public float getX() {
return x;
}
public void setX(float x) {
this.x = x;
update();
}
public float getY() {
return y;
}
public void setY(float y) {
this.y = y;
update();
}
protected void setBackground(String background) {
this.background = background;
}
protected String getIdentifier() {
return identifier;
}
protected void setIdentifier(String identifier) {
this.identifier = identifier;
}
protected Advancement getParent() {
return parent;
}
protected void setParent(Advancement parent) {
this.parent = parent;
}
protected AdvancementsPacket.DisplayData toDisplayData() {
AdvancementsPacket.DisplayData displayData = new AdvancementsPacket.DisplayData();
displayData.x = x;
displayData.y = y;
displayData.title = title;
displayData.description = description;
displayData.icon = icon;
displayData.frameType = frameType;
displayData.flags = getFlags();
if (background != null) {
displayData.backgroundTexture = background;
}
return displayData;
}
protected AdvancementsPacket getUpdatePacket() {
AdvancementsPacket advancementsPacket = new AdvancementsPacket();
advancementsPacket.resetAdvancements = false;
AdvancementsPacket.AdvancementMapping mapping = new AdvancementsPacket.AdvancementMapping();
{
AdvancementsPacket.Advancement adv = new AdvancementsPacket.Advancement();
mapping.key = getIdentifier();
mapping.value = adv;
final Advancement parent = getParent();
if (parent != null) {
final String parentIdentifier = parent.getIdentifier();
adv.parentIdentifier = parentIdentifier;
}
adv.displayData = toDisplayData();
adv.criterions = new String[]{};
adv.requirements = new AdvancementsPacket.Requirement[]{};
}
advancementsPacket.identifiersToRemove = new String[]{};
advancementsPacket.advancementMappings = new AdvancementsPacket.AdvancementMapping[]{mapping};
advancementsPacket.progressMappings = new AdvancementsPacket.ProgressMapping[]{};
return advancementsPacket;
}
/**
* Update this advancement value when a field is modified
*/
protected void update() {
if (tab != null) {
// TODO: how to update an advancement without clearing everything
//final AdvancementsPacket packet = getUpdatePacket();
//tab.sendPacketToViewers(packet);
}
}
private int getFlags() {
byte result = 0;
if (background != null) {
result |= 0x1;
}
if (hasToast()) {
result |= 0x2;
}
if (isHidden()) {
result |= 0x4;
}
return result;
}
}

View File

@ -0,0 +1,20 @@
package net.minestom.server.advancements;
import java.util.HashMap;
import java.util.Map;
public class AdvancementManager {
private Map<String, AdvancementTab> advancementTabMap = new HashMap<>();
public AdvancementTab createTab(String rootIdentifier, AdvancementRoot root) {
final AdvancementTab advancementTab = new AdvancementTab(rootIdentifier, root);
this.advancementTabMap.put(rootIdentifier, advancementTab);
return advancementTab;
}
public AdvancementTab getTab(String rootIdentifier) {
return advancementTabMap.get(rootIdentifier);
}
}

View File

@ -0,0 +1,25 @@
package net.minestom.server.advancements;
import net.minestom.server.chat.ColoredText;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
public class AdvancementRoot extends Advancement {
public AdvancementRoot(ColoredText title, ColoredText description,
ItemStack icon, FrameType frameType,
float x, float y,
String background) {
super(title, description, icon, frameType, x, y);
setBackground(background);
}
public AdvancementRoot(ColoredText title, ColoredText description,
Material icon, FrameType frameType,
float x, float y,
String background) {
super(title, description, icon, frameType, x, y);
setBackground(background);
}
}

View File

@ -0,0 +1,128 @@
package net.minestom.server.advancements;
import net.minestom.server.Viewable;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.AdvancementsPacket;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.validate.Check;
import java.util.*;
public class AdvancementTab implements Viewable {
private Set<Player> viewers = new HashSet<>();
private Advancement root;
// Advancement -> its parent
private Map<Advancement, Advancement> advancementMap = new HashMap<>();
protected AdvancementTab(String rootIdentifier, Advancement root) {
this.root = root;
cacheAdvancement(rootIdentifier, root, null);
}
public void createAdvancement(String identifier, Advancement advancement, Advancement parent) {
Check.stateCondition(!advancementMap.containsKey(parent),
"You tried to set a parent which doesn't exist or isn't registered");
cacheAdvancement(identifier, advancement, parent);
}
/**
* Build the packet which build the whole advancement tab
*
* @return the packet adding this advancement tab and all its advancements
*/
public AdvancementsPacket createPacket() {
AdvancementsPacket advancementsPacket = new AdvancementsPacket();
advancementsPacket.resetAdvancements = false;
List<AdvancementsPacket.AdvancementMapping> mappings = new ArrayList<>();
for (Advancement advancement : advancementMap.keySet()) {
AdvancementsPacket.AdvancementMapping mapping = new AdvancementsPacket.AdvancementMapping();
{
AdvancementsPacket.Advancement adv = new AdvancementsPacket.Advancement();
mapping.key = advancement.getIdentifier();
mapping.value = adv;
final Advancement parent = advancement.getParent();
if (parent != null) {
final String parentIdentifier = parent.getIdentifier();
adv.parentIdentifier = parentIdentifier;
}
adv.displayData = advancement.toDisplayData();
adv.criterions = new String[]{};
adv.requirements = new AdvancementsPacket.Requirement[]{};
}
mappings.add(mapping);
}
advancementsPacket.identifiersToRemove = new String[]{};
advancementsPacket.advancementMappings = mappings.toArray(new AdvancementsPacket.AdvancementMapping[0]);
advancementsPacket.progressMappings = new AdvancementsPacket.ProgressMapping[]{};
return advancementsPacket;
}
/**
* Create a packet which remove the root advancement
* <p>
* This does in fact remove the whole advancement tab
*
* @return the packet which remove the root advancement
*/
public AdvancementsPacket removePacket() {
AdvancementsPacket advancementsPacket = new AdvancementsPacket();
advancementsPacket.resetAdvancements = false;
advancementsPacket.identifiersToRemove = new String[]{root.getIdentifier()};
advancementsPacket.advancementMappings = new AdvancementsPacket.AdvancementMapping[]{};
advancementsPacket.progressMappings = new AdvancementsPacket.ProgressMapping[]{};
return advancementsPacket;
}
private void cacheAdvancement(String identifier, Advancement advancement, Advancement parent) {
Check.stateCondition(advancement.getTab() != null,
"You tried to add an advancement already linked to a tab");
advancement.setTab(this);
advancement.setIdentifier(identifier);
advancement.setParent(parent);
this.advancementMap.put(advancement, parent);
}
@Override
public boolean addViewer(Player player) {
final boolean result = viewers.add(player);
if (!result) {
return false;
}
final PlayerConnection playerConnection = player.getPlayerConnection();
// Send the tab to the player
playerConnection.sendPacket(createPacket());
return true;
}
@Override
public boolean removeViewer(Player player) {
if (!isViewer(player)) {
return false;
}
final PlayerConnection playerConnection = player.getPlayerConnection();
// Remove the tab
playerConnection.sendPacket(removePacket());
return viewers.remove(player);
}
@Override
public Set<Player> getViewers() {
return viewers;
}
}

View File

@ -40,7 +40,7 @@ public class NotificationCenter {
* Create the packet responsive for showing the Toast to players
*
* @param notification the notification
* @return the packet to show the Toast
* @return the packet used to show the Toast
*/
private static AdvancementsPacket getCreatePacket(Notification notification) {
// For An advancement to be shown, it must have all of it's criteria achieved (progress 100%)