Ensure tree types are available to the client when on a multiplayer server

This commit is contained in:
Sollace 2022-09-14 21:15:29 +02:00
parent e4eb233f7a
commit b14771e85a
4 changed files with 65 additions and 94 deletions

View file

@ -164,11 +164,11 @@ public interface TreeType {
boolean isWide(); boolean isWide();
static TreeType at(BlockPos pos, World world) { static TreeType at(BlockPos pos, World world) {
return TreeTypeLoader.INSTANCE.get(world.getBlockState(pos), pos, world); return TreeTypes.get(world.getBlockState(pos), pos, world);
} }
static TreeType of(BlockState state) { static TreeType of(BlockState state) {
return TreeTypeLoader.INSTANCE.get(state); return TreeTypes.get(state);
} }
static TreeType of(TreeType logs, TreeType leaves) { static TreeType of(TreeType logs, TreeType leaves) {

View file

@ -1,147 +1,111 @@
package com.minelittlepony.unicopia.ability.data.tree; package com.minelittlepony.unicopia.ability.data.tree;
import java.util.HashSet; import java.util.*;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import java.util.stream.Collectors;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.minelittlepony.unicopia.Unicopia; import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.util.PosHelper;
import com.minelittlepony.unicopia.util.Resources; import com.minelittlepony.unicopia.util.Resources;
import com.minelittlepony.unicopia.util.Weighted; import com.minelittlepony.unicopia.util.Weighted;
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.LeavesBlock;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.resource.JsonDataLoader; import net.minecraft.resource.JsonDataLoader;
import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceManager;
import net.minecraft.tag.BlockTags;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.profiler.Profiler; import net.minecraft.util.profiler.Profiler;
import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.Registry;
import net.minecraft.world.World;
public class TreeTypeLoader extends JsonDataLoader implements IdentifiableResourceReloadListener { public class TreeTypeLoader extends JsonDataLoader implements IdentifiableResourceReloadListener {
private static final Identifier ID = Unicopia.id("data/tree_type"); private static final Identifier ID = Unicopia.id("data/tree_type");
public static final TreeTypeLoader INSTANCE = new TreeTypeLoader(); public static final TreeTypeLoader INSTANCE = new TreeTypeLoader();
private final Set<TreeType> entries = new HashSet<>(); private Map<Identifier, TreeTypeDef> entries = new HashMap<>();
private final TreeType any1x = createDynamic(false);
private final TreeType any2x = createDynamic(true);
TreeTypeLoader() { TreeTypeLoader() {
super(Resources.GSON, "tree_types"); super(Resources.GSON, "tree_types");
} }
public Map<Identifier, TreeTypeDef> getEntries() {
return entries;
}
@Override @Override
public Identifier getFabricId() { public Identifier getFabricId() {
return ID; return ID;
} }
public TreeType get(BlockState state, BlockPos pos, World world) {
return entries.stream()
.filter(type -> type.matches(state))
.findFirst()
.map(type -> TreeType.of(type, type.findLeavesType(world, pos)))
.orElseGet(() -> {
if (any1x.matches(state)) {
if (PosHelper.any(pos, p -> world.getBlockState(p).isOf(state.getBlock()), PosHelper.HORIZONTAL)) {
return any2x;
}
return any1x;
}
return TreeType.NONE;
});
}
public TreeType get(BlockState state) {
return entries.stream()
.filter(type -> type.matches(state))
.findFirst()
.orElse(TreeType.NONE);
}
private TreeType createDynamic(boolean wide) {
return new TreeType() {
@Override
public boolean isLeaves(BlockState state) {
return (state.isIn(BlockTags.LEAVES) || state.getBlock() instanceof LeavesBlock || entries.stream().anyMatch(t -> t.isLeaves(state))) && TreeTypeImpl.isNonPersistent(state);
}
@Override
public boolean isLog(BlockState state) {
return state.isIn(BlockTags.LOGS_THAT_BURN) || entries.stream().anyMatch(t -> t.isLog(state));
}
@Override
public ItemStack pickRandomStack(BlockState state) {
TreeType type = get(state);
if (type == TreeType.NONE) {
type = get(Blocks.OAK_LOG.getDefaultState());
}
return type.pickRandomStack(state);
}
@Override
public boolean isWide() {
return wide;
}
};
}
@Override @Override
protected void apply(Map<Identifier, JsonElement> resources, ResourceManager manager, Profiler profiler) { protected void apply(Map<Identifier, JsonElement> resources, ResourceManager manager, Profiler profiler) {
entries.clear(); entries = resources.entrySet().stream().filter(Objects::nonNull)
.collect(Collectors.toMap(Map.Entry::getKey, entry -> {
for (Map.Entry<Identifier, JsonElement> entry : resources.entrySet()) {
try { try {
TreeTypeDef typeDef = Resources.GSON.fromJson(entry.getValue(), TreeTypeDef.class); return Resources.GSON.fromJson(entry.getValue(), TreeTypeDef.class);
if (typeDef != null) {
entries.add(new TreeTypeImpl(
entry.getKey(),
typeDef.wideTrunk,
typeDef.getWeighted(new Weighted<Supplier<ItemStack>>()),
Objects.requireNonNull(typeDef.logs, "TreeType must have logs"),
Objects.requireNonNull(typeDef.leaves, "TreeType must have leaves")
));
}
} catch (IllegalArgumentException | JsonParseException e) { } catch (IllegalArgumentException | JsonParseException e) {
return null;
}
} }
}));
TreeTypes.load(entries);
} }
static class TreeTypeDef { public static final class TreeTypeDef {
Set<Identifier> logs; final Set<Identifier> logs;
Set<Identifier> leaves; final Set<Identifier> leaves;
Set<Drop> drops; final Set<Drop> drops;
boolean wideTrunk; final boolean wideTrunk;
Weighted<Supplier<ItemStack>> getWeighted(Weighted<Supplier<ItemStack>> weighted) { public TreeTypeDef(PacketByteBuf buffer) {
logs = new HashSet<>(buffer.readList(PacketByteBuf::readIdentifier));
leaves = new HashSet<>(buffer.readList(PacketByteBuf::readIdentifier));
drops = new HashSet<>(buffer.readList(Drop::new));
wideTrunk = buffer.readBoolean();
}
private Weighted<Supplier<ItemStack>> getWeighted(Weighted<Supplier<ItemStack>> weighted) {
drops.forEach(drop -> drop.appendDrop(weighted)); drops.forEach(drop -> drop.appendDrop(weighted));
return weighted; return weighted;
} }
public TreeType toTreeType(Identifier id) {
return new TreeTypeImpl(
id,
wideTrunk,
getWeighted(new Weighted<Supplier<ItemStack>>()),
Objects.requireNonNull(logs, "TreeType must have logs"),
Objects.requireNonNull(leaves, "TreeType must have leaves")
);
}
public void write(PacketByteBuf buffer) {
buffer.writeCollection(logs, PacketByteBuf::writeIdentifier);
buffer.writeCollection(leaves, PacketByteBuf::writeIdentifier);
buffer.writeCollection(drops, (a, b) -> b.write(a));
buffer.writeBoolean(wideTrunk);
}
static class Drop { static class Drop {
int weight; final int weight;
Identifier item; final Identifier item;
public Drop(PacketByteBuf buffer) {
weight = buffer.readInt();
item = buffer.readIdentifier();
}
void appendDrop(Weighted<Supplier<ItemStack>> weighted) { void appendDrop(Weighted<Supplier<ItemStack>> weighted) {
Registry.ITEM.getOrEmpty(item).ifPresent(item -> { Registry.ITEM.getOrEmpty(item).ifPresent(item -> {
weighted.put(weight, item::getDefaultStack); weighted.put(weight, item::getDefaultStack);
}); });
} }
public void write(PacketByteBuf buffer) {
buffer.writeInt(weight);
buffer.writeIdentifier(item);
}
} }
} }
} }

View file

@ -3,6 +3,7 @@ package com.minelittlepony.unicopia.network;
import java.util.*; import java.util.*;
import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.ability.data.tree.TreeTypeLoader;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.client.gui.spellbook.ClientChapters; import com.minelittlepony.unicopia.client.gui.spellbook.ClientChapters;
import com.minelittlepony.unicopia.container.SpellbookChapterLoader; import com.minelittlepony.unicopia.container.SpellbookChapterLoader;
@ -17,22 +18,26 @@ import net.minecraft.util.Identifier;
public class MsgServerResources implements Packet<PlayerEntity> { public class MsgServerResources implements Packet<PlayerEntity> {
public final Map<Identifier, SpellTraits> traits; public final Map<Identifier, SpellTraits> traits;
public final Map<Identifier, ?> chapters; public final Map<Identifier, ?> chapters;
public final Map<Identifier, TreeTypeLoader.TreeTypeDef> treeTypes;
public MsgServerResources() { public MsgServerResources() {
traits = SpellTraits.all(); traits = SpellTraits.all();
chapters = SpellbookChapterLoader.INSTANCE.getChapters(); chapters = SpellbookChapterLoader.INSTANCE.getChapters();
treeTypes = TreeTypeLoader.INSTANCE.getEntries();
} }
@Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
public MsgServerResources(PacketByteBuf buffer) { public MsgServerResources(PacketByteBuf buffer) {
traits = buffer.readMap(PacketByteBuf::readIdentifier, SpellTraits::fromPacket); traits = buffer.readMap(PacketByteBuf::readIdentifier, SpellTraits::fromPacket);
chapters = buffer.readMap(PacketByteBuf::readIdentifier, ClientChapters::loadChapter); chapters = buffer.readMap(PacketByteBuf::readIdentifier, ClientChapters::loadChapter);
treeTypes = buffer.readMap(PacketByteBuf::readIdentifier, TreeTypeLoader.TreeTypeDef::new);
} }
@Override @Override
public void toBuffer(PacketByteBuf buffer) { public void toBuffer(PacketByteBuf buffer) {
buffer.writeMap(traits, 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)); buffer.writeMap(chapters, PacketByteBuf::writeIdentifier, (r, v) -> ((SpellbookChapterLoader.Chapter)v).write(r));
buffer.writeMap(treeTypes, PacketByteBuf::writeIdentifier, (r, v) -> v.write(r));
} }
@Override @Override

View file

@ -5,6 +5,7 @@ import java.util.Map;
import com.minelittlepony.unicopia.InteractionManager; import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Owned; import com.minelittlepony.unicopia.Owned;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.data.tree.TreeTypes;
import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits; import com.minelittlepony.unicopia.ability.magic.spell.trait.SpellTraits;
import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait; import com.minelittlepony.unicopia.ability.magic.spell.trait.Trait;
import com.minelittlepony.unicopia.client.ClientBlockDestructionManager; import com.minelittlepony.unicopia.client.ClientBlockDestructionManager;
@ -82,5 +83,6 @@ public class ClientNetworkHandlerImpl implements ClientNetworkHandler {
public void handleServerResources(MsgServerResources packet) { public void handleServerResources(MsgServerResources packet) {
SpellTraits.load(packet.traits); SpellTraits.load(packet.traits);
ClientChapters.load((Map<Identifier, Chapter>)packet.chapters); ClientChapters.load((Map<Identifier, Chapter>)packet.chapters);
TreeTypes.load(packet.treeTypes);
} }
} }