11package com .moulberry .axiom ;
22
33import com .google .common .util .concurrent .RateLimiter ;
4- import com .mojang .brigadier .StringReader ;
5- import com .moulberry .axiom .buffer .BlockBuffer ;
64import com .moulberry .axiom .buffer .CompressedBlockEntity ;
75import com .moulberry .axiom .event .AxiomCreateWorldPropertiesEvent ;
86import com .moulberry .axiom .event .AxiomModifyWorldEvent ;
7+ import com .moulberry .axiom .integration .plotsquared .PlotSquaredIntegration ;
98import com .moulberry .axiom .packet .*;
109import com .moulberry .axiom .world_properties .server .ServerWorldPropertiesRegistry ;
1110import io .netty .buffer .Unpooled ;
1514import io .papermc .paper .network .ChannelInitializeListener ;
1615import io .papermc .paper .network .ChannelInitializeListenerHolder ;
1716import net .kyori .adventure .key .Key ;
18- import net .minecraft .commands .arguments .blocks .BlockPredicateArgument ;
19- import net .minecraft .commands .arguments .blocks .BlockStateArgument ;
20- import net .minecraft .commands .arguments .blocks .BlockStateParser ;
17+ import net .minecraft .core .BlockPos ;
2118import net .minecraft .core .IdMapper ;
22- import net .minecraft .core .registries .BuiltInRegistries ;
2319import net .minecraft .network .Connection ;
2420import net .minecraft .network .ConnectionProtocol ;
2521import net .minecraft .network .FriendlyByteBuf ;
2622import net .minecraft .network .protocol .Packet ;
2723import net .minecraft .network .protocol .PacketFlow ;
2824import net .minecraft .network .protocol .common .ServerboundCustomPayloadPacket ;
2925import net .minecraft .server .MinecraftServer ;
30- import net .minecraft .world .level .block .Block ;
31- import net .minecraft .world .level .block .Blocks ;
3226import net .minecraft .world .level .block .state .BlockState ;
3327import org .bukkit .*;
3428import org .bukkit .configuration .Configuration ;
4337
4438import java .util .*;
4539import java .util .concurrent .ConcurrentHashMap ;
46- import java .util .concurrent .TimeUnit ;
47- import java .util .logging .Level ;
4840
4941public class AxiomPaper extends JavaPlugin implements Listener {
5042
5143 public static AxiomPaper PLUGIN ; // tsk tsk tsk
5244
5345 public final Set <UUID > activeAxiomPlayers = Collections .newSetFromMap (new ConcurrentHashMap <>());
5446 public final Map <UUID , RateLimiter > playerBlockBufferRateLimiters = new ConcurrentHashMap <>();
47+ public final Map <UUID , Restrictions > playerRestrictions = new ConcurrentHashMap <>();
5548 public Configuration configuration ;
5649
5750 public IdMapper <BlockState > allowedBlockRegistry = null ;
@@ -90,6 +83,7 @@ public void onEnable() {
9083 msg .registerOutgoingPluginChannel (this , "axiom:register_world_properties" );
9184 msg .registerOutgoingPluginChannel (this , "axiom:set_world_property" );
9285 msg .registerOutgoingPluginChannel (this , "axiom:ack_world_properties" );
86+ msg .registerOutgoingPluginChannel (this , "axiom:restrictions" );
9387
9488 if (configuration .getBoolean ("packet-handlers.hello" )) {
9589 msg .registerIncomingPluginChannel (this , "axiom:hello" , new HelloPacketListener (this ));
@@ -124,6 +118,15 @@ public void onEnable() {
124118 if (configuration .getBoolean ("packet-handlers.request-chunk-data" )) {
125119 msg .registerIncomingPluginChannel (this , "axiom:request_chunk_data" , new RequestChunkDataPacketListener (this ));
126120 }
121+ if (configuration .getBoolean ("packet-handlers.spawn-entity" )) {
122+ msg .registerIncomingPluginChannel (this , "axiom:spawn_entity" , new SpawnEntityPacketListener (this ));
123+ }
124+ if (configuration .getBoolean ("packet-handlers.manipulate-entity" )) {
125+ msg .registerIncomingPluginChannel (this , "axiom:manipulate_entity" , new ManipulateEntityPacketListener (this ));
126+ }
127+ if (configuration .getBoolean ("packet-handlers.delete-entity" )) {
128+ msg .registerIncomingPluginChannel (this , "axiom:delete_entity" , new DeleteEntityPacketListener (this ));
129+ }
127130
128131 if (configuration .getBoolean ("packet-handlers.set-buffer" )) {
129132 SetBlockBufferPacketListener setBlockBufferPacketListener = new SetBlockBufferPacketListener (this );
@@ -153,6 +156,13 @@ public void afterInitChannel(@NonNull Channel channel) {
153156 Bukkit .getScheduler ().scheduleSyncRepeatingTask (this , () -> {
154157 HashSet <UUID > stillActiveAxiomPlayers = new HashSet <>();
155158
159+ int rateLimit = this .configuration .getInt ("block-buffer-rate-limit" );
160+ if (rateLimit > 0 ) {
161+ // Reduce by 20% just to prevent synchronization/timing issues
162+ rateLimit = rateLimit * 8 /10 ;
163+ if (rateLimit <= 0 ) rateLimit = 1 ;
164+ }
165+
156166 for (Player player : Bukkit .getServer ().getOnlinePlayers ()) {
157167 if (activeAxiomPlayers .contains (player .getUniqueId ())) {
158168 if (!player .hasPermission ("axiom.*" )) {
@@ -162,13 +172,70 @@ public void afterInitChannel(@NonNull Channel channel) {
162172 buf .getBytes (0 , bytes );
163173 player .sendPluginMessage (this , "axiom:enable" , bytes );
164174 } else {
165- stillActiveAxiomPlayers .add (player .getUniqueId ());
175+ UUID uuid = player .getUniqueId ();
176+ stillActiveAxiomPlayers .add (uuid );
177+
178+ boolean send = false ;
179+
180+ Restrictions restrictions = playerRestrictions .get (uuid );
181+ if (restrictions == null ) {
182+ restrictions = new Restrictions ();
183+ playerRestrictions .put (uuid , restrictions );
184+ send = true ;
185+ }
186+
187+ BlockPos boundsMin = null ;
188+ BlockPos boundsMax = null ;
189+
190+ if (!player .hasPermission ("axiom.allow_copying_other_plots" )) {
191+ if (PlotSquaredIntegration .isPlotWorld (player .getWorld ())) {
192+ PlotSquaredIntegration .PlotBounds editable = PlotSquaredIntegration .getCurrentEditablePlot (player );
193+ if (editable != null ) {
194+ restrictions .lastPlotBounds = editable ;
195+ boundsMin = editable .min ();
196+ boundsMax = editable .max ();
197+ } else if (restrictions .lastPlotBounds != null && restrictions .lastPlotBounds .worldName ().equals (player .getWorld ().getName ())) {
198+ boundsMin = restrictions .lastPlotBounds .min ();
199+ boundsMax = restrictions .lastPlotBounds .max ();
200+ } else {
201+ boundsMin = BlockPos .ZERO ;
202+ boundsMax = BlockPos .ZERO ;
203+ }
204+ }
205+
206+ int min = Integer .MIN_VALUE ;
207+ int max = Integer .MAX_VALUE ;
208+ if (boundsMin != null && boundsMax != null &&
209+ boundsMin .getX () == min && boundsMin .getY () == min && boundsMin .getZ () == min &&
210+ boundsMax .getX () == max && boundsMax .getY () == max && boundsMax .getZ () == max ) {
211+ boundsMin = null ;
212+ boundsMax = null ;
213+ }
214+ }
215+
216+ boolean allowImportingBlocks = player .hasPermission ("axiom.can_import_blocks" );
217+
218+ if (restrictions .maxSectionsPerSecond != rateLimit ||
219+ restrictions .canImportBlocks != allowImportingBlocks ||
220+ !Objects .equals (restrictions .boundsMin , boundsMin ) ||
221+ !Objects .equals (restrictions .boundsMax , boundsMax )) {
222+ restrictions .maxSectionsPerSecond = rateLimit ;
223+ restrictions .canImportBlocks = allowImportingBlocks ;
224+ restrictions .boundsMin = boundsMin ;
225+ restrictions .boundsMax = boundsMax ;
226+ send = true ;
227+ }
228+
229+ if (send ) {
230+ restrictions .send (this , player );
231+ }
166232 }
167233 }
168234 }
169235
170236 activeAxiomPlayers .retainAll (stillActiveAxiomPlayers );
171237 playerBlockBufferRateLimiters .keySet ().retainAll (stillActiveAxiomPlayers );
238+ playerRestrictions .keySet ().retainAll (stillActiveAxiomPlayers );
172239 }, 20 , 20 );
173240
174241 int maxChunkRelightsPerTick = configuration .getInt ("max-chunk-relights-per-tick" );
0 commit comments