3
0
Mirror von https://github.com/Moulberry/AxiomPaperPlugin.git synchronisiert 2024-09-29 07:50:05 +02:00

Finish world properties, add WorldPropertiesExample

Dieser Commit ist enthalten in:
Moulberry 2023-09-21 16:35:00 +08:00
Ursprung f88d558f88
Commit 59cf7b49b9
9 geänderte Dateien mit 281 neuen und 35 gelöschten Zeilen

Datei anzeigen

@ -1,8 +1,13 @@
package com.moulberry.axiom; package com.moulberry.axiom;
import com.moulberry.axiom.buffer.CompressedBlockEntity; import com.moulberry.axiom.buffer.CompressedBlockEntity;
import com.moulberry.axiom.event.AxiomCreateWorldPropertiesEvent;
import com.moulberry.axiom.event.AxiomTimeChangeEvent;
import com.moulberry.axiom.packet.*; import com.moulberry.axiom.packet.*;
import com.moulberry.axiom.world_properties.WorldPropertyCategory;
import com.moulberry.axiom.world_properties.WorldPropertyWidgetType;
import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry; import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry;
import com.moulberry.axiom.world_properties.server.ServerWorldProperty;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.papermc.paper.event.player.PlayerFailMoveEvent; import io.papermc.paper.event.player.PlayerFailMoveEvent;
@ -15,6 +20,7 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.PacketFlow; import net.minecraft.network.protocol.PacketFlow;
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket; import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
import net.minecraft.resources.ResourceLocation;
import org.bukkit.*; import org.bukkit.*;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@ -24,15 +30,23 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.plugin.messaging.Messenger; import org.bukkit.plugin.messaging.Messenger;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.jetbrains.annotations.Nullable;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class AxiomPaper extends JavaPlugin implements Listener { public class AxiomPaper extends JavaPlugin implements Listener {
public static AxiomPaper PLUGIN; // tsk tsk tsk
public final Set<UUID> activeAxiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>());
@Override @Override
public void onEnable() { public void onEnable() {
PLUGIN = this;
Bukkit.getPluginManager().registerEvents(this, this); Bukkit.getPluginManager().registerEvents(this, this);
// Bukkit.getPluginManager().registerEvents(new WorldPropertiesExample(), this);
CompressedBlockEntity.initialize(this); CompressedBlockEntity.initialize(this);
Messenger msg = Bukkit.getMessenger(); Messenger msg = Bukkit.getMessenger();
@ -42,13 +56,14 @@ public class AxiomPaper extends JavaPlugin implements Listener {
msg.registerOutgoingPluginChannel(this, "axiom:set_editor_views"); msg.registerOutgoingPluginChannel(this, "axiom:set_editor_views");
msg.registerOutgoingPluginChannel(this, "axiom:block_entities"); msg.registerOutgoingPluginChannel(this, "axiom:block_entities");
msg.registerOutgoingPluginChannel(this, "axiom:register_world_properties"); msg.registerOutgoingPluginChannel(this, "axiom:register_world_properties");
msg.registerOutgoingPluginChannel(this, "axiom:set_world_property");
final Set<UUID> activeAxiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>()); msg.registerOutgoingPluginChannel(this, "axiom:ack_world_properties");
msg.registerIncomingPluginChannel(this, "axiom:hello", new HelloPacketListener(this, activeAxiomPlayers)); msg.registerIncomingPluginChannel(this, "axiom:hello", new HelloPacketListener(this, activeAxiomPlayers));
msg.registerIncomingPluginChannel(this, "axiom:set_gamemode", new SetGamemodePacketListener()); msg.registerIncomingPluginChannel(this, "axiom:set_gamemode", new SetGamemodePacketListener());
msg.registerIncomingPluginChannel(this, "axiom:set_fly_speed", new SetFlySpeedPacketListener()); msg.registerIncomingPluginChannel(this, "axiom:set_fly_speed", new SetFlySpeedPacketListener());
msg.registerIncomingPluginChannel(this, "axiom:set_world_time", new SetTimePacketListener()); msg.registerIncomingPluginChannel(this, "axiom:set_world_time", new SetTimePacketListener());
msg.registerIncomingPluginChannel(this, "axiom:set_world_property", new SetWorldPropertyListener());
msg.registerIncomingPluginChannel(this, "axiom:set_block", new SetBlockPacketListener(this)); msg.registerIncomingPluginChannel(this, "axiom:set_block", new SetBlockPacketListener(this));
msg.registerIncomingPluginChannel(this, "axiom:set_hotbar_slot", new SetHotbarSlotPacketListener()); msg.registerIncomingPluginChannel(this, "axiom:set_hotbar_slot", new SetHotbarSlotPacketListener());
msg.registerIncomingPluginChannel(this, "axiom:switch_active_hotbar", new SwitchActiveHotbarPacketListener()); msg.registerIncomingPluginChannel(this, "axiom:switch_active_hotbar", new SwitchActiveHotbarPacketListener());
@ -99,6 +114,18 @@ public class AxiomPaper extends JavaPlugin implements Listener {
}, 20, 20); }, 20, 20);
} }
private final WeakHashMap<World, ServerWorldPropertiesRegistry> worldProperties = new WeakHashMap<>();
public @Nullable ServerWorldPropertiesRegistry getWorldProperties(World world) {
if (worldProperties.containsKey(world)) {
return worldProperties.get(world);
} else {
ServerWorldPropertiesRegistry properties = createWorldProperties(world);
worldProperties.put(world, properties);
return properties;
}
}
@EventHandler @EventHandler
public void onFailMove(PlayerFailMoveEvent event) { public void onFailMove(PlayerFailMoveEvent event) {
if (event.getPlayer().hasPermission("axiom.*") && if (event.getPlayer().hasPermission("axiom.*") &&
@ -107,15 +134,17 @@ public class AxiomPaper extends JavaPlugin implements Listener {
} }
} }
private final WeakHashMap<World, ServerWorldPropertiesRegistry> worldProperties = new WeakHashMap<>();
@EventHandler @EventHandler
public void onChangedWorld(PlayerChangedWorldEvent event) { public void onChangedWorld(PlayerChangedWorldEvent event) {
System.out.println("Changed world!");
World world = event.getPlayer().getWorld(); World world = event.getPlayer().getWorld();
ServerWorldPropertiesRegistry properties = worldProperties.computeIfAbsent(world, k -> new ServerWorldPropertiesRegistry());
properties.registerFor(this, event.getPlayer()); ServerWorldPropertiesRegistry properties = getWorldProperties(world);
if (properties == null) {
event.getPlayer().sendPluginMessage(this, "axiom:register_world_properties", new byte[]{0});
} else {
properties.registerFor(this, event.getPlayer());
}
} }
@EventHandler @EventHandler
@ -123,9 +152,25 @@ public class AxiomPaper extends JavaPlugin implements Listener {
Player player = event.getPlayer(); Player player = event.getPlayer();
Bukkit.getScheduler().scheduleSyncDelayedTask(this, () -> { Bukkit.getScheduler().scheduleSyncDelayedTask(this, () -> {
World world = player.getWorld(); World world = player.getWorld();
ServerWorldPropertiesRegistry properties = worldProperties.computeIfAbsent(world, k -> new ServerWorldPropertiesRegistry());
properties.registerFor(this, player); ServerWorldPropertiesRegistry properties = getWorldProperties(world);
if (properties == null) {
player.sendPluginMessage(this, "axiom:register_world_properties", new byte[]{0});
} else {
properties.registerFor(this, player);
}
}, 20); // Why does this need to be delayed? }, 20); // Why does this need to be delayed?
} }
private ServerWorldPropertiesRegistry createWorldProperties(World world) {
ServerWorldPropertiesRegistry registry = new ServerWorldPropertiesRegistry();
AxiomCreateWorldPropertiesEvent createEvent = new AxiomCreateWorldPropertiesEvent(world, registry);
Bukkit.getPluginManager().callEvent(createEvent);
if (createEvent.isCancelled()) return null;
return registry;
}
} }

Datei anzeigen

@ -0,0 +1,55 @@
package com.moulberry.axiom;
import com.moulberry.axiom.event.AxiomCreateWorldPropertiesEvent;
import com.moulberry.axiom.world_properties.WorldPropertyCategory;
import com.moulberry.axiom.world_properties.WorldPropertyWidgetType;
import com.moulberry.axiom.world_properties.server.ServerWorldProperty;
import net.kyori.adventure.text.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Unit;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import java.util.List;
public class WorldPropertiesExample implements Listener {
@EventHandler
public void onCreateWorldProperties(AxiomCreateWorldPropertiesEvent event) {
WorldPropertyCategory category = new WorldPropertyCategory("Examples", false);
World world = event.getWorld();
ServerWorldProperty<Boolean> checkbox = new ServerWorldProperty<>(new ResourceLocation("axiom:checkbox"),
"Checkbox",
false, WorldPropertyWidgetType.CHECKBOX, false, bool -> {
world.sendMessage(Component.text("Checkbox: " + bool)); // Do something with input
return true; // true to sync with client
});
ServerWorldProperty<Integer> slider = new ServerWorldProperty<>(new ResourceLocation("axiom:slider"),
"Slider",
false, new WorldPropertyWidgetType.Slider(0, 8), 4, integer -> {
world.sendMessage(Component.text("Slider: " + integer)); // Do something with input
return true; // true to sync with client
});
ServerWorldProperty<String> textbox = new ServerWorldProperty<>(new ResourceLocation("axiom:textbox"),
"Textbox",
false, WorldPropertyWidgetType.TEXTBOX, "Hello", string -> {
world.sendMessage(Component.text("Textbox: " + string)); // Do something with input
return true; // true to sync with client
});
ServerWorldProperty<Unit> button = new ServerWorldProperty<>(new ResourceLocation("axiom:button"),
"Button",
false, WorldPropertyWidgetType.BUTTON, Unit.INSTANCE, unit -> {
world.sendMessage(Component.text("Button pressed")); // Do something with input
return true; // true to sync with client
});
event.addCategory(category, List.of(checkbox, slider, textbox, button));
}
}

Datei anzeigen

@ -0,0 +1,56 @@
package com.moulberry.axiom.event;
import com.moulberry.axiom.world_properties.WorldPropertyCategory;
import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry;
import com.moulberry.axiom.world_properties.server.ServerWorldProperty;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class AxiomCreateWorldPropertiesEvent extends Event implements Cancellable {
private static final HandlerList HANDLERS = new HandlerList();
private final World world;
private final ServerWorldPropertiesRegistry registry;
private boolean cancelled = false;
public AxiomCreateWorldPropertiesEvent(World world, ServerWorldPropertiesRegistry registry) {
this.world = world;
this.registry = registry;
}
public World getWorld() {
return world;
}
public void addCategory(WorldPropertyCategory category, List<ServerWorldProperty<?>> properties) {
this.registry.addCategory(category, properties);
}
@Override
public boolean isCancelled() {
return this.cancelled;
}
@Override
public void setCancelled(boolean cancel) {
this.cancelled = cancel;
}
public static HandlerList getHandlerList() {
return HANDLERS;
}
@Override
public @NotNull HandlerList getHandlers() {
return HANDLERS;
}
}

Datei anzeigen

@ -60,7 +60,6 @@ public class HelloPacketListener implements PluginMessageListener {
// Enable // Enable
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
buf.writeBoolean(true); buf.writeBoolean(true);
buf.writeByte(0); // todo: world properties
buf.writeInt(handshakeEvent.getMaxBufferSize()); // Max Buffer Size buf.writeInt(handshakeEvent.getMaxBufferSize()); // Max Buffer Size
buf.writeBoolean(false); // No source info buf.writeBoolean(false); // No source info
buf.writeBoolean(false); // No source settings buf.writeBoolean(false); // No source settings

Datei anzeigen

@ -1,6 +1,5 @@
package com.moulberry.axiom.packet; package com.moulberry.axiom.packet;
import com.moulberry.axiom.event.AxiomFlySpeedChangeEvent;
import com.moulberry.axiom.event.AxiomTimeChangeEvent; import com.moulberry.axiom.event.AxiomTimeChangeEvent;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
@ -11,7 +10,6 @@ import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld; import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener; import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@ -25,7 +23,7 @@ public class SetTimePacketListener implements PluginMessageListener {
} }
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message)); FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
ResourceKey<Level> key = friendlyByteBuf.readResourceKey(Registries.DIMENSION); // Ignore ResourceKey<Level> key = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
Integer time = friendlyByteBuf.readNullable(FriendlyByteBuf::readInt); Integer time = friendlyByteBuf.readNullable(FriendlyByteBuf::readInt);
Boolean freezeTime = friendlyByteBuf.readNullable(FriendlyByteBuf::readBoolean); Boolean freezeTime = friendlyByteBuf.readNullable(FriendlyByteBuf::readBoolean);

Datei anzeigen

@ -0,0 +1,53 @@
package com.moulberry.axiom.packet;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.event.AxiomTimeChangeEvent;
import com.moulberry.axiom.world_properties.WorldPropertyCategory;
import com.moulberry.axiom.world_properties.server.ServerWorldPropertiesRegistry;
import com.moulberry.axiom.world_properties.server.ServerWorldProperty;
import io.netty.buffer.Unpooled;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Map;
public class SetWorldPropertyListener implements PluginMessageListener {
@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, @NotNull byte[] message) {
if (!player.hasPermission("axiom.*")) {
return;
}
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
ResourceLocation id = friendlyByteBuf.readResourceLocation();
int type = friendlyByteBuf.readVarInt();
byte[] data = friendlyByteBuf.readByteArray();
int updateId = friendlyByteBuf.readVarInt();
ServerWorldPropertiesRegistry registry = AxiomPaper.PLUGIN.getWorldProperties(player.getWorld());
if (registry == null) return;
ServerWorldProperty<?> property = registry.getById(id);
if (property != null && property.getType().getTypeId() == type) {
property.update(player.getWorld(), data);
}
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
buf.writeVarInt(updateId);
player.sendPluginMessage(AxiomPaper.PLUGIN, "axiom:ack_world_properties",
buf.accessByteBufWithCorrectSize());
}
}

Datei anzeigen

@ -3,6 +3,7 @@ package com.moulberry.axiom.world_properties;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.util.Unit;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
@ -108,4 +109,21 @@ public abstract class WorldPropertyDataType<T> {
} }
}; };
public static WorldPropertyDataType<Unit> EMPTY = new WorldPropertyDataType<>() {
@Override
public int getTypeId() {
return 5;
}
@Override
public byte[] serialize(Unit value) {
return new byte[0];
}
@Override
public Unit deserialize(byte[] bytes) {
return Unit.INSTANCE;
}
};
} }

Datei anzeigen

@ -1,23 +1,14 @@
package com.moulberry.axiom.world_properties; package com.moulberry.axiom.world_properties;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Unit;
public interface WorldPropertyWidgetType<T> { public interface WorldPropertyWidgetType<T> {
WorldPropertyDataType<T> dataType(); WorldPropertyDataType<T> dataType();
void write(FriendlyByteBuf friendlyByteBuf); void write(FriendlyByteBuf friendlyByteBuf);
static WorldPropertyWidgetType<?> read(FriendlyByteBuf friendlyByteBuf) {
int type = friendlyByteBuf.readVarInt();
return switch (type) {
case 0 -> CHECKBOX;
case 1 -> new Slider(friendlyByteBuf.readInt(), friendlyByteBuf.readInt());
case 2 -> TEXTBOX;
case 3 -> TIME;
default -> throw new RuntimeException("Unknown widget type: " + type);
};
}
WorldPropertyWidgetType<Boolean> CHECKBOX = new WorldPropertyWidgetType<>() { WorldPropertyWidgetType<Boolean> CHECKBOX = new WorldPropertyWidgetType<>() {
@Override @Override
public WorldPropertyDataType<Boolean> dataType() { public WorldPropertyDataType<Boolean> dataType() {
@ -68,4 +59,17 @@ public interface WorldPropertyWidgetType<T> {
} }
}; };
WorldPropertyWidgetType<Unit> BUTTON = new WorldPropertyWidgetType<>() {
@Override
public WorldPropertyDataType<Unit> dataType() {
return WorldPropertyDataType.EMPTY;
}
@Override
public void write(FriendlyByteBuf friendlyByteBuf) {
friendlyByteBuf.writeVarInt(4);
}
};
} }

Datei anzeigen

@ -1,11 +1,14 @@
package com.moulberry.axiom.world_properties.server; package com.moulberry.axiom.world_properties.server;
import com.moulberry.axiom.AxiomPaper;
import com.moulberry.axiom.world_properties.WorldPropertyCategory;
import com.moulberry.axiom.world_properties.WorldPropertyDataType; import com.moulberry.axiom.world_properties.WorldPropertyDataType;
import com.moulberry.axiom.world_properties.WorldPropertyWidgetType; import com.moulberry.axiom.world_properties.WorldPropertyWidgetType;
import io.netty.buffer.Unpooled;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel; import org.bukkit.World;
import net.minecraft.server.level.ServerPlayer; import org.bukkit.entity.Player;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -36,22 +39,37 @@ public class ServerWorldProperty<T> {
return this.widget.dataType(); return this.widget.dataType();
} }
public void update(ServerLevel serverLevel, byte[] data) { public void update(World world, byte[] data) {
this.value = this.widget.dataType().deserialize(data); this.value = this.widget.dataType().deserialize(data);
if (this.handler.test(this.value)) { if (this.handler.test(this.value)) {
// AxiomClientboundSetWorldProperty packet = new AxiomClientboundSetWorldProperty(this.id, this.sync(world);
// this.widget.dataType().getTypeId(), this.widget.dataType().serialize(this.value));
// for (ServerPlayer player : serverLevel.players()) {
// if (player.hasPermissions(2)) packet.send(player);
// }
} }
} }
public void setValue(T value) { public void setValueWithoutSyncing(T value) {
this.value = value; this.value = value;
} }
public void setValue(World world, T value) {
this.value = value;
this.sync(world);
}
public void sync(World world) {
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
buf.writeResourceLocation(this.id);
buf.writeVarInt(this.widget.dataType().getTypeId());
buf.writeByteArray(this.widget.dataType().serialize(this.value));
byte[] message = buf.accessByteBufWithCorrectSize();
for (Player player : world.getPlayers()) {
if (AxiomPaper.PLUGIN.activeAxiomPlayers.contains(player.getUniqueId())) {
player.sendPluginMessage(AxiomPaper.PLUGIN, "axiom:set_world_property", message);
}
}
}
public void write(FriendlyByteBuf friendlyByteBuf) { public void write(FriendlyByteBuf friendlyByteBuf) {
friendlyByteBuf.writeResourceLocation(this.id); friendlyByteBuf.writeResourceLocation(this.id);
friendlyByteBuf.writeUtf(this.name); friendlyByteBuf.writeUtf(this.name);