geforkt von Mirrors/AxiomPaperPlugin
Update master #3
@ -12,7 +12,7 @@ public class AxiomConstants {
|
||||
}
|
||||
}
|
||||
|
||||
public static final int API_VERSION = 5;
|
||||
public static final int API_VERSION = 6;
|
||||
public static final NamespacedKey ACTIVE_HOTBAR_INDEX = new NamespacedKey("axiom", "active_hotbar_index");
|
||||
public static final NamespacedKey HOTBAR_DATA = new NamespacedKey("axiom", "hotbar_data");
|
||||
|
||||
|
@ -1,10 +1,17 @@
|
||||
package com.moulberry.axiom;
|
||||
|
||||
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.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.ServerWorldProperty;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.papermc.paper.event.player.PlayerFailMoveEvent;
|
||||
import io.papermc.paper.event.world.WorldGameRuleChangeEvent;
|
||||
import io.papermc.paper.network.ChannelInitializeListener;
|
||||
import io.papermc.paper.network.ChannelInitializeListenerHolder;
|
||||
import net.kyori.adventure.key.Key;
|
||||
@ -14,22 +21,34 @@ import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.PacketFlow;
|
||||
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.messaging.Messenger;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class AxiomPaper extends JavaPlugin implements Listener {
|
||||
|
||||
public static AxiomPaper PLUGIN; // tsk tsk tsk
|
||||
|
||||
public final Set<UUID> activeAxiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
PLUGIN = this;
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(this, this);
|
||||
// Bukkit.getPluginManager().registerEvents(new WorldPropertiesExample(), this);
|
||||
CompressedBlockEntity.initialize(this);
|
||||
|
||||
Messenger msg = Bukkit.getMessenger();
|
||||
@ -38,12 +57,15 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:initialize_hotbars");
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:set_editor_views");
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:block_entities");
|
||||
|
||||
final Set<UUID> activeAxiomPlayers = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:register_world_properties");
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:set_world_property");
|
||||
msg.registerOutgoingPluginChannel(this, "axiom:ack_world_properties");
|
||||
|
||||
msg.registerIncomingPluginChannel(this, "axiom:hello", new HelloPacketListener(this, activeAxiomPlayers));
|
||||
msg.registerIncomingPluginChannel(this, "axiom:set_gamemode", new SetGamemodePacketListener());
|
||||
msg.registerIncomingPluginChannel(this, "axiom:set_fly_speed", new SetFlySpeedPacketListener());
|
||||
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_hotbar_slot", new SetHotbarSlotPacketListener());
|
||||
msg.registerIncomingPluginChannel(this, "axiom:switch_active_hotbar", new SwitchActiveHotbarPacketListener());
|
||||
@ -94,12 +116,76 @@ public class AxiomPaper extends JavaPlugin implements Listener {
|
||||
}, 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
|
||||
public void onFailMove(PlayerFailMoveEvent event) {
|
||||
if (event.getPlayer().hasPermission("axiom.*") &&
|
||||
event.getFailReason() == PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY) {
|
||||
event.getFailReason() == PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY) {
|
||||
event.setAllowed(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChangedWorld(PlayerChangedWorldEvent event) {
|
||||
World world = event.getPlayer().getWorld();
|
||||
|
||||
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
|
||||
public void onJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
Bukkit.getScheduler().scheduleSyncDelayedTask(this, () -> {
|
||||
World world = player.getWorld();
|
||||
|
||||
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?
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onGameRuleChanged(WorldGameRuleChangeEvent event) {
|
||||
if (event.getGameRule() == GameRule.DO_WEATHER_CYCLE) {
|
||||
ServerWorldPropertiesRegistry properties = getWorldProperties(event.getWorld());
|
||||
if (properties != null) {
|
||||
ServerWorldProperty<?> property = properties.getById(new ResourceLocation("axiom:pause_weather"));
|
||||
if (property != null) {
|
||||
((ServerWorldProperty<Boolean>)property).setValue(event.getWorld(), !Boolean.parseBoolean(event.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ServerWorldPropertiesRegistry createWorldProperties(World world) {
|
||||
ServerWorldPropertiesRegistry registry = new ServerWorldPropertiesRegistry(world);
|
||||
|
||||
AxiomCreateWorldPropertiesEvent createEvent = new AxiomCreateWorldPropertiesEvent(world, registry);
|
||||
Bukkit.getPluginManager().callEvent(createEvent);
|
||||
if (createEvent.isCancelled()) return null;
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
}
|
||||
|
55
src/main/java/com/moulberry/axiom/WorldPropertiesExample.java
Normale Datei
55
src/main/java/com/moulberry/axiom/WorldPropertiesExample.java
Normale Datei
@ -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));
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
56
src/main/java/com/moulberry/axiom/event/AxiomTimeChangeEvent.java
Normale Datei
56
src/main/java/com/moulberry/axiom/event/AxiomTimeChangeEvent.java
Normale Datei
@ -0,0 +1,56 @@
|
||||
package com.moulberry.axiom.event;
|
||||
|
||||
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;
|
||||
|
||||
public class AxiomTimeChangeEvent extends Event implements Cancellable {
|
||||
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
|
||||
private final Player player;
|
||||
private final @Nullable Integer time;
|
||||
private final @Nullable Boolean freezeTime;
|
||||
private boolean cancelled = false;
|
||||
|
||||
public AxiomTimeChangeEvent(Player player, @Nullable Integer time, @Nullable Boolean freezeTime) {
|
||||
this.player = player;
|
||||
this.time = time;
|
||||
this.freezeTime = freezeTime;
|
||||
}
|
||||
|
||||
public @Nullable Integer getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public @Nullable Boolean isFreezeTime() {
|
||||
return freezeTime;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
@ -4,6 +4,9 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RegionProtection {
|
||||
|
||||
private final RegionProtectionWorldGuard worldGuard;
|
||||
@ -16,8 +19,17 @@ public class RegionProtection {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canBuildInSection(int cx, int cy, int cz) {
|
||||
if (this.worldGuard != null && !this.worldGuard.canBuildInSection(cx, cy, cz)) return false;
|
||||
public SectionProtection getSection(int cx, int cy, int cz) {
|
||||
List<SectionProtection> protections = new ArrayList<>();
|
||||
if (this.worldGuard != null) {
|
||||
return this.worldGuard.getSection(cx, cy, cz);
|
||||
}
|
||||
// todo: PlotSquared
|
||||
return SectionProtection.ALLOW;
|
||||
}
|
||||
|
||||
public boolean canBuild(int x, int y, int z) {
|
||||
if (this.worldGuard != null && !this.worldGuard.canBuild(x, y, z)) return false;
|
||||
// todo: PlotSquared
|
||||
return true;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
package com.moulberry.axiom.integration;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldguard.LocalPlayer;
|
||||
@ -7,16 +9,21 @@ import com.sk89q.worldguard.WorldGuard;
|
||||
import com.sk89q.worldguard.bukkit.WorldGuardPlugin;
|
||||
import com.sk89q.worldguard.internal.platform.WorldGuardPlatform;
|
||||
import com.sk89q.worldguard.protection.ApplicableRegionSet;
|
||||
import com.sk89q.worldguard.protection.FlagValueCalculator;
|
||||
import com.sk89q.worldguard.protection.association.RegionAssociable;
|
||||
import com.sk89q.worldguard.protection.flags.Flags;
|
||||
import com.sk89q.worldguard.protection.flags.RegionGroup;
|
||||
import com.sk89q.worldguard.protection.flags.StateFlag;
|
||||
import com.sk89q.worldguard.protection.managers.RegionManager;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
|
||||
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
|
||||
import com.sk89q.worldguard.protection.regions.RegionContainer;
|
||||
import com.sk89q.worldguard.protection.regions.RegionQuery;
|
||||
import com.sk89q.worldguard.protection.regions.*;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class RegionProtectionWorldGuard {
|
||||
|
||||
private final LocalPlayer player;
|
||||
@ -32,12 +39,15 @@ public class RegionProtectionWorldGuard {
|
||||
WorldGuardPlatform platform = WorldGuard.getInstance().getPlatform();
|
||||
|
||||
RegionContainer regionContainer = platform.getRegionContainer();
|
||||
if (regionContainer == null) return null;
|
||||
|
||||
com.sk89q.worldedit.world.World worldEditWorld = BukkitAdapter.adapt(world);
|
||||
LocalPlayer worldGuardPlayer = WorldGuardPlugin.inst().wrapPlayer(player);
|
||||
|
||||
// Don't do any protection if player has bypass
|
||||
if (platform.getSessionManager().hasBypass(worldGuardPlayer, worldEditWorld)) {
|
||||
return null;
|
||||
// todo: enable bypass
|
||||
// return null;
|
||||
}
|
||||
|
||||
RegionManager regionManager = regionContainer.get(worldEditWorld);
|
||||
@ -46,12 +56,128 @@ public class RegionProtectionWorldGuard {
|
||||
return new RegionProtectionWorldGuard(worldGuardPlayer, regionManager);
|
||||
}
|
||||
|
||||
public boolean canBuildInSection(int cx, int cy, int cz) {
|
||||
public SectionProtection getSection(int cx, int cy, int cz) {
|
||||
BlockVector3 min = BlockVector3.at(cx*16, cy*16, cz*16);
|
||||
BlockVector3 max = BlockVector3.at(cx*16+15, cy*16+15, cz*16+15);
|
||||
ProtectedRegion test = new ProtectedCuboidRegion("dummy", min, max);
|
||||
ApplicableRegionSet regions = this.regionManager.getApplicableRegions(test, RegionQuery.QueryOption.COMPUTE_PARENTS);
|
||||
return regions.testState(this.player, Flags.BUILD);
|
||||
|
||||
int minimumPriority = Integer.MIN_VALUE;
|
||||
|
||||
Map<ProtectedRegion, StateFlag.State> consideredValues = new HashMap<>();
|
||||
Set<ProtectedRegion> ignoredParents = new HashSet<>();
|
||||
|
||||
for (ProtectedRegion region : regions) {
|
||||
int priority = FlagValueCalculator.getPriorityOf(region);
|
||||
|
||||
// todo: this logic doesn't work for us in determining ALLOW, DENY, CHECK
|
||||
if (priority < minimumPriority) {
|
||||
break;
|
||||
}
|
||||
|
||||
// todo: have to keep track of 2 booleans: partialAllow & partialDeny
|
||||
|
||||
if (ignoredParents.contains(region)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
StateFlag.State value = FlagValueCalculator.getEffectiveFlagOf(region, Flags.BUILD, this.player);
|
||||
if (value != null) {
|
||||
minimumPriority = priority;
|
||||
consideredValues.put(region, value);
|
||||
}
|
||||
|
||||
addParents(ignoredParents, region);
|
||||
|
||||
// The BUILD flag is implicitly set on every region where
|
||||
// PASSTHROUGH is not set to ALLOW
|
||||
if (minimumPriority != priority && Flags.BUILD.implicitlySetWithMembership() &&
|
||||
FlagValueCalculator.getEffectiveFlagOf(region, Flags.PASSTHROUGH, this.player) != StateFlag.State.ALLOW) {
|
||||
minimumPriority = priority;
|
||||
}
|
||||
}
|
||||
|
||||
if (consideredValues.isEmpty()) {
|
||||
if (Flags.BUILD.usesMembershipAsDefault()) {
|
||||
// todo
|
||||
// switch (getMembership(subject)) {
|
||||
// case FAIL:
|
||||
// return ImmutableList.of();
|
||||
// case SUCCESS:
|
||||
// return (Collection<V>) ImmutableList.of(StateFlag.State.ALLOW);
|
||||
// }
|
||||
}
|
||||
|
||||
System.out.println("returning default");
|
||||
StateFlag.State fallback = Flags.BUILD.getDefault();
|
||||
return fallback == StateFlag.State.DENY ? SectionProtection.DENY : SectionProtection.ALLOW;
|
||||
}
|
||||
|
||||
boolean hasPartialDeny = false;
|
||||
for (Map.Entry<ProtectedRegion, StateFlag.State> entry : consideredValues.entrySet()) {
|
||||
ProtectedRegion region = entry.getKey();
|
||||
if (entry.getValue() == StateFlag.State.DENY) {
|
||||
System.out.println("found region with deny!");
|
||||
if (region instanceof GlobalProtectedRegion) {
|
||||
return SectionProtection.DENY;
|
||||
} else if (region instanceof ProtectedCuboidRegion && doesRegionCompletelyContainSection(region, cx, cy, cz)) {
|
||||
return SectionProtection.DENY;
|
||||
}
|
||||
hasPartialDeny = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasPartialDeny) {
|
||||
System.out.println("returning check!");
|
||||
return new SectionProtection() {
|
||||
@Override
|
||||
public SectionState getSectionState() {
|
||||
return SectionState.CHECK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(int wx, int wy, int wz) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
// return complex thing
|
||||
}
|
||||
|
||||
System.out.println("returning allow!");
|
||||
return SectionProtection.ALLOW;
|
||||
}
|
||||
|
||||
private boolean doesRegionCompletelyContainSection(ProtectedRegion region, int cx, int cy, int cz) {
|
||||
BlockVector3 regionMin = region.getMinimumPoint();
|
||||
|
||||
if (regionMin.getBlockX() > cx*16) return false;
|
||||
if (regionMin.getBlockY() > cy*16) return false;
|
||||
if (regionMin.getBlockZ() > cz*16) return false;
|
||||
|
||||
BlockVector3 regionMax = region.getMaximumPoint();
|
||||
|
||||
if (regionMax.getBlockX() < cx*16+15) return false;
|
||||
if (regionMax.getBlockY() < cy*16+15) return false;
|
||||
if (regionMax.getBlockZ() < cz*16+15) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void addParents(Set<ProtectedRegion> ignored, ProtectedRegion region) {
|
||||
ProtectedRegion parent = region.getParent();
|
||||
|
||||
while (parent != null) {
|
||||
ignored.add(parent);
|
||||
parent = parent.getParent();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canBuild(int x, int y, int z) {
|
||||
return this.regionManager.getApplicableRegions(BlockVector3.at(x, y, z)).testState(this.player, Flags.BUILD);
|
||||
}
|
||||
|
||||
public boolean isAllowed(LocalPlayer player, ProtectedRegion protectedRegion) {
|
||||
return protectedRegion.isOwner(player) || protectedRegion.isMember(player);
|
||||
}
|
||||
|
||||
}
|
||||
|
38
src/main/java/com/moulberry/axiom/integration/SectionProtection.java
Normale Datei
38
src/main/java/com/moulberry/axiom/integration/SectionProtection.java
Normale Datei
@ -0,0 +1,38 @@
|
||||
package com.moulberry.axiom.integration;
|
||||
|
||||
public interface SectionProtection {
|
||||
|
||||
SectionProtection ALLOW = new SectionProtection() {
|
||||
@Override
|
||||
public SectionState getSectionState() {
|
||||
return SectionState.ALLOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(int wx, int wy, int wz) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
SectionProtection DENY = new SectionProtection() {
|
||||
@Override
|
||||
public SectionState getSectionState() {
|
||||
return SectionState.DENY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(int wx, int wy, int wz) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
enum SectionState {
|
||||
ALLOW,
|
||||
DENY,
|
||||
CHECK
|
||||
}
|
||||
|
||||
SectionState getSectionState();
|
||||
boolean check(int wx, int wy, int wz);
|
||||
|
||||
}
|
@ -60,7 +60,6 @@ public class HelloPacketListener implements PluginMessageListener {
|
||||
// Enable
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
buf.writeBoolean(true);
|
||||
buf.writeByte(0); // todo: world properties
|
||||
buf.writeInt(handshakeEvent.getMaxBufferSize()); // Max Buffer Size
|
||||
buf.writeBoolean(false); // No source info
|
||||
buf.writeBoolean(false); // No source settings
|
||||
|
@ -6,6 +6,7 @@ import com.moulberry.axiom.buffer.BlockBuffer;
|
||||
import com.moulberry.axiom.buffer.CompressedBlockEntity;
|
||||
import com.moulberry.axiom.event.AxiomModifyWorldEvent;
|
||||
import com.moulberry.axiom.integration.RegionProtection;
|
||||
import com.moulberry.axiom.integration.SectionProtection;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
@ -38,6 +39,7 @@ import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.EntityBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
@ -135,9 +137,14 @@ public class SetBlockBufferPacketListener {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!regionProtection.canBuildInSection(cx, cy, cz)) {
|
||||
continue;
|
||||
}
|
||||
SectionProtection sectionProtection = regionProtection.getSection(cx, cy, cz);
|
||||
// switch (sectionProtection.getSectionState()) {
|
||||
// case ALLOW -> sectionProtection = null;
|
||||
// case DENY -> {
|
||||
// continue;
|
||||
// }
|
||||
// case CHECK -> {}
|
||||
// }
|
||||
|
||||
LevelChunk chunk = world.getChunk(cx, cz);
|
||||
chunk.setUnsaved(true);
|
||||
@ -170,10 +177,20 @@ public class SetBlockBufferPacketListener {
|
||||
BlockState blockState = container.get(x, y, z);
|
||||
if (blockState == emptyState) continue;
|
||||
|
||||
switch (sectionProtection.getSectionState()) {
|
||||
case ALLOW -> {}
|
||||
case DENY -> blockState = Blocks.REDSTONE_BLOCK.defaultBlockState();
|
||||
case CHECK -> blockState = Blocks.DIAMOND_BLOCK.defaultBlockState();
|
||||
}
|
||||
|
||||
int bx = cx*16 + x;
|
||||
int by = cy*16 + y;
|
||||
int bz = cz*16 + z;
|
||||
|
||||
// if (!regionProtection.canBuild(bx, by, bz)) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
blockPos.set(bx, by, bz);
|
||||
|
||||
if (hasOnlyAir && blockState.isAir()) {
|
||||
|
@ -8,6 +8,8 @@ import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.EntityBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
@ -16,9 +18,14 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.lighting.LightEngine;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.block.CraftBlock;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.block.Action;
|
||||
import org.bukkit.event.player.PlayerInteractEvent;
|
||||
import org.bukkit.plugin.messaging.PluginMessageListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
|
||||
@ -61,97 +68,130 @@ public class SetBlockPacketListener implements PluginMessageListener {
|
||||
|
||||
// Read packet
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
BlockPos blockPos = friendlyByteBuf.readBlockPos();
|
||||
BlockState blockState = friendlyByteBuf.readById(Block.BLOCK_STATE_REGISTRY);
|
||||
Map<BlockPos, BlockState> blocks = friendlyByteBuf.readMap(FriendlyByteBuf::readBlockPos, buf -> buf.readById(Block.BLOCK_STATE_REGISTRY));
|
||||
boolean updateNeighbors = friendlyByteBuf.readBoolean();
|
||||
int sequenceId = friendlyByteBuf.readInt();
|
||||
|
||||
int reason = friendlyByteBuf.readVarInt();
|
||||
boolean breaking = friendlyByteBuf.readBoolean();
|
||||
BlockHitResult blockHit = friendlyByteBuf.readBlockHitResult();
|
||||
InteractionHand hand = friendlyByteBuf.readEnum(InteractionHand.class);
|
||||
int sequenceId = friendlyByteBuf.readVarInt();
|
||||
|
||||
ServerPlayer player = ((CraftPlayer)bukkitPlayer).getHandle();
|
||||
|
||||
org.bukkit.inventory.ItemStack heldItem;
|
||||
if (hand == InteractionHand.MAIN_HAND) {
|
||||
heldItem = bukkitPlayer.getInventory().getItemInMainHand();
|
||||
} else {
|
||||
heldItem = bukkitPlayer.getInventory().getItemInOffHand();
|
||||
}
|
||||
|
||||
org.bukkit.block.Block blockClicked = bukkitPlayer.getWorld().getBlockAt(blockHit.getBlockPos().getX(),
|
||||
blockHit.getBlockPos().getY(), blockHit.getBlockPos().getZ());
|
||||
|
||||
BlockFace blockFace = CraftBlock.notchToBlockFace(blockHit.getDirection());
|
||||
|
||||
// Call interact event
|
||||
PlayerInteractEvent playerInteractEvent = new PlayerInteractEvent(bukkitPlayer,
|
||||
breaking ? Action.LEFT_CLICK_BLOCK : Action.RIGHT_CLICK_BLOCK, heldItem, blockClicked, blockFace);
|
||||
if (!playerInteractEvent.callEvent()) {
|
||||
if (sequenceId >= 0) {
|
||||
player.connection.ackBlockChangesUpTo(sequenceId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Update blocks
|
||||
if (updateNeighbors) {
|
||||
player.level().setBlock(blockPos, blockState, 3);
|
||||
for (Map.Entry<BlockPos, BlockState> entry : blocks.entrySet()) {
|
||||
player.level().setBlock(entry.getKey(), entry.getValue(), 3);
|
||||
}
|
||||
} else {
|
||||
int bx = blockPos.getX();
|
||||
int by = blockPos.getY();
|
||||
int bz = blockPos.getZ();
|
||||
int x = bx & 0xF;
|
||||
int y = by & 0xF;
|
||||
int z = bz & 0xF;
|
||||
int cx = bx >> 4;
|
||||
int cy = by >> 4;
|
||||
int cz = bz >> 4;
|
||||
for (Map.Entry<BlockPos, BlockState> entry : blocks.entrySet()) {
|
||||
BlockPos blockPos = entry.getKey();
|
||||
BlockState blockState = entry.getValue();
|
||||
|
||||
ServerLevel level = player.serverLevel();
|
||||
LevelChunk chunk = level.getChunk(cx, cz);
|
||||
chunk.setUnsaved(true);
|
||||
int bx = blockPos.getX();
|
||||
int by = blockPos.getY();
|
||||
int bz = blockPos.getZ();
|
||||
int x = bx & 0xF;
|
||||
int y = by & 0xF;
|
||||
int z = bz & 0xF;
|
||||
int cx = bx >> 4;
|
||||
int cy = by >> 4;
|
||||
int cz = bz >> 4;
|
||||
|
||||
LevelChunkSection section = chunk.getSection(level.getSectionIndexFromSectionY(cy));
|
||||
boolean hasOnlyAir = section.hasOnlyAir();
|
||||
ServerLevel level = player.serverLevel();
|
||||
LevelChunk chunk = level.getChunk(cx, cz);
|
||||
chunk.setUnsaved(true);
|
||||
|
||||
Heightmap worldSurface = null;
|
||||
Heightmap oceanFloor = null;
|
||||
Heightmap motionBlocking = null;
|
||||
Heightmap motionBlockingNoLeaves = null;
|
||||
for (Map.Entry<Heightmap.Types, Heightmap> heightmap : chunk.getHeightmaps()) {
|
||||
switch (heightmap.getKey()) {
|
||||
case WORLD_SURFACE -> worldSurface = heightmap.getValue();
|
||||
case OCEAN_FLOOR -> oceanFloor = heightmap.getValue();
|
||||
case MOTION_BLOCKING -> motionBlocking = heightmap.getValue();
|
||||
case MOTION_BLOCKING_NO_LEAVES -> motionBlockingNoLeaves = heightmap.getValue();
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
LevelChunkSection section = chunk.getSection(level.getSectionIndexFromSectionY(cy));
|
||||
boolean hasOnlyAir = section.hasOnlyAir();
|
||||
|
||||
BlockState old = section.setBlockState(x, y, z, blockState, false);
|
||||
if (blockState != old) {
|
||||
Block block = blockState.getBlock();
|
||||
motionBlocking.update(x, by, z, blockState);
|
||||
motionBlockingNoLeaves.update(x, by, z, blockState);
|
||||
oceanFloor.update(x, by, z, blockState);
|
||||
worldSurface.update(x, by, z, blockState);
|
||||
|
||||
if (blockState.hasBlockEntity()) {
|
||||
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
|
||||
|
||||
if (blockEntity == null) {
|
||||
// There isn't a block entity here, create it!
|
||||
blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState);
|
||||
if (blockEntity != null) {
|
||||
chunk.addAndRegisterBlockEntity(blockEntity);
|
||||
}
|
||||
} else if (blockEntity.getType().isValid(blockState)) {
|
||||
// Block entity is here and the type is correct
|
||||
// Just update the state and ticker and move on
|
||||
blockEntity.setBlockState(blockState);
|
||||
|
||||
try {
|
||||
this.updateBlockEntityTicker.invoke(chunk, blockEntity);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
// Block entity type isn't correct, we need to recreate it
|
||||
chunk.removeBlockEntity(blockPos);
|
||||
|
||||
blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState);
|
||||
if (blockEntity != null) {
|
||||
chunk.addAndRegisterBlockEntity(blockEntity);
|
||||
}
|
||||
Heightmap worldSurface = null;
|
||||
Heightmap oceanFloor = null;
|
||||
Heightmap motionBlocking = null;
|
||||
Heightmap motionBlockingNoLeaves = null;
|
||||
for (Map.Entry<Heightmap.Types, Heightmap> heightmap : chunk.getHeightmaps()) {
|
||||
switch (heightmap.getKey()) {
|
||||
case WORLD_SURFACE -> worldSurface = heightmap.getValue();
|
||||
case OCEAN_FLOOR -> oceanFloor = heightmap.getValue();
|
||||
case MOTION_BLOCKING -> motionBlocking = heightmap.getValue();
|
||||
case MOTION_BLOCKING_NO_LEAVES -> motionBlockingNoLeaves = heightmap.getValue();
|
||||
default -> {}
|
||||
}
|
||||
} else if (old.hasBlockEntity()) {
|
||||
chunk.removeBlockEntity(blockPos);
|
||||
}
|
||||
|
||||
level.getChunkSource().blockChanged(blockPos);
|
||||
if (LightEngine.hasDifferentLightProperties(chunk, blockPos, old, blockState)) {
|
||||
level.getChunkSource().getLightEngine().checkBlock(blockPos);
|
||||
}
|
||||
}
|
||||
BlockState old = section.setBlockState(x, y, z, blockState, false);
|
||||
if (blockState != old) {
|
||||
Block block = blockState.getBlock();
|
||||
motionBlocking.update(x, by, z, blockState);
|
||||
motionBlockingNoLeaves.update(x, by, z, blockState);
|
||||
oceanFloor.update(x, by, z, blockState);
|
||||
worldSurface.update(x, by, z, blockState);
|
||||
|
||||
boolean nowHasOnlyAir = section.hasOnlyAir();
|
||||
if (hasOnlyAir != nowHasOnlyAir) {
|
||||
level.getChunkSource().getLightEngine().updateSectionStatus(SectionPos.of(cx, cy, cz), nowHasOnlyAir);
|
||||
if (blockState.hasBlockEntity()) {
|
||||
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
|
||||
|
||||
if (blockEntity == null) {
|
||||
// There isn't a block entity here, create it!
|
||||
blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState);
|
||||
if (blockEntity != null) {
|
||||
chunk.addAndRegisterBlockEntity(blockEntity);
|
||||
}
|
||||
} else if (blockEntity.getType().isValid(blockState)) {
|
||||
// Block entity is here and the type is correct
|
||||
// Just update the state and ticker and move on
|
||||
blockEntity.setBlockState(blockState);
|
||||
|
||||
try {
|
||||
this.updateBlockEntityTicker.invoke(chunk, blockEntity);
|
||||
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
} else {
|
||||
// Block entity type isn't correct, we need to recreate it
|
||||
chunk.removeBlockEntity(blockPos);
|
||||
|
||||
blockEntity = ((EntityBlock)block).newBlockEntity(blockPos, blockState);
|
||||
if (blockEntity != null) {
|
||||
chunk.addAndRegisterBlockEntity(blockEntity);
|
||||
}
|
||||
}
|
||||
} else if (old.hasBlockEntity()) {
|
||||
chunk.removeBlockEntity(blockPos);
|
||||
}
|
||||
|
||||
level.getChunkSource().blockChanged(blockPos);
|
||||
if (LightEngine.hasDifferentLightProperties(chunk, blockPos, old, blockState)) {
|
||||
level.getChunkSource().getLightEngine().checkBlock(blockPos);
|
||||
}
|
||||
}
|
||||
|
||||
boolean nowHasOnlyAir = section.hasOnlyAir();
|
||||
if (hasOnlyAir != nowHasOnlyAir) {
|
||||
level.getChunkSource().getLightEngine().updateSectionStatus(SectionPos.of(cx, cy, cz), nowHasOnlyAir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@ public class SetFlySpeedPacketListener implements PluginMessageListener {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(Unpooled.wrappedBuffer(message));
|
||||
float flySpeed = friendlyByteBuf.readFloat();
|
||||
|
||||
|
45
src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java
Normale Datei
45
src/main/java/com/moulberry/axiom/packet/SetTimePacketListener.java
Normale Datei
@ -0,0 +1,45 @@
|
||||
package com.moulberry.axiom.packet;
|
||||
|
||||
import com.moulberry.axiom.event.AxiomTimeChangeEvent;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
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;
|
||||
|
||||
public class SetTimePacketListener 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));
|
||||
ResourceKey<Level> key = friendlyByteBuf.readResourceKey(Registries.DIMENSION);
|
||||
Integer time = friendlyByteBuf.readNullable(FriendlyByteBuf::readInt);
|
||||
Boolean freezeTime = friendlyByteBuf.readNullable(FriendlyByteBuf::readBoolean);
|
||||
|
||||
if (time == null && freezeTime == null) return;
|
||||
|
||||
ServerLevel level = ((CraftWorld)player.getWorld()).getHandle();
|
||||
if (!level.dimension().equals(key)) return;
|
||||
|
||||
// Call event
|
||||
AxiomTimeChangeEvent timeChangeEvent = new AxiomTimeChangeEvent(player, time, freezeTime);
|
||||
Bukkit.getPluginManager().callEvent(timeChangeEvent);
|
||||
if (timeChangeEvent.isCancelled()) return;
|
||||
|
||||
// Change time
|
||||
if (time != null) level.setDayTime(time);
|
||||
if (freezeTime != null) level.getGameRules().getRule(GameRules.RULE_DAYLIGHT).set(!freezeTime, null);
|
||||
}
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.moulberry.axiom.world_properties;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
|
||||
public record WorldPropertyCategory(String name, boolean localizeName) {
|
||||
|
||||
public void write(FriendlyByteBuf friendlyByteBuf) {
|
||||
friendlyByteBuf.writeUtf(this.name);
|
||||
friendlyByteBuf.writeBoolean(this.localizeName);
|
||||
}
|
||||
|
||||
public static WorldPropertyCategory read(FriendlyByteBuf friendlyByteBuf) {
|
||||
return new WorldPropertyCategory(
|
||||
friendlyByteBuf.readUtf(),
|
||||
friendlyByteBuf.readBoolean()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
package com.moulberry.axiom.world_properties;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.util.Unit;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public abstract class WorldPropertyDataType<T> {
|
||||
|
||||
public abstract int getTypeId();
|
||||
public abstract byte[] serialize(T value);
|
||||
public abstract T deserialize(byte[] bytes);
|
||||
|
||||
public static WorldPropertyDataType<Boolean> BOOLEAN = new WorldPropertyDataType<>() {
|
||||
@Override
|
||||
public int getTypeId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(Boolean value) {
|
||||
return new byte[] { value ? (byte)1 : (byte)0 };
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean deserialize(byte[] bytes) {
|
||||
return bytes[0] != 0;
|
||||
}
|
||||
};
|
||||
|
||||
public static WorldPropertyDataType<Integer> INTEGER = new WorldPropertyDataType<>() {
|
||||
@Override
|
||||
public int getTypeId() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(Integer value) {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(8));
|
||||
buf.writeVarInt(value);
|
||||
return buf.accessByteBufWithCorrectSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer deserialize(byte[] bytes) {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(bytes));
|
||||
return buf.readVarInt();
|
||||
}
|
||||
};
|
||||
|
||||
public static WorldPropertyDataType<String> STRING = new WorldPropertyDataType<>() {
|
||||
@Override
|
||||
public int getTypeId() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(String value) {
|
||||
return value.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String deserialize(byte[] bytes) {
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
};
|
||||
|
||||
public static WorldPropertyDataType<Item> ITEM = new WorldPropertyDataType<>() {
|
||||
@Override
|
||||
public int getTypeId() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(Item value) {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(8));
|
||||
buf.writeId(BuiltInRegistries.ITEM, value);
|
||||
return buf.accessByteBufWithCorrectSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item deserialize(byte[] bytes) {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(bytes));
|
||||
return buf.readById(BuiltInRegistries.ITEM);
|
||||
}
|
||||
};
|
||||
|
||||
public static WorldPropertyDataType<Block> BLOCK = new WorldPropertyDataType<>() {
|
||||
@Override
|
||||
public int getTypeId() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] serialize(Block value) {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(8));
|
||||
buf.writeId(BuiltInRegistries.BLOCK, value);
|
||||
return buf.accessByteBufWithCorrectSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block deserialize(byte[] bytes) {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.wrappedBuffer(bytes));
|
||||
return buf.readById(BuiltInRegistries.BLOCK);
|
||||
}
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package com.moulberry.axiom.world_properties;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Unit;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface WorldPropertyWidgetType<T> {
|
||||
|
||||
WorldPropertyDataType<T> dataType();
|
||||
void write(FriendlyByteBuf friendlyByteBuf);
|
||||
|
||||
WorldPropertyWidgetType<Boolean> CHECKBOX = new WorldPropertyWidgetType<>() {
|
||||
@Override
|
||||
public WorldPropertyDataType<Boolean> dataType() {
|
||||
return WorldPropertyDataType.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf friendlyByteBuf) {
|
||||
friendlyByteBuf.writeVarInt(0);
|
||||
}
|
||||
};
|
||||
|
||||
record Slider(int min, int max) implements WorldPropertyWidgetType<Integer> {
|
||||
@Override
|
||||
public WorldPropertyDataType<Integer> dataType() {
|
||||
return WorldPropertyDataType.INTEGER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf friendlyByteBuf) {
|
||||
friendlyByteBuf.writeVarInt(1);
|
||||
friendlyByteBuf.writeInt(this.min);
|
||||
friendlyByteBuf.writeInt(this.max);
|
||||
}
|
||||
}
|
||||
|
||||
WorldPropertyWidgetType<String> TEXTBOX = new WorldPropertyWidgetType<>() {
|
||||
@Override
|
||||
public WorldPropertyDataType<String> dataType() {
|
||||
return WorldPropertyDataType.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf friendlyByteBuf) {
|
||||
friendlyByteBuf.writeVarInt(2);
|
||||
}
|
||||
};
|
||||
|
||||
WorldPropertyWidgetType<Integer> TIME = new WorldPropertyWidgetType<>() {
|
||||
@Override
|
||||
public WorldPropertyDataType<Integer> dataType() {
|
||||
return WorldPropertyDataType.INTEGER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf friendlyByteBuf) {
|
||||
friendlyByteBuf.writeVarInt(3);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
WorldPropertyWidgetType<Unit> BUTTON = new WorldPropertyWidgetType<>() {
|
||||
@Override
|
||||
public WorldPropertyDataType<Unit> dataType() {
|
||||
return WorldPropertyDataType.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf friendlyByteBuf) {
|
||||
friendlyByteBuf.writeVarInt(4);
|
||||
}
|
||||
};
|
||||
|
||||
record ButtonArray(List<String> otherButtons) implements WorldPropertyWidgetType<Integer> {
|
||||
@Override
|
||||
public WorldPropertyDataType<Integer> dataType() {
|
||||
return WorldPropertyDataType.INTEGER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf friendlyByteBuf) {
|
||||
friendlyByteBuf.writeVarInt(5);
|
||||
friendlyByteBuf.writeCollection(this.otherButtons, FriendlyByteBuf::writeUtf);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package com.moulberry.axiom.world_properties.server;
|
||||
|
||||
import com.moulberry.axiom.world_properties.WorldPropertyCategory;
|
||||
import com.moulberry.axiom.world_properties.WorldPropertyWidgetType;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
import org.bukkit.GameRule;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ServerWorldPropertiesRegistry {
|
||||
|
||||
private final LinkedHashMap<WorldPropertyCategory, List<ServerWorldProperty<?>>> propertyList = new LinkedHashMap<>();
|
||||
private final Map<ResourceLocation, ServerWorldProperty<?>> propertyMap = new HashMap<>();
|
||||
|
||||
public ServerWorldPropertiesRegistry(World world) {
|
||||
this.registerDefault(world);
|
||||
}
|
||||
|
||||
public ServerWorldProperty<?> getById(ResourceLocation resourceLocation) {
|
||||
return propertyMap.get(resourceLocation);
|
||||
}
|
||||
|
||||
public void addCategory(WorldPropertyCategory category, List<ServerWorldProperty<?>> properties) {
|
||||
this.propertyList.put(category, properties);
|
||||
|
||||
for (ServerWorldProperty<?> property : properties) {
|
||||
ResourceLocation id = property.getId();
|
||||
if (this.propertyMap.containsKey(id)) {
|
||||
throw new RuntimeException("Duplicate property: " + id);
|
||||
}
|
||||
this.propertyMap.put(id, property);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerFor(Plugin plugin, Player bukkitPlayer) {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
|
||||
buf.writeVarInt(this.propertyList.size());
|
||||
|
||||
for (Map.Entry<WorldPropertyCategory, List<ServerWorldProperty<?>>> entry : this.propertyList.entrySet()) {
|
||||
entry.getKey().write(buf);
|
||||
buf.writeCollection(entry.getValue(), (buffer, p) -> p.write(buffer));
|
||||
}
|
||||
|
||||
bukkitPlayer.sendPluginMessage(plugin, "axiom:register_world_properties",
|
||||
buf.accessByteBufWithCorrectSize());
|
||||
}
|
||||
|
||||
public void registerDefault(World world) {
|
||||
ServerLevel serverLevel = ((CraftWorld)world).getHandle();
|
||||
|
||||
// Time
|
||||
WorldPropertyCategory timeCategory = new WorldPropertyCategory("axiom.editorui.window.world_properties.time", true);
|
||||
|
||||
ServerWorldProperty<Integer> time = new ServerWorldProperty<>(new ResourceLocation("axiom:time"),
|
||||
"axiom.editorui.window.world_properties.time",
|
||||
true, WorldPropertyWidgetType.TIME, 0, integer -> false
|
||||
);
|
||||
|
||||
this.addCategory(timeCategory, List.of(time));
|
||||
|
||||
// Weather
|
||||
WorldPropertyCategory weatherCategory = new WorldPropertyCategory("axiom.editorui.window.world_properties.weather",
|
||||
true);
|
||||
|
||||
ServerWorldProperty<Boolean> pauseWeather = new ServerWorldProperty<>(new ResourceLocation("axiom:pause_weather"),
|
||||
"axiom.editorui.window.world_properties.pause_weather",
|
||||
true, WorldPropertyWidgetType.CHECKBOX, !world.getGameRuleValue(GameRule.DO_WEATHER_CYCLE), bool -> {
|
||||
world.setGameRule(GameRule.DO_WEATHER_CYCLE, !bool);
|
||||
return false;
|
||||
});
|
||||
|
||||
ServerWorldProperty<Integer> weatherType = new ServerWorldProperty<>(new ResourceLocation("axiom:weather_type"),
|
||||
"axiom.editorui.window.world_properties.clear_weather",
|
||||
true, new WorldPropertyWidgetType.ButtonArray(
|
||||
List.of("axiom.editorui.window.world_properties.rain_weather", "axiom.editorui.window.world_properties.thunder_weather")
|
||||
), 0, index -> {
|
||||
if (index == 0) {
|
||||
serverLevel.setWeatherParameters(ServerLevel.RAIN_DELAY.sample(serverLevel.random), 0, false, false);
|
||||
} else if (index == 1) {
|
||||
serverLevel.setWeatherParameters(0, ServerLevel.RAIN_DURATION.sample(serverLevel.random), true, false);
|
||||
} else if (index == 2) {
|
||||
serverLevel.setWeatherParameters(0, ServerLevel.THUNDER_DURATION.sample(serverLevel.random), true, true);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
this.addCategory(weatherCategory, List.of(pauseWeather, weatherType));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package com.moulberry.axiom.world_properties.server;
|
||||
|
||||
import com.moulberry.axiom.AxiomPaper;
|
||||
import com.moulberry.axiom.world_properties.WorldPropertyDataType;
|
||||
import com.moulberry.axiom.world_properties.WorldPropertyWidgetType;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ServerWorldProperty<T> {
|
||||
|
||||
private final ResourceLocation id;
|
||||
private final String name;
|
||||
private final boolean localizeName;
|
||||
private WorldPropertyWidgetType<T> widget;
|
||||
private T value;
|
||||
private Predicate<T> handler;
|
||||
|
||||
public ServerWorldProperty(ResourceLocation id, String name, boolean localizeName, WorldPropertyWidgetType<T> widget,
|
||||
T value, Predicate<T> handler) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.localizeName = localizeName;
|
||||
this.widget = widget;
|
||||
this.value = value;
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public ResourceLocation getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public WorldPropertyDataType<T> getType() {
|
||||
return this.widget.dataType();
|
||||
}
|
||||
|
||||
public void update(World world, byte[] data) {
|
||||
this.value = this.widget.dataType().deserialize(data);
|
||||
if (this.handler.test(this.value)) {
|
||||
this.sync(world);
|
||||
}
|
||||
}
|
||||
|
||||
public void setValueWithoutSyncing(T 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) {
|
||||
friendlyByteBuf.writeResourceLocation(this.id);
|
||||
friendlyByteBuf.writeUtf(this.name);
|
||||
friendlyByteBuf.writeBoolean(this.localizeName);
|
||||
this.widget.write(friendlyByteBuf);
|
||||
friendlyByteBuf.writeByteArray(this.widget.dataType().serialize(this.value));
|
||||
}
|
||||
|
||||
}
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren