Implement networking, reimplement pega-reach

This commit is contained in:
Sollace 2020-04-23 23:44:31 +02:00
parent 2536872aad
commit 5708f9c80f
36 changed files with 367 additions and 608 deletions

View file

@ -1,23 +0,0 @@
package com.minelittlepony.jumpingcastle.api;
import java.util.UUID;
import javax.annotation.Nullable;
import com.minelittlepony.jumpingcastle.api.payload.BinaryPayload;
/**
* Implementor for a Jumping Castle API bus.
*/
public interface Bus {
void sendToServer(String channel, long id, Message message, Target target);
void sendToClient(String channel, long id, Message message, UUID playerId);
void sendToClient(UUID playerId, BinaryPayload forwarded);
@Nullable
Object getMinecraftServer();
Server getServer();
}

View file

@ -1,60 +0,0 @@
package com.minelittlepony.jumpingcastle.api;
import java.util.UUID;
/**
* A channel for sending and recieving messages.
*/
public interface Channel {
/**
* Registers a handler for a specific message type transmitted over this channel.
*
* @param messageType The message type being recieved.
* @param handler A handler instance to handle the message.
*/
<T extends Message> Channel listenFor(Class<T> messageType, Message.Handler<T> handler);
/**
* Registers a handler for a specific message type transmitted over this channel.
*
* @param messageType The message type being recieved.
*/
<T extends Message & Message.Handler<T>> Channel listenFor(Class<T> messageType);
/**
* Gets the minecraft server
*/
<T> T getServer();
/**
* Sends a message over this channel. By default targets all other clients listening on this channel.
*
* @param message The message to send.
*/
default Channel send(Message message) {
return send(message, Target.CLIENTS);
}
/**
* Sends a message over this channel.
*
* @param message The message to send.
* @param target Recipients that must handle this message (clients, server, or both)
*/
Channel send(Message message, Target target);
/**
* Sends a message back. Use this if you're a server.
*
* @param message The message to send.
* @param recipient Recipient that must handle this message
*/
Channel respond(Message message, UUID recipient);
/**
* Sends a message back to all clients. Use this if you're a server.
*
* @param message The message to send.
*/
Channel broadcast(Message message);
}

View file

@ -1,28 +0,0 @@
package com.minelittlepony.jumpingcastle.api;
/**
* Jumping Castle main interface.
* <p>
*{@code
* JumpingCastle.listen("My Channel").consume(MyMessage.class, (msg, channel) -> {
* ...
* });
*
*/
public interface JumpingCastle {
/**
* Gets or creates a new channel indexed by the given identifier.
*
* @param channelName The channel name
*
* @return An instance of IChannel.
*/
static Channel subscribeTo(String channelName, Client clientHandler) {
return null;// TODO: JumpingFabric
}
@FunctionalInterface
public interface Client {
void connectionEstablished();
}
}

View file

@ -1,45 +0,0 @@
package com.minelittlepony.jumpingcastle.api;
import com.minelittlepony.jumpingcastle.api.payload.Serializable;
/**
* A message for communicating over a channel.
* Fields marked with @Expose are automatically serialized to the output packet stream
* and will be made available on the far end of the pipe.
*
* Override the read and write methods to customise this behaviour.
*
*/
public interface Message extends Serializable<Message> {
/**
* Gets a unique identifier to represent a packet over channel communications.
*/
static long identifier(Class<? extends Message> cls) {
return cls.getCanonicalName().hashCode();
}
/**
* Gets a unique identifier to represent this packet over channel communications.
*/
default long identifier() {
return identifier(getClass());
}
/**
* Handler interface for incoming messages.
*
* @param <T> The type of message to handle.
*/
@FunctionalInterface
public interface Handler<T extends Message> {
/**
* Called when a new message is received.
*
* @param message The message received.
*
* @param channel The channel used to deliver the message.
*/
void onPayload(T message, Channel channel);
}
}

View file

@ -1,7 +0,0 @@
package com.minelittlepony.jumpingcastle.api;
import java.util.UUID;
public interface Server {
void stopTrackingPlayer(UUID playerId);
}

View file

@ -1,43 +0,0 @@
package com.minelittlepony.jumpingcastle.api;
/**
* Targeting method to control who receives a message when sent.
* Senders choose whether a message is received on other clients, just the server, or both.
*/
public enum Target {
/**
* Message is ignored by the server and forwarded to connected clients.
*/
CLIENTS(true, false),
/**
* Only the server should process this message. Clients ignore it.
*/
SERVER(false, true),
/**
* The server should process this message and forward it to all available clients.
*/
SERVER_AND_CLIENTS(true, true);
private final boolean clients;
private final boolean servers;
Target(boolean clients, boolean servers) {
this.clients = clients;
this.servers = servers;
}
/**
* True if messages with this targeting must be processed by the client.
*/
public boolean isClients() {
return clients;
}
/**
* True if messages with this targeting must be processed by the server.
*/
public boolean isServers() {
return servers;
}
}

View file

@ -1,63 +0,0 @@
package com.minelittlepony.jumpingcastle.api.payload;
import javax.annotation.Nullable;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
public interface BinaryPayload {
@Nullable
static BinaryPayload of(Object buffer) {
if (buffer instanceof ByteBuf) {
return ByteBufBinaryPayload.of((ByteBuf)buffer);
}
return null;
}
static BinaryPayload create() {
return of(Unpooled.buffer());
}
<T> T buff();
byte[] bytes();
byte[] readToEnd();
long readLong();
BinaryPayload writeLong(long l);
int readInt();
BinaryPayload writeInt(int b);
byte readByte();
BinaryPayload writeByte(byte b);
String readString();
BinaryPayload writeString(String s);
byte[] readBytes(int len);
BinaryPayload writeBytes(byte[] bytes);
BinaryPayload reverse();
@SuppressWarnings("unchecked")
default <T extends Serializable<? super T>> T readBinary(Class<T> type) {
try {
return (T)type.newInstance().read(this);
} catch (InstantiationException | IllegalAccessException e) {
return null;
}
}
default <T extends Serializable<T>> BinaryPayload writeBinary(T message) {
message.write(this);
return this;
}
}

View file

@ -1,89 +0,0 @@
package com.minelittlepony.jumpingcastle.api.payload;
import java.nio.charset.StandardCharsets;
import io.netty.buffer.ByteBuf;
interface ByteBufBinaryPayload extends BinaryPayload {
static BinaryPayload of(ByteBuf buff) {
return (ByteBufBinaryPayload)(() -> buff);
}
@SuppressWarnings("unchecked")
ByteBuf buff();
@Override
default String readString() {
return buff().readCharSequence(readInt(), StandardCharsets.UTF_8).toString();
}
@Override
default int readInt() {
return buff().readInt();
}
@Override
default BinaryPayload writeInt(int b) {
buff().writeInt(b);
return this;
}
@Override
default byte readByte() {
return buff().readByte();
}
@Override
default BinaryPayload writeByte(byte b) {
buff().writeByte(b);
return this;
}
default byte[] bytes() {
return buff().array();
}
default byte[] readToEnd() {
byte[] bytes = new byte[buff().writerIndex() - buff().readerIndex()];
buff().readBytes(bytes);
return bytes;
}
@Override
default long readLong() {
return buff().readLong();
}
@Override
default BinaryPayload writeLong(long l) {
buff().writeLong(l);
return this;
}
@Override
default BinaryPayload reverse() {
buff().readerIndex(0);
return this;
}
@Override
default byte[] readBytes(int len) {
byte[] data = new byte[len];
buff().readBytes(data);
return data;
}
@Override
default BinaryPayload writeBytes(byte[] bytes) {
buff().writeBytes(bytes);
return this;
}
@Override
default BinaryPayload writeString(String s) {
buff().writeInt(s.getBytes(StandardCharsets.UTF_8).length);
buff().writeCharSequence(s, StandardCharsets.UTF_8);
return this;
}
}

View file

@ -1,19 +0,0 @@
package com.minelittlepony.jumpingcastle.api.payload;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class JsonSerializer {
private static final Gson READER_GSON = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
public static <T> T read(BinaryPayload payload, Class<T> type) {
return (T)READER_GSON.fromJson(payload.readString(), type);
}
public static <T> void write(BinaryPayload payload, T object) {
payload.writeString(READER_GSON.toJson(object));
}
}

View file

@ -1,19 +0,0 @@
package com.minelittlepony.jumpingcastle.api.payload;
public interface Serializable<T extends Serializable<T>> {
/**
* Reads the contents of this message from a networking payload.
*/
@SuppressWarnings("unchecked")
default T read(BinaryPayload payload) {
return (T)JsonSerializer.read(payload, getClass());
}
/**
* Writes the contents of this message to a networking payload.
*/
default void write(BinaryPayload payload) {
JsonSerializer.write(payload, this);
}
}

View file

@ -16,7 +16,7 @@ import net.minecraft.world.World;
@Deprecated @Deprecated
public class CustomDrops { public class CustomDrops {
// TODO: loot table // XXX: loot table
public void addAuxiliaryDrops(World world, BlockState state, BlockPos pos, List<ItemStack> drops, int fortune) { public void addAuxiliaryDrops(World world, BlockState state, BlockPos pos, List<ItemStack> drops, int fortune) {
Block block = state.getBlock(); Block block = state.getBlock();

View file

@ -18,7 +18,7 @@ import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
public final class TreeType { public final class TreeType {
// TODO: move to datapack // XXX: move to datapack
private static final Set<TreeType> REGISTRY = new HashSet<>(); private static final Set<TreeType> REGISTRY = new HashSet<>();
public static final TreeType NONE = new TreeType("none", new Weighted<Supplier<ItemStack>>()); public static final TreeType NONE = new TreeType("none", new Weighted<Supplier<ItemStack>>());

View file

@ -8,8 +8,6 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import com.minelittlepony.common.util.GamePaths; import com.minelittlepony.common.util.GamePaths;
import com.minelittlepony.jumpingcastle.api.Channel;
import com.minelittlepony.jumpingcastle.api.JumpingCastle;
import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.advancement.BOHDeathCriterion; import com.minelittlepony.unicopia.advancement.BOHDeathCriterion;
import com.minelittlepony.unicopia.block.UBlocks; import com.minelittlepony.unicopia.block.UBlocks;
@ -17,39 +15,28 @@ import com.minelittlepony.unicopia.command.Commands;
import com.minelittlepony.unicopia.container.UContainers; import com.minelittlepony.unicopia.container.UContainers;
import com.minelittlepony.unicopia.enchanting.Pages; import com.minelittlepony.unicopia.enchanting.Pages;
import com.minelittlepony.unicopia.enchanting.recipe.AffineIngredients; import com.minelittlepony.unicopia.enchanting.recipe.AffineIngredients;
import com.minelittlepony.unicopia.enchanting.recipe.URecipes;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.mixin.CriterionsRegistry; import com.minelittlepony.unicopia.mixin.CriterionsRegistry;
import com.minelittlepony.unicopia.network.MsgPlayerAbility; import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgPlayerCapabilities;
import com.minelittlepony.unicopia.network.MsgRequestCapabilities;
import com.minelittlepony.unicopia.structure.UStructures; import com.minelittlepony.unicopia.structure.UStructures;
public class Unicopia implements ModInitializer { public class Unicopia implements ModInitializer {
public static final String MODID = "unicopia"; public static final String MODID = "unicopia";
public static final Logger LOGGER = LogManager.getLogger(); public static final Logger LOGGER = LogManager.getLogger();
private static Channel channel;
public static Channel getConnection() {
return channel;
}
@Override @Override
public void onInitialize() { public void onInitialize() {
Config.init(GamePaths.getConfigDirectory()); Config.init(GamePaths.getConfigDirectory());
channel = JumpingCastle.subscribeTo(MODID, () -> {}) Channel.bootstrap();
.listenFor(MsgRequestCapabilities.class)
.listenFor(MsgPlayerCapabilities.class)
.listenFor(MsgPlayerAbility.class);
UTags.bootstrap(); UTags.bootstrap();
Commands.bootstrap(); Commands.bootstrap();
UBlocks.bootstrap(); UBlocks.bootstrap();
UItems.bootstrap(); UItems.bootstrap();
UContainers.bootstrap(); UContainers.bootstrap();
UStructures.bootstrap(); UStructures.bootstrap();
URecipes.bootstrap();
Abilities.getInstance().init(); Abilities.getInstance().init();
CriterionsRegistry.register(BOHDeathCriterion.INSTANCE); CriterionsRegistry.register(BOHDeathCriterion.INSTANCE);

View file

@ -50,7 +50,7 @@ public class UnicornCastingAbility implements Ability<Ability.Hit> {
@Override @Override
public void apply(Pony player, Hit data) { public void apply(Pony player, Hit data) {
// TODO: A way for the player to select which effect they want // XXX: A way for the player to select which effect they want
if (player.getEffect() instanceof ShieldSpell) { if (player.getEffect() instanceof ShieldSpell) {
player.setEffect(null); player.setEffect(null);
} else { } else {

View file

@ -6,11 +6,9 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.common.event.ClientReadyCallback; import com.minelittlepony.common.event.ClientReadyCallback;
import com.minelittlepony.jumpingcastle.api.Target;
import com.minelittlepony.unicopia.Config; import com.minelittlepony.unicopia.Config;
import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.block.UBlocks; import com.minelittlepony.unicopia.block.UBlocks;
import com.minelittlepony.unicopia.container.SpellbookResultSlot; import com.minelittlepony.unicopia.container.SpellbookResultSlot;
@ -19,6 +17,7 @@ import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.UItems; import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.magic.spell.SpellRegistry; import com.minelittlepony.unicopia.magic.spell.SpellRegistry;
import com.minelittlepony.unicopia.mixin.client.DefaultTexturesRegistry; import com.minelittlepony.unicopia.mixin.client.DefaultTexturesRegistry;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgRequestCapabilities; import com.minelittlepony.unicopia.network.MsgRequestCapabilities;
import com.minelittlepony.unicopia.util.dummy.DummyClientPlayerEntity; import com.minelittlepony.unicopia.util.dummy.DummyClientPlayerEntity;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
@ -84,7 +83,7 @@ public class UnicopiaClient extends InteractionManager implements ClientModIniti
if (newRace != clientPlayerRace) { if (newRace != clientPlayerRace) {
clientPlayerRace = newRace; clientPlayerRace = newRace;
Unicopia.getConnection().send(new MsgRequestCapabilities(player, clientPlayerRace), Target.SERVER); Channel.REQUEST_CAPABILITIES.send(new MsgRequestCapabilities(player, clientPlayerRace));
} }
} }

View file

@ -5,7 +5,7 @@ import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.client.MinecraftClient; import net.minecraft.client.MinecraftClient;
@Deprecated @Deprecated
// TODO: forge events // XXX: hud render events
class HudHooks { class HudHooks {
public static void beforePreRenderHud() { public static void beforePreRenderHud() {
MinecraftClient client = MinecraftClient.getInstance(); MinecraftClient client = MinecraftClient.getInstance();

View file

@ -5,6 +5,7 @@ import javax.annotation.Nonnull;
import com.minelittlepony.unicopia.AwaitTickQueue; import com.minelittlepony.unicopia.AwaitTickQueue;
import com.minelittlepony.unicopia.EquinePredicates; import com.minelittlepony.unicopia.EquinePredicates;
import com.minelittlepony.unicopia.enchanting.IPageUnlockListener; import com.minelittlepony.unicopia.enchanting.IPageUnlockListener;
import com.minelittlepony.unicopia.enchanting.recipe.URecipes;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.magic.spell.SpellRegistry; import com.minelittlepony.unicopia.magic.spell.SpellRegistry;
@ -16,7 +17,6 @@ import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.particle.ParticleTypes; import net.minecraft.particle.ParticleTypes;
import net.minecraft.recipe.Recipe; import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeType;
import net.minecraft.sound.SoundEvents; import net.minecraft.sound.SoundEvents;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.PacketByteBuf; import net.minecraft.util.PacketByteBuf;
@ -73,8 +73,7 @@ public class SpellBookContainer extends Container {
ItemStack current = craftResult.getInvStack(0); ItemStack current = craftResult.getInvStack(0);
if (!current.isEmpty()) { if (!current.isEmpty()) {
// TODO: URecipeType.SPELL_BOOK ItemStack crafted = player.world.getRecipeManager().getFirstMatch(URecipes.SPELL_BOOK, craftMatrix, worldObj)
ItemStack crafted = player.world.getRecipeManager().getFirstMatch(RecipeType.CRAFTING, craftMatrix, worldObj)
.map(Recipe::getOutput) .map(Recipe::getOutput)
.orElse(ItemStack.EMPTY); .orElse(ItemStack.EMPTY);

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.container;
import com.minelittlepony.unicopia.enchanting.IPageUnlockListener; import com.minelittlepony.unicopia.enchanting.IPageUnlockListener;
import com.minelittlepony.unicopia.enchanting.SpellCraftingEvent; import com.minelittlepony.unicopia.enchanting.SpellCraftingEvent;
import com.minelittlepony.unicopia.enchanting.recipe.URecipes;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.MagicGemItem; import com.minelittlepony.unicopia.item.MagicGemItem;
import com.minelittlepony.unicopia.magic.spell.SpellRegistry; import com.minelittlepony.unicopia.magic.spell.SpellRegistry;
@ -12,7 +13,6 @@ import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.Inventory; import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.MusicDiscItem; import net.minecraft.item.MusicDiscItem;
import net.minecraft.recipe.RecipeType;
import net.minecraft.util.DefaultedList; import net.minecraft.util.DefaultedList;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
@ -49,8 +49,7 @@ public class SpellbookResultSlot extends SpellBookContainer.SpellbookSlot {
ItemStack current = craftMatrix.getCraftResultMatrix().getInvStack(0); ItemStack current = craftMatrix.getCraftResultMatrix().getInvStack(0);
craftMatrix.getCraftResultMatrix().setInvStack(0, stack); craftMatrix.getCraftResultMatrix().setInvStack(0, stack);
// TODO: URecipeType.SPELL_BOOK DefaultedList<ItemStack> remaining = player.world.getRecipeManager().getRemainingStacks(URecipes.SPELL_BOOK, craftMatrix, player.world);
DefaultedList<ItemStack> remaining = player.world.getRecipeManager().getRemainingStacks(RecipeType.CRAFTING, craftMatrix, player.world);
craftMatrix.getCraftResultMatrix().setInvStack(0, current); craftMatrix.getCraftResultMatrix().setInvStack(0, current);

View file

@ -1,7 +1,7 @@
package com.minelittlepony.unicopia.ducks; package com.minelittlepony.unicopia.ducks;
@Deprecated @Deprecated
// TODO: 1.16 Use the vanilla BlockTag once mojang adds it // XXX: 1.16 Use the vanilla BlockTag once mojang adds it
public interface Climbable { public interface Climbable {
} }

View file

@ -2,29 +2,18 @@ package com.minelittlepony.unicopia.enchanting.recipe;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import net.minecraft.inventory.CraftingInventory;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeSerializer; import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.RecipeType; import net.minecraft.recipe.RecipeType;
import net.minecraft.util.DefaultedList; import net.minecraft.util.DefaultedList;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.PacketByteBuf;
public class SpecialRecipe extends AbstractSpecialRecipe { public class SpecialRecipe extends AbstractSpecialRecipe {
private final SpellIngredient output; private final SpellIngredient output;
public static Recipe<CraftingInventory> deserialize(JsonObject json) {
return new SpecialRecipe(null,
SpellIngredient.single(json.get("input").getAsJsonObject()),
SpellIngredient.single(json.get("output").getAsJsonObject()),
SpellIngredient.multiple(json)
);
}
public SpecialRecipe(Identifier id, SpellIngredient input, SpellIngredient output, DefaultedList<SpellIngredient> ingredients) { public SpecialRecipe(Identifier id, SpellIngredient input, SpellIngredient output, DefaultedList<SpellIngredient> ingredients) {
super(id, input, ingredients); super(id, input, ingredients);
this.output = output; this.output = output;
} }
@ -35,13 +24,45 @@ public class SpecialRecipe extends AbstractSpecialRecipe {
@Override @Override
public RecipeSerializer<?> getSerializer() { public RecipeSerializer<?> getSerializer() {
// TODO Auto-generated method stub return URecipes.SPECIAL_SERIALIZER;
return null;
} }
@Override @Override
public RecipeType<?> getType() { public RecipeType<?> getType() {
// TODO Auto-generated method stub return URecipes.SPELL_BOOK;
return null;
} }
public static class Serializer implements RecipeSerializer<SpecialRecipe> {
@Override
public SpecialRecipe read(Identifier id, JsonObject json) {
return new SpecialRecipe(id,
SpellIngredient.single(json.get("input").getAsJsonObject()),
SpellIngredient.single(json.get("output").getAsJsonObject()),
SpellIngredient.multiple(json)
);
}
@Override
public SpecialRecipe read(Identifier id, PacketByteBuf buf) {
SpellIngredient input = SpellIngredient.SERIALIZER.read(buf);
SpellIngredient output = SpellIngredient.SERIALIZER.read(buf);
int length = buf.readInt();
DefaultedList<SpellIngredient> ingredients = DefaultedList.copyOf(SpellIngredient.EMPTY);
while (ingredients.size() < length) {
ingredients.add(SpellIngredient.SERIALIZER.read(buf));
}
return new SpecialRecipe(id, input, output, ingredients);
}
@Override
public void write(PacketByteBuf buf, SpecialRecipe recipe) {
recipe.getSpellItem().write(buf);
recipe.output.write(buf);
DefaultedList<SpellIngredient> ingredients = recipe.getSpellIngredients();
buf.writeInt(ingredients.size());
ingredients.forEach(i -> i.write(buf));
}
}
} }

View file

@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.enchanting.recipe;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
@ -20,6 +21,7 @@ public interface SpellIngredient {
map.put("single", SingleSpellIngredient.SERIALIZER); map.put("single", SingleSpellIngredient.SERIALIZER);
map.put("affine", AffineIngredient.SERIALIZER); map.put("affine", AffineIngredient.SERIALIZER);
}); });
Map<Serializer<? extends SpellIngredient>, String> IDS = SERIALIZERS.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
Serializer<SpellIngredient> SERIALIZER = new Serializer<SpellIngredient>() { Serializer<SpellIngredient> SERIALIZER = new Serializer<SpellIngredient>() {
@Override @Override
@ -40,7 +42,7 @@ public interface SpellIngredient {
@Override @Override
public void write(PacketByteBuf buff, SpellIngredient recipe) { public void write(PacketByteBuf buff, SpellIngredient recipe) {
buff.writeByte(recipe instanceof SingleSpellIngredient ? 0 : 1); buff.writeString(IDS.get(recipe.getSerializer()));
recipe.write(buff); recipe.write(buff);
} }
}; };

View file

@ -45,16 +45,15 @@ public class SpellRecipe extends AbstractSpecialRecipe {
@Override @Override
public RecipeSerializer<?> getSerializer() { public RecipeSerializer<?> getSerializer() {
return null; return URecipes.SPELL_SERIALIZER;
} }
@Override @Override
public RecipeType<?> getType() { public RecipeType<?> getType() {
return null; return URecipes.SPELL_BOOK;
} }
public static class Serializer implements RecipeSerializer<SpellRecipe> { public static class Serializer implements RecipeSerializer<SpellRecipe> {
@Override @Override
public SpellRecipe read(Identifier id, JsonObject json) { public SpellRecipe read(Identifier id, JsonObject json) {
JsonObject resultJson = json.get("result").getAsJsonObject(); JsonObject resultJson = json.get("result").getAsJsonObject();
@ -93,4 +92,5 @@ public class SpellRecipe extends AbstractSpecialRecipe {
ingredients.forEach(i -> i.write(buff)); ingredients.forEach(i -> i.write(buff));
} }
} }
} }

View file

@ -0,0 +1,30 @@
package com.minelittlepony.unicopia.enchanting.recipe;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.RecipeType;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
public interface URecipes {
RecipeType<SpellRecipe> SPELL_BOOK = register("spell_book");
RecipeSerializer<SpecialRecipe> SPECIAL_SERIALIZER = register("special_spell", new SpecialRecipe.Serializer());
RecipeSerializer<SpellRecipe> SPELL_SERIALIZER = register("spell", new SpellRecipe.Serializer());
static <T extends Recipe<?>> RecipeType<T> register(final String id) {
return Registry.register(Registry.RECIPE_TYPE, new Identifier("unicopia", id), new RecipeType<T>() {
@Override
public String toString() {
return id;
}
});
}
static <S extends RecipeSerializer<T>, T extends Recipe<?>> S register(String id, S serializer) {
return Registry.register(Registry.RECIPE_SERIALIZER, new Identifier("unicopia", id), serializer);
}
static void bootstrap() {}
}

View file

@ -1,18 +1,17 @@
package com.minelittlepony.unicopia.entity; package com.minelittlepony.unicopia.entity;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgSpawnRainbow;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.packet.EntitySpawnGlobalS2CPacket;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.EntityType; import net.minecraft.entity.EntityType;
import net.minecraft.entity.LightningEntity;
import net.minecraft.entity.SpawnType; import net.minecraft.entity.SpawnType;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.NetworkThreadUtils;
import net.minecraft.network.Packet; import net.minecraft.network.Packet;
import net.minecraft.network.listener.ClientPlayPacketListener;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
import net.minecraft.util.math.Box; import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
@ -26,7 +25,7 @@ public class RainbowEntity extends Entity implements InAnimate {
private int ticksAlive; private int ticksAlive;
private double radius; private final double radius;
public static final int RAINBOW_MAX_SIZE = 180; public static final int RAINBOW_MAX_SIZE = 180;
public static final int RAINBOW_MIN_SIZE = 50; public static final int RAINBOW_MIN_SIZE = 50;
@ -49,8 +48,7 @@ public class RainbowEntity extends Entity implements InAnimate {
ignoreCameraFrustum = true; ignoreCameraFrustum = true;
//width = (float)radius; calculateDimensions();
//height = width;
} }
@Override @Override
@ -69,6 +67,11 @@ public class RainbowEntity extends Entity implements InAnimate {
)); ));
} }
@Override
public EntityDimensions getDimensions(EntityPose pose) {
return EntityDimensions.changing((float)getRadius(), (float)getRadius());
}
@Override @Override
public SoundCategory getSoundCategory() { public SoundCategory getSoundCategory() {
return SoundCategory.WEATHER; return SoundCategory.WEATHER;
@ -119,7 +122,7 @@ public class RainbowEntity extends Entity implements InAnimate {
@Override @Override
public Packet<?> createSpawnPacket() { public Packet<?> createSpawnPacket() {
return new SpawnPacket(this); return Channel.SPAWN_RAINBOW.toPacket(new MsgSpawnRainbow(this));
} }
public static class Spawner extends MobEntity { public static class Spawner extends MobEntity {
@ -159,27 +162,4 @@ public class RainbowEntity extends Entity implements InAnimate {
world.spawnEntity(rainbow); world.spawnEntity(rainbow);
} }
} }
static class SpawnPacket extends EntitySpawnGlobalS2CPacket {
public SpawnPacket(RainbowEntity entity) {
super(entity);
}
@Override
public void apply(ClientPlayPacketListener listener) {
// TODO: Packet needs to be registered, and handling separated
MinecraftClient client = MinecraftClient.getInstance();
NetworkThreadUtils.forceMainThread(this, listener, client);
double x = getX();
double y = getY();
double z = getZ();
LightningEntity entity = new LightningEntity(client.world, x, y, z, false);
entity.updateTrackedPosition(x, y, z);
entity.yaw = 0;
entity.pitch = 0;
entity.setEntityId(getId());
client.world.addLightning(entity);
}
}
} }

View file

@ -1,15 +1,13 @@
package com.minelittlepony.unicopia.entity.player; package com.minelittlepony.unicopia.entity.player;
import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import com.minelittlepony.jumpingcastle.api.Target;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.AbilityReceiver; import com.minelittlepony.unicopia.ability.AbilityReceiver;
import com.minelittlepony.unicopia.ability.Ability; import com.minelittlepony.unicopia.ability.Ability;
import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.entity.Updatable; import com.minelittlepony.unicopia.entity.Updatable;
import com.minelittlepony.unicopia.network.MsgPlayerAbility; import com.minelittlepony.unicopia.network.MsgPlayerAbility;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
@ -112,7 +110,11 @@ class AbilityDelegate implements AbilityReceiver, Updatable, NbtSerialisable {
cooldown = ability.getCooldownTime(player); cooldown = ability.getCooldownTime(player);
if (player.isClientPlayer()) { if (player.isClientPlayer()) {
if (!activateAbility(ability)) { Ability.IData data = ability.tryActivate(player);
if (data != null) {
Channel.PLAYER_ABILITY.send(new MsgPlayerAbility(ability, data));
} else {
cooldown = 0; cooldown = 0;
} }
} }
@ -150,18 +152,4 @@ class AbilityDelegate implements AbilityReceiver, Updatable, NbtSerialisable {
.ifPresent(p -> activeAbility = p); .ifPresent(p -> activeAbility = p);
} }
} }
/**
* Attempts to activate the current stored ability.
* Returns true if the ability suceeded, otherwise false.
*/
protected boolean activateAbility(@Nonnull Ability<?> ability) {
Ability.IData data = ability.tryActivate(player);
if (data != null) {
Unicopia.getConnection().send(new MsgPlayerAbility(player.getOwner(), ability, data), Target.SERVER);
}
return data != null;
}
} }

View file

@ -15,6 +15,7 @@ import com.minelittlepony.unicopia.util.NbtSerialisable;
import com.minelittlepony.unicopia.util.MutableVector; import com.minelittlepony.unicopia.util.MutableVector;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundCategory;
@ -41,6 +42,8 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
private float gravity = 0; private float gravity = 0;
private float eyeHeight;
public GravityDelegate(Pony player) { public GravityDelegate(Pony player) {
this.player = player; this.player = player;
} }
@ -65,6 +68,10 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
return Math.sqrt(getHorizontalMotion(player.getOwner())) > 0.4F; return Math.sqrt(getHorizontalMotion(player.getOwner())) > 0.4F;
} }
public float getEyeHeight() {
return eyeHeight;
}
@Override @Override
public float getTargetEyeHeight(Pony player) { public float getTargetEyeHeight(Pony player) {
if (player.hasEffect()) { if (player.hasEffect()) {
@ -81,7 +88,8 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
return 0.5F; return 0.5F;
} }
return player.getOwner().getStandingEyeHeight(); EntityPose pose = player.getOwner().getPose();
return player.getOwner().getActiveEyeHeight(pose, player.getOwner().getDimensions(pose));
} }
@Override @Override
@ -163,7 +171,8 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
} }
float bodyHeight = getTargetBodyHeight(player); float bodyHeight = getTargetBodyHeight(player);
float eyeHeight = getTargetEyeHeight(player); eyeHeight = 0;
eyeHeight = getTargetEyeHeight(player);
if (gravity < 0) { if (gravity < 0) {
eyeHeight = bodyHeight - eyeHeight; eyeHeight = bodyHeight - eyeHeight;
@ -176,8 +185,6 @@ public class GravityDelegate implements Updatable, FlightControl, NbtSerialisabl
((MixinEntity)entity).setSize(entity.getWidth(), bodyHeight); ((MixinEntity)entity).setSize(entity.getWidth(), bodyHeight);
// TODO: Change eye height
//entity.eyeHeight = eyeHeight;
if (gravity < 0) { if (gravity < 0) {
if (entity.isSneaking()) { if (entity.isSneaking()) {

View file

@ -6,6 +6,7 @@ import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.container.HeavyInventory; import com.minelittlepony.unicopia.container.HeavyInventory;
import com.minelittlepony.unicopia.mixin.Walker; import com.minelittlepony.unicopia.mixin.Walker;
import net.minecraft.entity.attribute.ClampedEntityAttribute;
import net.minecraft.entity.attribute.EntityAttribute; import net.minecraft.entity.attribute.EntityAttribute;
import net.minecraft.entity.attribute.EntityAttributeInstance; import net.minecraft.entity.attribute.EntityAttributeInstance;
import net.minecraft.entity.attribute.EntityAttributeModifier; import net.minecraft.entity.attribute.EntityAttributeModifier;
@ -13,14 +14,16 @@ import net.minecraft.entity.attribute.EntityAttributeModifier.Operation;
import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
public class PlayerAttributes { class PlayerAttributes {
static final EntityAttribute EXTENDED_REACH_DISTANCE = new ClampedEntityAttribute(null, "player.reachDistance", 0, 0, 10);
private static final EntityAttributeModifier EARTH_PONY_STRENGTH = private static final EntityAttributeModifier EARTH_PONY_STRENGTH =
new EntityAttributeModifier(UUID.fromString("777a5505-521e-480b-b9d5-6ea54f259564"), "Earth Pony Strength", 0.6, Operation.MULTIPLY_TOTAL); new EntityAttributeModifier(UUID.fromString("777a5505-521e-480b-b9d5-6ea54f259564"), "Earth Pony Strength", 0.6, Operation.MULTIPLY_TOTAL);
private static final EntityAttributeModifier PEGASUS_SPEED = private static final EntityAttributeModifier PEGASUS_SPEED =
new EntityAttributeModifier(UUID.fromString("9e2699fc-3b8d-4f71-9d2d-fb92ee19b4f7"), "Pegasus Speed", 0.2, Operation.MULTIPLY_TOTAL); new EntityAttributeModifier(UUID.fromString("9e2699fc-3b8d-4f71-9d2d-fb92ee19b4f7"), "Pegasus Speed", 0.2, Operation.MULTIPLY_TOTAL);
//private static final EntityAttributeModifier PEGASUS_REACH = private static final EntityAttributeModifier PEGASUS_REACH =
// new EntityAttributeModifier(UUID.fromString("707b50a8-03e8-40f4-8553-ecf67025fd6d"), "Pegasus Reach", 1.5, Operation.ADDITION); new EntityAttributeModifier(UUID.fromString("707b50a8-03e8-40f4-8553-ecf67025fd6d"), "Pegasus Reach", 1.5, Operation.ADDITION);
private double loadStrength = 0; private double loadStrength = 0;
@ -29,14 +32,15 @@ public class PlayerAttributes {
((Walker)entity.abilities).setWalkSpeed(0.1F - (float)(loadStrength / 100000)); ((Walker)entity.abilities).setWalkSpeed(0.1F - (float)(loadStrength / 100000));
applyAttribute(entity, EntityAttributes.ATTACK_DAMAGE, EARTH_PONY_STRENGTH, race.canUseEarth()); toggleAttribute(entity, EntityAttributes.ATTACK_DAMAGE, EARTH_PONY_STRENGTH, race.canUseEarth());
applyAttribute(entity, EntityAttributes.KNOCKBACK_RESISTANCE, EARTH_PONY_STRENGTH, race.canUseEarth()); toggleAttribute(entity, EntityAttributes.KNOCKBACK_RESISTANCE, EARTH_PONY_STRENGTH, race.canUseEarth());
applyAttribute(entity, EntityAttributes.MOVEMENT_SPEED, PEGASUS_SPEED, race.canFly()); toggleAttribute(entity, EntityAttributes.MOVEMENT_SPEED, PEGASUS_SPEED, race.canFly());
applyAttribute(entity, EntityAttributes.ATTACK_SPEED, PEGASUS_SPEED, race.canFly()); toggleAttribute(entity, EntityAttributes.ATTACK_SPEED, PEGASUS_SPEED, race.canFly());
// applyAttribute(entity, PlayerEntity.REACH_DISTANCE, PEGASUS_REACH, race.canFly()); toggleAttribute(entity, EXTENDED_REACH_DISTANCE, PEGASUS_REACH, race.canFly());
} }
private void applyAttribute(PlayerEntity entity, EntityAttribute attribute, EntityAttributeModifier modifier, boolean enable) { private void toggleAttribute(PlayerEntity entity, EntityAttribute attribute, EntityAttributeModifier modifier, boolean enable) {
EntityAttributeInstance instance = entity.getAttributeInstance(attribute); EntityAttributeInstance instance = entity.getAttributeInstance(attribute);
if (enable) { if (enable) {

View file

@ -4,7 +4,6 @@ import javax.annotation.Nullable;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.ability.AbilityReceiver; import com.minelittlepony.unicopia.ability.AbilityReceiver;
import com.minelittlepony.unicopia.enchanting.PageOwner; import com.minelittlepony.unicopia.enchanting.PageOwner;
import com.minelittlepony.unicopia.entity.FlightControl; import com.minelittlepony.unicopia.entity.FlightControl;
@ -16,6 +15,7 @@ import com.minelittlepony.unicopia.magic.HeldMagicEffect;
import com.minelittlepony.unicopia.magic.MagicEffect; import com.minelittlepony.unicopia.magic.MagicEffect;
import com.minelittlepony.unicopia.magic.MagicalItem; import com.minelittlepony.unicopia.magic.MagicalItem;
import com.minelittlepony.unicopia.magic.spell.SpellRegistry; import com.minelittlepony.unicopia.magic.spell.SpellRegistry;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.EffectSync; import com.minelittlepony.unicopia.network.EffectSync;
import com.minelittlepony.unicopia.network.MsgPlayerCapabilities; import com.minelittlepony.unicopia.network.MsgPlayerCapabilities;
import com.minelittlepony.unicopia.util.BasicEasingInterpolator; import com.minelittlepony.unicopia.util.BasicEasingInterpolator;
@ -85,6 +85,8 @@ public class PlayerImpl implements Pony {
player.getDataTracker().startTracking(ENERGY, 0F); player.getDataTracker().startTracking(ENERGY, 0F);
player.getDataTracker().startTracking(EFFECT, new CompoundTag()); player.getDataTracker().startTracking(EFFECT, new CompoundTag());
player.getDataTracker().startTracking(HELD_EFFECT, new CompoundTag()); player.getDataTracker().startTracking(HELD_EFFECT, new CompoundTag());
player.getAttributes().register(PlayerAttributes.EXTENDED_REACH_DISTANCE);
} }
@Override @Override
@ -169,11 +171,7 @@ public class PlayerImpl implements Pony {
dirty = false; dirty = false;
if (!getWorld().isClient()) { if (!getWorld().isClient()) {
if (full) { Channel.BROADCAST_CAPABILITIES.send(new MsgPlayerCapabilities(full, this));
Unicopia.getConnection().broadcast(new MsgPlayerCapabilities(this));
} else {
Unicopia.getConnection().broadcast(new MsgPlayerCapabilities(getSpecies(), getOwner()));
}
} }
} }
@ -199,6 +197,11 @@ public class PlayerImpl implements Pony {
return gravity; return gravity;
} }
@Override
public float getExtendedReach() {
return (float)entity.getAttributeInstance(PlayerAttributes.EXTENDED_REACH_DISTANCE).getValue();
}
@Override @Override
public FlightControl getFlight() { public FlightControl getFlight() {
return gravity; return gravity;

View file

@ -70,6 +70,12 @@ public interface Pony extends Caster<PlayerEntity>, RaceContainer<PlayerEntity>,
*/ */
void setExertion(float exertion); void setExertion(float exertion);
/**
*
* @return
*/
float getExtendedReach();
/** /**
* Adds player tiredness. * Adds player tiredness.
*/ */

View file

@ -55,7 +55,7 @@ public class ShieldSpell extends AbstractSpell.RangedAreaSpell implements Attach
particlEffect particlEffect
.ifMissing(source, () -> { .ifMissing(source, () -> {
source.addParticle(UParticles.SPHERE, source.getOriginVector(), Vec3d.ZERO); source.addParticle(UParticles.SPHERE, source.getOriginVector(), Vec3d.ZERO);
return null; // TODO: Attachables return null; // XXX: Attachables
}) // 1, getTint(), 10 }) // 1, getTint(), 10
.ifPresent(p -> p.setAttribute(0, radius)); .ifPresent(p -> p.setAttribute(0, radius));
} }

View file

@ -13,6 +13,8 @@ import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.entity.player.PlayerImpl; import com.minelittlepony.unicopia.entity.player.PlayerImpl;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityPose;
import net.minecraft.entity.ItemEntity; import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@ -58,7 +60,17 @@ public abstract class MixinPlayerEntity extends LivingEntity implements PonyCont
@Inject(method = "setGameMode(Lnet/minecraft/world/GameMode;)V", @Inject(method = "setGameMode(Lnet/minecraft/world/GameMode;)V",
at = @At("RETURN")) at = @At("RETURN"))
public void setGameMode(GameMode mode, CallbackInfo info) { private void onSetGameMode(GameMode mode, CallbackInfo info) {
get().setSpecies(get().getSpecies()); get().setSpecies(get().getSpecies());
} }
@Inject(method = "getActiveEyeHeight(Lnet/minecraft/entity/EntityPose;Lnet/minecraft/entity/EntityDimensions;)F",
at = @At("RETURN"),
cancellable = true)
private void onGetActiveEyeHeight(EntityPose pose, EntityDimensions dimensions, CallbackInfoReturnable<Float> info) {
float h = get().getGravity().getEyeHeight();
if (h != 0) {
info.setReturnValue(h);
}
}
} }

View file

@ -0,0 +1,86 @@
package com.minelittlepony.unicopia.network;
import java.util.function.Function;
import io.netty.buffer.Unpooled;
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
import net.fabricmc.fabric.api.network.PacketContext;
import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Identifier;
import net.minecraft.util.PacketByteBuf;
public interface Channel {
SPacketType<MsgPlayerAbility> PLAYER_ABILITY = clientToServer(new Identifier("unicopia", "player_ability"), MsgPlayerAbility::new);
SPacketType<MsgRequestCapabilities> REQUEST_CAPABILITIES = clientToServer(new Identifier("unicopia", "request_capabilities"), MsgRequestCapabilities::new);
CPacketType<MsgPlayerCapabilities> PLAYER_CAPABILITIES = serverToClient(new Identifier("unicopia", "player_capabilities"), MsgPlayerCapabilities::new);
SPacketType<MsgPlayerCapabilities> BROADCAST_CAPABILITIES = broadcast(PLAYER_CAPABILITIES, MsgPlayerCapabilities::new);
CPacketType<MsgSpawnRainbow> SPAWN_RAINBOW = serverToClient(new Identifier("unicopia", "rainbow_entity"), MsgSpawnRainbow::new);
static void bootstrap() { }
static <T extends Packet> SPacketType<T> clientToServer(Identifier id, Function<PacketByteBuf, T> factory) {
ServerSidePacketRegistry.INSTANCE.register(id, (context, buffer) -> factory.apply(buffer).handle(context));
return () -> id;
}
static <T extends Packet> SPacketType<T> broadcast(CPacketType<T> redirect, Function<PacketByteBuf, T> factory) {
Identifier id = new Identifier(redirect.getId().getNamespace(), "broadcast_" + redirect.getId().getPath());
ServerSidePacketRegistry.INSTANCE.register(id, (context, buffer) -> {
PlayerEntity sender = context.getPlayer();
T p = factory.apply(buffer);
p.handle(context);
sender.world.getPlayers().forEach(player -> {
if (player != null && player != sender) {
redirect.send(player, p);
}
});
});
return () -> id;
}
static <T extends Packet> CPacketType<T> serverToClient(Identifier id, Function<PacketByteBuf, T> factory) {
ClientSidePacketRegistry.INSTANCE.register(id, (context, buffer) -> factory.apply(buffer).handle(context));
return () -> id;
}
interface CPacketType<T extends Packet> {
Identifier getId();
default void send(PlayerEntity recipient, T packet) {
ServerSidePacketRegistry.INSTANCE.sendToPlayer(recipient, getId(), packet.toBuffer());
}
default net.minecraft.network.Packet<?> toPacket(T packet) {
return ServerSidePacketRegistry.INSTANCE.toPacket(getId(), packet.toBuffer());
}
}
interface SPacketType<T extends Packet> {
Identifier getId();
default void send(T packet) {
ClientSidePacketRegistry.INSTANCE.sendToServer(getId(), packet.toBuffer());
}
default net.minecraft.network.Packet<?> toPacket(T packet) {
return ClientSidePacketRegistry.INSTANCE.toPacket(getId(), packet.toBuffer());
}
}
interface Packet {
void handle(PacketContext context);
void toBuffer(PacketByteBuf buffer);
default PacketByteBuf toBuffer() {
PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
toBuffer(buf);
return buf;
}
}
}

View file

@ -1,43 +1,36 @@
package com.minelittlepony.unicopia.network; package com.minelittlepony.unicopia.network;
import java.util.UUID;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.minelittlepony.jumpingcastle.api.Channel;
import com.minelittlepony.jumpingcastle.api.Message;
import com.minelittlepony.unicopia.ability.Ability; import com.minelittlepony.unicopia.ability.Ability;
import com.minelittlepony.unicopia.ability.Abilities; import com.minelittlepony.unicopia.ability.Abilities;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.entity.player.PlayerEntity; import net.fabricmc.fabric.api.network.PacketContext;
import net.minecraft.server.MinecraftServer; import net.minecraft.util.PacketByteBuf;
public class MsgPlayerAbility implements Message, Message.Handler<MsgPlayerAbility> { public class MsgPlayerAbility implements Channel.Packet {
private static final Gson gson = new GsonBuilder() private static final Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation() .excludeFieldsWithoutExposeAnnotation()
.create(); .create();
@Expose private final String powerIdentifier;
private UUID senderId;
@Expose private final String abilityJson;
private String powerIdentifier;
@Expose public MsgPlayerAbility(Ability<?> power, Ability.IData data) {
private String abilityJson;
public MsgPlayerAbility(PlayerEntity player, Ability<?> power, Ability.IData data) {
senderId = player.getUuid();
powerIdentifier = power.getKeyName(); powerIdentifier = power.getKeyName();
abilityJson = gson.toJson(data, power.getPackageType()); abilityJson = gson.toJson(data, power.getPackageType());
} }
private <T extends Ability.IData> void apply(Ability<T> power, Channel channel) { public MsgPlayerAbility(PacketByteBuf buffer) {
MinecraftServer server = channel.getServer(); powerIdentifier = buffer.readString();
Pony player = Pony.of(server.getPlayerManager().getPlayer(senderId)); abilityJson = buffer.readString();
}
private <T extends Ability.IData> void apply(Ability<T> power, PacketContext context) {
Pony player = Pony.of(context.getPlayer());
if (player == null) { if (player == null) {
return; return;
} }
@ -48,7 +41,13 @@ public class MsgPlayerAbility implements Message, Message.Handler<MsgPlayerAbili
} }
@Override @Override
public void onPayload(MsgPlayerAbility message, Channel channel) { public void toBuffer(PacketByteBuf buffer) {
Abilities.getInstance().getPowerFromName(powerIdentifier).ifPresent(power -> apply(power, channel)); buffer.writeString(powerIdentifier);
buffer.writeString(abilityJson);
}
@Override
public void handle(PacketContext context) {
Abilities.getInstance().getPowerFromName(powerIdentifier).ifPresent(power -> apply(power, context));
} }
} }

View file

@ -1,77 +1,60 @@
package com.minelittlepony.unicopia.network; package com.minelittlepony.unicopia.network;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.UUID; import java.io.InputStream;
import java.io.OutputStream;
import com.google.gson.annotations.Expose;
import com.minelittlepony.jumpingcastle.api.Channel;
import com.minelittlepony.jumpingcastle.api.Message;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import io.netty.buffer.ByteBufInputStream;
import io.netty.buffer.ByteBufOutputStream;
import net.fabricmc.fabric.api.network.PacketContext;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.MinecraftServer; import net.minecraft.util.PacketByteBuf;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.NbtIo;
public class MsgPlayerCapabilities implements Message, Message.Handler<MsgPlayerCapabilities> { public class MsgPlayerCapabilities implements Channel.Packet {
@Expose
Race newRace;
@Expose private final Race newRace;
UUID senderId;
@Expose private final CompoundTag compoundTag;
byte[] compoundTag;
public MsgPlayerCapabilities(PacketByteBuf buffer) {
newRace = Race.values()[buffer.readInt()];
try (InputStream in = new ByteBufInputStream(buffer)) {
compoundTag = NbtIo.readCompressed(in);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public MsgPlayerCapabilities(Race race, PlayerEntity player) { public MsgPlayerCapabilities(Race race, PlayerEntity player) {
newRace = race; newRace = race;
senderId = player.getUuid(); compoundTag = new CompoundTag();
compoundTag = new byte[0];
} }
public MsgPlayerCapabilities(Pony player) { public MsgPlayerCapabilities(boolean full, Pony player) {
newRace = player.getSpecies(); newRace = player.getSpecies();
senderId = player.getOwner().getUuid(); compoundTag = full ? player.toNBT() : new CompoundTag();
}
try (ByteArrayOutputStream bytes = new ByteArrayOutputStream()) { @Override
CompoundTag nbt = player.toNBT(); public void toBuffer(PacketByteBuf buffer) {
buffer.writeInt(newRace.ordinal());
NbtIo.write(nbt, new DataOutputStream(bytes)); try (OutputStream out = new ByteBufOutputStream(buffer)) {
NbtIo.writeCompressed(compoundTag, out);
compoundTag = bytes.toByteArray();
} catch (IOException e) { } catch (IOException e) {
} }
} }
@Override @Override
public void onPayload(MsgPlayerCapabilities message, Channel channel) { public void handle(PacketContext context) {
Pony player = Pony.of(context.getPlayer());
MinecraftServer server = channel.getServer(); if (compoundTag.isEmpty()) {
player.setSpecies(newRace);
PlayerEntity self = server.getPlayerManager().getPlayer(senderId);
if (self == null) {
Unicopia.LOGGER.warn("[Unicopia] [CLIENT] [MsgPlayerCapabilities] Player with id %s was not found!\n", senderId.toString());
} else { } else {
Pony player = Pony.of(self); player.fromNBT(compoundTag);
if (compoundTag.length > 0) {
try (ByteArrayInputStream input = new ByteArrayInputStream(compoundTag)) {
CompoundTag nbt = NbtIo.read(new DataInputStream(input));
player.fromNBT(nbt);
} catch (IOException e) {
}
} else {
player.setSpecies(newRace);
}
} }
} }
} }

View file

@ -1,40 +1,38 @@
package com.minelittlepony.unicopia.network; package com.minelittlepony.unicopia.network;
import java.util.UUID;
import com.google.gson.annotations.Expose;
import com.minelittlepony.jumpingcastle.api.Channel;
import com.minelittlepony.jumpingcastle.api.Message;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import net.fabricmc.fabric.api.network.PacketContext;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.MinecraftServer; import net.minecraft.util.PacketByteBuf;
public class MsgRequestCapabilities implements Message, Message.Handler<MsgRequestCapabilities> { public class MsgRequestCapabilities implements Channel.Packet {
@Expose
public UUID senderId;
@Expose private final Race race;
public Race race;
public MsgRequestCapabilities(PacketByteBuf buffer) {
race = Race.values()[buffer.readInt()];
}
public MsgRequestCapabilities(PlayerEntity player, Race preferredRace) { public MsgRequestCapabilities(PlayerEntity player, Race preferredRace) {
senderId = player.getGameProfile().getId();
race = preferredRace; race = preferredRace;
} }
@Override @Override
public void onPayload(MsgRequestCapabilities message, Channel channel) { public void toBuffer(PacketByteBuf buffer) {
MinecraftServer server = channel.getServer(); buffer.writeInt(race.ordinal());
}
Unicopia.LOGGER.warn("[Unicopia] [SERVER] [MsgRequestCapabilities] Sending capabilities to player %s\n", senderId.toString()); @Override
Pony player = Pony.of(server.getPlayerManager().getPlayer(senderId)); public void handle(PacketContext context) {
Pony player = Pony.of(context.getPlayer());
if (player.getSpecies().isDefault()) { if (player.getSpecies().isDefault()) {
player.setSpecies(message.race); player.setSpecies(race);
} }
channel.respond(new MsgPlayerCapabilities(player), senderId); Channel.PLAYER_CAPABILITIES.send(context.getPlayer(), new MsgPlayerCapabilities(true, player));
} }
} }

View file

@ -0,0 +1,52 @@
package com.minelittlepony.unicopia.network;
import com.minelittlepony.unicopia.entity.RainbowEntity;
import com.minelittlepony.unicopia.entity.UEntities;
import net.fabricmc.fabric.api.network.PacketContext;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.Entity;
import net.minecraft.util.PacketByteBuf;
public class MsgSpawnRainbow implements Channel.Packet {
private final int id;
private final double x;
private final double y;
private final double z;
public MsgSpawnRainbow(Entity entity) {
id = entity.getEntityId();
x = entity.getX();
y = entity.getY();
z = entity.getZ();
}
public MsgSpawnRainbow(PacketByteBuf buffer) {
id = buffer.readVarInt();
x = buffer.readDouble();
y = buffer.readDouble();
z = buffer.readDouble();
}
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeVarInt(id);
buffer.writeDouble(x);
buffer.writeDouble(y);
buffer.writeDouble(z);
}
@Override
public void handle(PacketContext context) {
MinecraftClient client = MinecraftClient.getInstance();
RainbowEntity entity = UEntities.RAINBOW.create(client.world);
entity.setPos(x, y, z);
entity.updateTrackedPosition(x, y, z);
entity.yaw = 0;
entity.pitch = 0;
entity.setEntityId(id);
client.world.addEntity(id, entity);
}
}