Spellbook chapters are now server-controlled

This commit is contained in:
Sollace 2022-09-12 01:46:48 +02:00
parent e721568312
commit 17d3d92416
18 changed files with 308 additions and 143 deletions

View file

@ -19,6 +19,7 @@ import com.minelittlepony.unicopia.advancement.UCriteria;
import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.block.state.StateMapLoader;
import com.minelittlepony.unicopia.command.Commands;
import com.minelittlepony.unicopia.container.SpellbookChapterLoader;
import com.minelittlepony.unicopia.container.UScreenHandlers;
import com.minelittlepony.unicopia.entity.UEntities;
import com.minelittlepony.unicopia.entity.effect.UPotions;
@ -62,6 +63,7 @@ public class Unicopia implements ModInitializer {
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(UEnchantments.POISONED_JOKE);
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(new TraitLoader());
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(StateMapLoader.INSTANCE);
ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(SpellbookChapterLoader.INSTANCE);
UBlocks.bootstrap();
UItems.bootstrap();

View file

@ -10,7 +10,6 @@ import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.client.gui.LanSettingsScreen;
import com.minelittlepony.unicopia.client.gui.UHud;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterLoader;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookScreen;
import com.minelittlepony.unicopia.client.minelittlepony.MineLPConnector;
import com.minelittlepony.unicopia.container.*;
@ -19,14 +18,12 @@ import com.minelittlepony.unicopia.entity.player.Pony;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.OpenToLanScreen;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreens;
import net.minecraft.client.gui.screen.world.CreateWorldScreen;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.resource.ResourceType;
import net.minecraft.text.Text;
public class UnicopiaClient implements ClientModInitializer {
@ -66,7 +63,6 @@ public class UnicopiaClient implements ClientModInitializer {
URenderers.bootstrap();
HandledScreens.register(UScreenHandlers.SPELL_BOOK, SpellbookScreen::new);
ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(SpellbookChapterLoader.INSTANCE);
ClientTickEvents.END_CLIENT_TICK.register(this::onTick);
ScreenInitCallback.EVENT.register(this::onScreenInit);

View file

@ -0,0 +1,28 @@
package com.minelittlepony.unicopia.client.gui.spellbook;
import java.util.*;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.*;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.*;
public class ClientChapters {
private static Map<Identifier, Chapter> CHAPTERS = new HashMap<>();
public static Set<SpellbookChapterList.Chapter> getChapters() {
return new HashSet<>(CHAPTERS.values());
}
public static void load(Map<Identifier, Chapter> chapters) {
CHAPTERS = chapters;
}
public static Chapter loadChapter(PacketByteBuf buffer) {
return new Chapter(
buffer.readIdentifier(),
buffer.readEnumConstant(TabSide.class),
buffer.readInt(),
buffer.readInt(),
buffer.readOptional(DynamicContent::new)
);
}
}

View file

@ -2,16 +2,17 @@ package com.minelittlepony.unicopia.client.gui.spellbook;
import java.util.*;
import com.google.gson.*;
import com.minelittlepony.common.client.gui.IViewRoot;
import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.unicopia.client.gui.DrawableUtil;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Content;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Drawable;
import com.minelittlepony.unicopia.container.SpellbookChapterLoader.Flow;
import com.minelittlepony.unicopia.container.SpellbookState;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.Text;
import net.minecraft.util.*;
@ -20,12 +21,12 @@ public class DynamicContent implements Content {
private static final Text UNKNOWN_LEVEL = Text.literal("Level: ???").formatted(Formatting.DARK_GREEN);
private SpellbookState.PageState state = new SpellbookState.PageState();
private final List<Page> pages = new ArrayList<>();
private final List<Page> pages;
private Bounds bounds = Bounds.empty();
public DynamicContent(JsonArray json) {
json.forEach(element -> pages.add(new Page(element.getAsJsonObject())));
public DynamicContent(PacketByteBuf buffer) {
pages = buffer.readList(Page::new);
}
@Override
@ -76,21 +77,19 @@ public class DynamicContent implements Content {
}
class Page implements Drawable {
private final List<PageElement> elements = new ArrayList<>();
private final Text title;
private final int level;
private final List<PageElement> elements;
private boolean compiled;
private Bounds bounds = Bounds.empty();
public Page(JsonObject json) {
title = Text.Serializer.fromJson(json.get("title"));
level = JsonHelper.getInt(json, "level", 0);
JsonHelper.getArray(json, "elements", new JsonArray()).forEach(element -> {
elements.add(PageElement.fromJson(this, element));
});
public Page(PacketByteBuf buffer) {
title = buffer.readText();
level = buffer.readInt();
elements = buffer.readList(r -> PageElement.read(this, r));
}
protected int getLineLimitAt(int yPosition) {
@ -104,7 +103,7 @@ public class DynamicContent implements Content {
protected int getLeftMarginAt(int yPosition) {
return elements.stream()
.filter(p -> p.flow() == PageElement.Flow.LEFT)
.filter(p -> p.flow() == Flow.LEFT)
.map(PageElement::bounds)
.filter(b -> b.containsY(yPosition))
.mapToInt(b -> b.width)

View file

@ -3,14 +3,13 @@ package com.minelittlepony.unicopia.client.gui.spellbook;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.minelittlepony.common.client.gui.IViewRoot;
import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.unicopia.ability.magic.spell.crafting.IngredientWithSpell;
import com.minelittlepony.unicopia.ability.magic.spell.crafting.SpellbookRecipe;
import com.minelittlepony.unicopia.client.gui.ParagraphWrappingVisitor;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Drawable;
import com.minelittlepony.unicopia.container.SpellbookChapterLoader.Flow;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.mojang.blaze3d.systems.RenderSystem;
@ -18,6 +17,7 @@ import net.minecraft.client.MinecraftClient;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawableHelper;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.Style;
import net.minecraft.text.Text;
import net.minecraft.util.*;
@ -44,37 +44,19 @@ interface PageElement extends Drawable {
default void compile(int y, IViewRoot Container) {}
static PageElement fromJson(DynamicContent.Page page, JsonElement element) {
if (element.isJsonPrimitive()) {
return new TextBlock(page, Text.Serializer.fromJson(element));
}
JsonObject el = JsonHelper.asObject(element, "element");
if (el.has("texture")) {
return new Image(
new Identifier(JsonHelper.getString(el, "texture")),
boundsFromJson(el),
Flow.valueOf(JsonHelper.getString(el, "flow", "RIGHT"))
);
}
if (el.has("recipe")) {
return new Recipe(page, new Identifier(JsonHelper.getString(el, "recipe")), new Bounds(0, 0, 0, 0));
}
if (el.has("item")) {
return new Stack(page, IngredientWithSpell.fromJson(el.get("item")), boundsFromJson(el));
}
return new TextBlock(page, Text.Serializer.fromJson(element));
static PageElement read(DynamicContent.Page page, PacketByteBuf buffer) {
byte type = buffer.readByte();
return (switch (type) {
case 0 -> new Image(buffer.readIdentifier(), boundsFromBuffer(buffer), buffer.readEnumConstant(Flow.class));
case 1 -> new Recipe(page, buffer.readIdentifier(), Bounds.empty());
case 2 -> new Stack(page, IngredientWithSpell.fromPacket(buffer), boundsFromBuffer(buffer));
case 3 -> new TextBlock(page, buffer.readText());
default -> throw new IllegalArgumentException("Unexpected value: " + type);
});
}
private static Bounds boundsFromJson(JsonObject el) {
return new Bounds(
JsonHelper.getInt(el, "y", 0),
JsonHelper.getInt(el, "x", 0),
JsonHelper.getInt(el, "width", 0),
JsonHelper.getInt(el, "height", 0)
);
private static Bounds boundsFromBuffer(PacketByteBuf buffer) {
return new Bounds(buffer.readInt(), buffer.readInt(), buffer.readInt(), buffer.readInt());
}
record Image(
@ -171,8 +153,4 @@ interface PageElement extends Drawable {
bounds.height = tree.build(container) - 10;
}
}
enum Flow {
NONE, LEFT, RIGHT
}
}

View file

@ -6,6 +6,7 @@ import java.util.stream.Stream;
import com.minelittlepony.common.client.gui.IViewRoot;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.container.SpellbookChapterLoader;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.util.Identifier;
@ -24,7 +25,7 @@ public class SpellbookChapterList {
public SpellbookChapterList(SpellbookScreen screen, Chapter craftingChapter, Chapter... builtIn) {
this.screen = screen;
this.craftingChapter = craftingChapter;
SpellbookChapterLoader.INSTANCE.getChapters().forEach(chapter -> {
ClientChapters.getChapters().forEach(chapter -> {
chapters.put(chapter.id(), chapter);
});
chapters.put(craftingChapter.id(), craftingChapter);
@ -39,7 +40,7 @@ public class SpellbookChapterList {
public Chapter getCurrentChapter() {
if (SpellbookChapterLoader.DEBUG) {
SpellbookChapterLoader.INSTANCE.getChapters().forEach(chapter -> {
ClientChapters.getChapters().forEach(chapter -> {
Optional.ofNullable(chapters.get(chapter.id())).flatMap(Chapter::content).ifPresent(old -> {
chapter.content().ifPresent(neu -> neu.copyStateFrom(old));
});

View file

@ -1,74 +0,0 @@
package com.minelittlepony.unicopia.client.gui.spellbook;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import com.google.gson.*;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.*;
import com.minelittlepony.unicopia.util.Resources;
import com.mojang.logging.LogUtils;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.minecraft.client.MinecraftClient;
import net.minecraft.resource.JsonDataLoader;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.*;
import net.minecraft.util.profiler.Profiler;
public class SpellbookChapterLoader extends JsonDataLoader implements IdentifiableResourceReloadListener {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Identifier ID = Unicopia.id("spellbook/chapters");
private static final Executor EXECUTOR = CompletableFuture.delayedExecutor(5, TimeUnit.SECONDS);
public static boolean DEBUG = false;
public static final SpellbookChapterLoader INSTANCE = new SpellbookChapterLoader();
private Map<Identifier, Chapter> chapters = new HashMap<>();
public SpellbookChapterLoader() {
super(Resources.GSON, ID.getPath());
}
@Override
public Identifier getFabricId() {
return ID;
}
public Set<SpellbookChapterList.Chapter> getChapters() {
return new HashSet<>(chapters.values());
}
@Override
protected void apply(Map<Identifier, JsonElement> data, ResourceManager manager, Profiler profiler) {
try {
chapters = data.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> {
JsonObject json = JsonHelper.asObject(entry.getValue(), "root");
return new Chapter(entry.getKey(),
TabSide.valueOf(JsonHelper.getString(json, "side")),
JsonHelper.getInt(json, "y_position"),
JsonHelper.getInt(json, "color", 0),
loadContent(JsonHelper.getObject(json, "content", new JsonObject()))
);
}));
} catch (IllegalStateException | JsonParseException e) {
LOGGER.error("Could not load spellbook chapters due to exception", e);
}
if (DEBUG) {
CompletableFuture.runAsync(() -> {
reload(CompletableFuture::completedFuture, manager, profiler, profiler, Util.getMainWorkerExecutor(), MinecraftClient.getInstance());
}, EXECUTOR);
}
}
private Optional<Content> loadContent(JsonObject json) {
return Optional.of(JsonHelper.getArray(json, "pages", new JsonArray()))
.filter(pages -> pages.size() > 0)
.map(DynamicContent::new);
}
}

View file

@ -0,0 +1,218 @@
package com.minelittlepony.unicopia.container;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import org.slf4j.Logger;
import com.google.gson.*;
import com.minelittlepony.common.client.gui.dimension.Bounds;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.magic.spell.crafting.IngredientWithSpell;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.*;
import com.minelittlepony.unicopia.util.Resources;
import com.mojang.logging.LogUtils;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.minecraft.client.MinecraftClient;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.resource.JsonDataLoader;
import net.minecraft.resource.ResourceManager;
import net.minecraft.text.Text;
import net.minecraft.util.*;
import net.minecraft.util.profiler.Profiler;
public class SpellbookChapterLoader extends JsonDataLoader implements IdentifiableResourceReloadListener {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Identifier ID = Unicopia.id("spellbook/chapters");
private static final Executor EXECUTOR = CompletableFuture.delayedExecutor(5, TimeUnit.SECONDS);
public static boolean DEBUG = false;
public static final SpellbookChapterLoader INSTANCE = new SpellbookChapterLoader();
private Map<Identifier, Chapter> chapters = new HashMap<>();
public SpellbookChapterLoader() {
super(Resources.GSON, ID.getPath());
}
@Override
public Identifier getFabricId() {
return ID;
}
public Map<Identifier, Chapter> getChapters() {
return chapters;
}
@Override
protected void apply(Map<Identifier, JsonElement> data, ResourceManager manager, Profiler profiler) {
try {
chapters = data.entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey,
entry -> new Chapter(entry.getKey(), JsonHelper.asObject(entry.getValue(), "root"))
));
} catch (IllegalStateException | JsonParseException e) {
LOGGER.error("Could not load spellbook chapters due to exception", e);
}
if (DEBUG) {
CompletableFuture.runAsync(() -> {
reload(CompletableFuture::completedFuture, manager, profiler, profiler, Util.getMainWorkerExecutor(), MinecraftClient.getInstance());
}, EXECUTOR);
}
}
public record Chapter (
Identifier id,
TabSide side,
int tabY,
int color,
List<Page> pages) {
public Chapter(Identifier id, JsonObject json) {
this(id,
TabSide.valueOf(JsonHelper.getString(json, "side")),
JsonHelper.getInt(json, "y_position"),
JsonHelper.getInt(json, "color", 0),
loadContent(JsonHelper.getObject(json, "content", new JsonObject()))
);
}
private static List<Page> loadContent(JsonObject json) {
return Optional.of(JsonHelper.getArray(json, "pages", new JsonArray()))
.filter(pages -> pages.size() > 0)
.stream()
.flatMap(pages -> StreamSupport.stream(pages.spliterator(), false))
.map(Page::new)
.toList();
}
public void write(PacketByteBuf buffer) {
buffer.writeIdentifier(id);
buffer.writeEnumConstant(side);
buffer.writeInt(tabY);
buffer.writeInt(color);
buffer.writeBoolean(true);
buffer.writeCollection(pages, Page::write);
}
}
private record Page (
Text title,
int level,
List<Element> elements
) {
public Page(JsonElement json) {
this(json.getAsJsonObject());
}
public Page(JsonObject json) {
this(
Text.Serializer.fromJson(json.get("title")),
JsonHelper.getInt(json, "level", 0),
new ArrayList<Element>()
);
JsonHelper.getArray(json, "elements", new JsonArray()).forEach(element -> {
elements.add(Element.read(element));
});
}
public void toBuffer(PacketByteBuf buffer) {
buffer.writeText(title);
buffer.writeInt(level);
buffer.writeCollection(elements, Element::write);
}
public static void write(PacketByteBuf buffer, Page page) {
page.toBuffer(buffer);
}
}
public enum Flow {
NONE, LEFT, RIGHT
}
private interface Element {
void toBuffer(PacketByteBuf buffer);
record Image (Identifier texture, Bounds bounds, Flow flow) implements Element {
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeByte(0);
buffer.writeIdentifier(texture);
boundsToBuffer(bounds, buffer);
buffer.writeEnumConstant(flow);
}
}
record Recipe (Identifier id) implements Element {
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeByte(1);
buffer.writeIdentifier(id);
}
}
record Stack (IngredientWithSpell ingredient, Bounds bounds) implements Element {
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeByte(2);
ingredient.write(buffer);
boundsToBuffer(bounds, buffer);
}
}
record TextBlock (Text text) implements Element {
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeByte(3);
buffer.writeText(text);
}
}
static void write(PacketByteBuf buffer, Element element) {
element.toBuffer(buffer);
}
static Element read(JsonElement json) {
if (!json.isJsonPrimitive()) {
JsonObject el = JsonHelper.asObject(json, "element");
if (el.has("texture")) {
return new Image(
new Identifier(JsonHelper.getString(el, "texture")),
boundsFromJson(el),
Flow.valueOf(JsonHelper.getString(el, "flow", "RIGHT"))
);
}
if (el.has("recipe")) {
return new Recipe(new Identifier(JsonHelper.getString(el, "recipe")));
}
if (el.has("item")) {
return new Stack(IngredientWithSpell.fromJson(el.get("item")), boundsFromJson(el));
}
}
return new TextBlock(Text.Serializer.fromJson(json));
}
private static Bounds boundsFromJson(JsonObject el) {
return new Bounds(
JsonHelper.getInt(el, "y", 0),
JsonHelper.getInt(el, "x", 0),
JsonHelper.getInt(el, "width", 0),
JsonHelper.getInt(el, "height", 0)
);
}
private static void boundsToBuffer(Bounds bounds, PacketByteBuf buffer) {
buffer.writeInt(bounds.top);
buffer.writeInt(bounds.left);
buffer.writeInt(bounds.width);
buffer.writeInt(bounds.height);
}
}
}

View file

@ -2,31 +2,41 @@ package com.minelittlepony.unicopia.network;
import java.util.*;
import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.client.gui.spellbook.ClientChapters;
import com.minelittlepony.unicopia.container.SpellbookChapterLoader;
import com.minelittlepony.unicopia.util.network.Packet;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.Identifier;
public class MsgServerResources implements Packet<PlayerEntity> {
private final Map<Identifier, SpellTraits> entries;
public final Map<Identifier, SpellTraits> traits;
public final Map<Identifier, ?> chapters;
public MsgServerResources() {
entries = SpellTraits.all();
traits = SpellTraits.all();
chapters = SpellbookChapterLoader.INSTANCE.getChapters();
}
@Environment(EnvType.CLIENT)
public MsgServerResources(PacketByteBuf buffer) {
entries = buffer.readMap(PacketByteBuf::readIdentifier, SpellTraits::fromPacket);
traits = buffer.readMap(PacketByteBuf::readIdentifier, SpellTraits::fromPacket);
chapters = buffer.readMap(PacketByteBuf::readIdentifier, ClientChapters::loadChapter);
}
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeMap(entries, PacketByteBuf::writeIdentifier, (r, v) -> v.write(r));
buffer.writeMap(traits, PacketByteBuf::writeIdentifier, (r, v) -> v.write(r));
buffer.writeMap(chapters, PacketByteBuf::writeIdentifier, (r, v) -> ((SpellbookChapterLoader.Chapter)v).write(r));
}
@Override
public void handle(PlayerEntity sender) {
SpellTraits.load(entries);
InteractionManager.instance().getClientNetworkHandler().handleServerResources(this);
}
}

View file

@ -1,10 +1,6 @@
package com.minelittlepony.unicopia.network.handler;
import com.minelittlepony.unicopia.network.MsgBlockDestruction;
import com.minelittlepony.unicopia.network.MsgCancelPlayerAbility;
import com.minelittlepony.unicopia.network.MsgSpawnProjectile;
import com.minelittlepony.unicopia.network.MsgTribeSelect;
import com.minelittlepony.unicopia.network.MsgUnlockTraits;
import com.minelittlepony.unicopia.network.*;
public interface ClientNetworkHandler {
@ -17,4 +13,6 @@ public interface ClientNetworkHandler {
void handleCancelAbility(MsgCancelPlayerAbility packet);
void handleUnlockTraits(MsgUnlockTraits packet);
void handleServerResources(MsgServerResources packet);
}

View file

@ -1,23 +1,25 @@
package com.minelittlepony.unicopia.network.handler;
import java.util.Map;
import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Owned;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.client.ClientBlockDestructionManager;
import com.minelittlepony.unicopia.client.DiscoveryToast;
import com.minelittlepony.unicopia.client.gui.TribeSelectionScreen;
import com.minelittlepony.unicopia.client.gui.spellbook.ClientChapters;
import com.minelittlepony.unicopia.client.gui.spellbook.SpellbookChapterList.Chapter;
import com.minelittlepony.unicopia.entity.UEntities;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.network.MsgBlockDestruction;
import com.minelittlepony.unicopia.network.MsgCancelPlayerAbility;
import com.minelittlepony.unicopia.network.MsgSpawnProjectile;
import com.minelittlepony.unicopia.network.MsgTribeSelect;
import com.minelittlepony.unicopia.network.MsgUnlockTraits;
import com.minelittlepony.unicopia.network.*;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.entity.Entity;
import net.minecraft.util.Identifier;
public class ClientNetworkHandlerImpl implements ClientNetworkHandler {
@ -74,4 +76,11 @@ public class ClientNetworkHandlerImpl implements ClientNetworkHandler {
DiscoveryToast.show(client.getToastManager(), trait.getSprite());
}
}
@SuppressWarnings("unchecked")
@Override
public void handleServerResources(MsgServerResources packet) {
SpellTraits.load(packet.traits);
ClientChapters.load((Map<Identifier, Chapter>)packet.chapters);
}
}