This commit is contained in:
AlphaKR93
2024-05-04 17:13:01 +09:00
parent 5b5d1c1281
commit 39a32b7ea3
6 changed files with 751 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AlphaKR93 <dev@alpha93.kr>
Date: Mon, 4 Dec 2023 23:17:15 +0900
Subject: [PATCH] Skip event if no listeners
diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
index 7ce9ebba8ce304d1f3f21d4f15ee5f3560d7700b..23594fb7eb4b2f33146592866608c2858ef23937 100644
--- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
@@ -36,15 +36,16 @@ class PaperEventManager {
// SimplePluginManager
public void callEvent(@NotNull Event event) {
+ // Plazma start - Skip event if no listeners
+ RegisteredListener[] listeners = event.getHandlers().getRegisteredListeners();
+ if (listeners.length == 0) return;
+ // Plazma end
if (event.isAsynchronous() && this.server.isPrimaryThread()) {
throw new IllegalStateException(event.getEventName() + " may only be triggered asynchronously.");
} else if (!event.isAsynchronous() && !this.server.isPrimaryThread() && !this.server.isStopping()) {
throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously.");
}
- HandlerList handlers = event.getHandlers();
- RegisteredListener[] listeners = handlers.getRegisteredListeners();
-
for (RegisteredListener registration : listeners) {
if (!registration.getPlugin().isEnabled()) {
continue;

View File

@@ -0,0 +1,81 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AlphaKR93 <dev@alpha93.kr>
Date: Tue, 5 Dec 2023 13:29:28 +0900
Subject: [PATCH] Add entity spawn deadlock timer
[REFERENCE]
- AbsolemJackdaw/FixMySpawnR
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
index 967af8771ff8564c715d89f4b4b69b16c25add59..2ac5fb585636523787e05edaa58a4fa34a39ef28 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -50,6 +50,8 @@ public abstract class BaseSpawner {
public int requiredPlayerRange = 16;
public int spawnRange = 4;
private int tickDelay = 0; // Paper - Configurable mob spawner tick rate
+ private int blockExistsTick = 0; // Plazma - Add entity spawn deadlock timer
+ private boolean blockLockedByTime = false; // Plazma - Add entity spawn deadlock timer
public BaseSpawner() {}
@@ -85,6 +87,17 @@ public abstract class BaseSpawner {
}
public void serverTick(ServerLevel world, BlockPos pos) {
+ // Plazma start - Add entity spawn deadlock timer
+ if (world.plazmaConfig().entity.spawnDeadlockTimer.enabled) {
+ if (!this.blockLockedByTime) {
+ if (this.blockExistsTick > world.plazmaConfig().entity.spawnDeadlockTimer.timerTimeout)
+ blockLockedByTime = true;
+ else blockExistsTick++;
+ }
+
+ if (blockLockedByTime && world.getBestNeighborSignal(pos) > 0) return;
+ }
+ // Plazma end - Add entity spawn deadlock timer
if (spawnCount <= 0 || maxNearbyEntities <= 0) return; // Paper - Ignore impossible spawn tick
// Paper start - Configurable mob spawner tick rate
if (spawnDelay > 0 && --tickDelay > 0) return;
@@ -290,6 +303,13 @@ public abstract class BaseSpawner {
this.spawnRange = nbt.getShort("SpawnRange");
}
+ // Plazma start - Add entity spawn deadlock timer
+ if (nbt.contains("Plazma.SpawnerTicks", 99)) {
+ this.blockExistsTick = nbt.getInt("Plazma.SpawnerTicks");
+ this.blockLockedByTime = nbt.getBoolean("Plazma.SpawnerLocked");
+ }
+ // Plazma end - Add entity spawn deadlock timer
+
this.displayEntity = null;
}
@@ -318,6 +338,8 @@ public abstract class BaseSpawner {
}));
}
+ nbt.putInt("Plazma.SpawnerTicks", this.blockExistsTick); // Plazma - Add entity spawn deadlock timer
+ nbt.putBoolean("Plazma.SpawnerLocked", this.blockLockedByTime); // Plazma - Add entity spawn deadlock timer
nbt.put("SpawnPotentials", (Tag) SpawnData.LIST_CODEC.encodeStart(NbtOps.INSTANCE, this.spawnPotentials).getOrThrow());
return nbt;
}
diff --git a/src/main/java/org/plazmamc/plazma/configurations/WorldConfigurations.java b/src/main/java/org/plazmamc/plazma/configurations/WorldConfigurations.java
index 29514dd01d46ba9f6b123bf3af56981541f670db..6a0cfec24618227d9a5ddc6c71e37d1986147799 100644
--- a/src/main/java/org/plazmamc/plazma/configurations/WorldConfigurations.java
+++ b/src/main/java/org/plazmamc/plazma/configurations/WorldConfigurations.java
@@ -54,6 +54,14 @@ public class WorldConfigurations extends ConfigurationPart {
}
+ public SpawnDeadlockTimer spawnDeadlockTimer;
+ public class SpawnDeadlockTimer extends ConfigurationPart {
+
+ public boolean enabled = OPTIMIZE;
+ public int timerTimeout = 0;
+
+ }
+
}
public Structure structure;

View File

@@ -0,0 +1,306 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AlphaKR93 <dev@alpha93.kr>
Date: Wed, 10 Jan 2024 18:08:59 +0900
Subject: [PATCH] Lithium - HashedList
diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedReferenceList.java b/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedReferenceList.java
new file mode 100644
index 0000000000000000000000000000000000000000..d11579075e653868a43fe826bdf9b41ddc031b85
--- /dev/null
+++ b/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedReferenceList.java
@@ -0,0 +1,277 @@
+package me.jellysquid.mods.lithium.common.util.collections;
+
+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
+import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
+import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+/**
+ * Wraps a {@link List} with a hash table which provides O(1) lookups for {@link Collection#contains(Object)}. The type
+ * contained by this list must use reference-equality semantics.
+ */
+@SuppressWarnings("SuspiciousMethodCalls")
+public class HashedReferenceList<T> implements List<T> {
+ private final ReferenceArrayList<T> list;
+ private final Reference2IntOpenHashMap<T> counter;
+
+ public HashedReferenceList(List<T> list) {
+ this.list = new ReferenceArrayList<>();
+ this.list.addAll(list);
+
+ this.counter = new Reference2IntOpenHashMap<>();
+ this.counter.defaultReturnValue(0);
+
+ for (T obj : this.list) {
+ this.counter.addTo(obj, 1);
+ }
+ }
+
+ @Override
+ public int size() {
+ return this.list.size();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return this.list.isEmpty();
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ return this.counter.containsKey(o);
+ }
+
+ @Override
+ public @NotNull Iterator<T> iterator() {
+ return this.listIterator();
+ }
+
+ @Override
+ public Object @NotNull [] toArray() {
+ return this.list.toArray();
+ }
+
+ @Override
+ public <T1> T1 @NotNull [] toArray(T1 @NotNull [] a) {
+ return this.list.toArray(a);
+ }
+
+ @Override
+ public boolean add(T t) {
+ this.trackReferenceAdded(t);
+
+ return this.list.add(t);
+ }
+
+ @Override
+ public boolean remove(Object o) {
+ this.trackReferenceRemoved(o);
+
+ return this.list.remove(o);
+ }
+
+ @Override
+ public boolean containsAll(Collection<?> c) {
+ for (Object obj : c) {
+ if (!this.counter.containsKey(obj)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends T> c) {
+ for (T obj : c) {
+ this.trackReferenceAdded(obj);
+ }
+
+ return this.list.addAll(c);
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends T> c) {
+ for (T obj : c) {
+ this.trackReferenceAdded(obj);
+ }
+
+ return this.list.addAll(index, c);
+ }
+
+ @Override
+ public boolean removeAll(@NotNull Collection<?> c) {
+ if (this.size() >= 2 && c.size() > 4 && c instanceof List) {
+ //HashReferenceList uses reference equality, so using ReferenceOpenHashSet is fine
+ c = new ReferenceOpenHashSet<>(c);
+ }
+ this.counter.keySet().removeAll(c);
+ return this.list.removeAll(c);
+ }
+
+ @Override
+ public boolean retainAll(@NotNull Collection<?> c) {
+ this.counter.keySet().retainAll(c);
+ return this.list.retainAll(c);
+ }
+
+ @Override
+ public void clear() {
+ this.counter.clear();
+ this.list.clear();
+ }
+
+ @Override
+ public T get(int index) {
+ return this.list.get(index);
+ }
+
+ @Override
+ public T set(int index, T element) {
+ T prev = this.list.set(index, element);
+
+ if (prev != element) {
+ if (prev != null) {
+ this.trackReferenceRemoved(prev);
+ }
+
+ this.trackReferenceAdded(element);
+ }
+
+ return prev;
+ }
+
+ @Override
+ public void add(int index, T element) {
+ this.trackReferenceAdded(element);
+
+ this.list.add(index, element);
+ }
+
+ @Override
+ public T remove(int index) {
+ T prev = this.list.remove(index);
+
+ if (prev != null) {
+ this.trackReferenceRemoved(prev);
+ }
+
+ return prev;
+ }
+
+ @Override
+ public int indexOf(Object o) {
+ return this.list.indexOf(o);
+ }
+
+ @Override
+ public int lastIndexOf(Object o) {
+ return this.list.lastIndexOf(o);
+ }
+
+ @Override
+ public @NotNull ListIterator<T> listIterator() {
+ return this.listIterator(0);
+ }
+
+ @Override
+ public @NotNull ListIterator<T> listIterator(int index) {
+ return new ListIterator<>() {
+ private final ListIterator<T> inner = HashedReferenceList.this.list.listIterator(index);
+
+ @Override
+ public boolean hasNext() {
+ return this.inner.hasNext();
+ }
+
+ @Override
+ public T next() {
+ return this.inner.next();
+ }
+
+ @Override
+ public boolean hasPrevious() {
+ return this.inner.hasPrevious();
+ }
+
+ @Override
+ public T previous() {
+ return this.inner.previous();
+ }
+
+ @Override
+ public int nextIndex() {
+ return this.inner.nextIndex();
+ }
+
+ @Override
+ public int previousIndex() {
+ return this.inner.previousIndex();
+ }
+
+ @Override
+ public void remove() {
+ int last = this.previousIndex();
+
+ if (last == -1) {
+ throw new NoSuchElementException();
+ }
+
+ T prev = HashedReferenceList.this.get(last);
+
+ if (prev != null) {
+ HashedReferenceList.this.trackReferenceRemoved(prev);
+ }
+
+ this.inner.remove();
+ }
+
+ @Override
+ public void set(T t) {
+ int last = this.previousIndex();
+
+ if (last == -1) {
+ throw new NoSuchElementException();
+ }
+
+ T prev = HashedReferenceList.this.get(last);
+
+ if (prev != t) {
+ if (prev != null) {
+ HashedReferenceList.this.trackReferenceRemoved(prev);
+ }
+
+ HashedReferenceList.this.trackReferenceAdded(t);
+ }
+
+ this.inner.remove();
+ }
+
+ @Override
+ public void add(T t) {
+ HashedReferenceList.this.trackReferenceAdded(t);
+
+ this.inner.add(t);
+ }
+ };
+ }
+
+ @Override
+ public @NotNull List<T> subList(int fromIndex, int toIndex) {
+ return this.list.subList(fromIndex, toIndex);
+ }
+
+ private void trackReferenceAdded(T t) {
+ this.counter.addTo(t, 1);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void trackReferenceRemoved(Object o) {
+ if (this.counter.addTo((T) o, -1) <= 1) {
+ this.counter.removeInt(o);
+ }
+ }
+
+}
diff --git a/src/main/java/net/minecraft/util/random/WeightedRandomList.java b/src/main/java/net/minecraft/util/random/WeightedRandomList.java
index ef44047c3ea850fe52370b8176efbdf0515d20d6..30efa8704c1ae94027272602687cbc4a2bc8a772 100644
--- a/src/main/java/net/minecraft/util/random/WeightedRandomList.java
+++ b/src/main/java/net/minecraft/util/random/WeightedRandomList.java
@@ -10,10 +10,10 @@ import net.minecraft.util.RandomSource;
public class WeightedRandomList<E extends WeightedEntry> {
private final int totalWeight;
- private final ImmutableList<E> items;
+ private final List<E> items; // Plazma - Lithium: collections.mob_spawning
WeightedRandomList(List<? extends E> entries) {
- this.items = ImmutableList.copyOf(entries);
+ this.items = entries.size() > 4 ? ImmutableList.copyOf(entries) : java.util.Collections.unmodifiableList(new me.jellysquid.mods.lithium.common.util.collections.HashedReferenceList<>(entries)); // Plazma - Lithium: collections.mob_spawning
this.totalWeight = WeightedRandom.getTotalWeight(entries);
}

View File

@@ -0,0 +1,18 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AlphaKR93 <dev@alpha93.kr>
Date: Wed, 10 Jan 2024 18:11:03 +0900
Subject: [PATCH] Improve SwingTime ticking
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index fa698cfefccdddf5e5e9938a2959004c70f743a7..b24754e36e210a635524be099cffe4553220a6a9 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -2654,6 +2654,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
protected void updateSwingTime() {
+ if (!this.swinging && this.swingTime == 0) return; // Plazma - Improve SwingTime ticking
int i = this.getCurrentSwingDuration();
if (this.swinging) {

View File

@@ -0,0 +1,152 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AlphaKR93 <dev@alpha93.kr>
Date: Thu, 11 Jan 2024 13:40:41 +0900
Subject: [PATCH] Save Json list asynchronously
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java b/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java
index 22c4f8dea99f92a1eb3da2baf0a15bf9d2ca0462..20c531f11b310dab0a867e589c769393ed835df5 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedPlayerList.java
@@ -58,21 +58,23 @@ public class DedicatedPlayerList extends PlayerList {
this.loadWhiteList();
}
+ // Plazma start - Save JSON list asynchronously
private void saveIpBanList() {
- try {
- this.getIpBans().save();
- } catch (IOException var2) {
- LOGGER.warn("Failed to save ip banlist: ", (Throwable)var2);
- }
+ this.getIpBans().save();
}
private void saveUserBanList() {
- try {
- this.getBans().save();
- } catch (IOException var2) {
- LOGGER.warn("Failed to save user banlist: ", (Throwable)var2);
- }
+ this.getBans().save();
+ }
+
+ private void saveOps() {
+ this.getOps().save();
+ }
+
+ private void saveWhiteList() {
+ this.getWhiteList().save();
}
+ // Plazma end - Save JSON list asynchronously
private void loadIpBanList() {
try {
@@ -98,14 +100,6 @@ public class DedicatedPlayerList extends PlayerList {
}
}
- private void saveOps() {
- try {
- this.getOps().save();
- } catch (Exception var2) {
- LOGGER.warn("Failed to save operators list: ", (Throwable)var2);
- }
- }
-
private void loadWhiteList() {
try {
this.getWhiteList().load();
@@ -114,14 +108,6 @@ public class DedicatedPlayerList extends PlayerList {
}
}
- private void saveWhiteList() {
- try {
- this.getWhiteList().save();
- } catch (Exception var2) {
- LOGGER.warn("Failed to save white-list: ", (Throwable)var2);
- }
- }
-
@Override
public boolean isWhiteListed(GameProfile profile) {
return !this.isUsingWhitelist() || this.isOp(profile) || this.getWhiteList().isWhiteListed(profile);
diff --git a/src/main/java/net/minecraft/server/players/StoredUserList.java b/src/main/java/net/minecraft/server/players/StoredUserList.java
index c038da20b76c0b7b1c18471b20be01e849d29f3a..0735a0bd182635e1969d19336b46bc72b14e555f 100644
--- a/src/main/java/net/minecraft/server/players/StoredUserList.java
+++ b/src/main/java/net/minecraft/server/players/StoredUserList.java
@@ -42,13 +42,7 @@ public abstract class StoredUserList<K, V extends StoredUserEntry<K>> {
public void add(V entry) {
this.map.put(this.getKeyForUser(entry.getUser()), entry);
-
- try {
- this.save();
- } catch (IOException ioexception) {
- StoredUserList.LOGGER.warn("Could not save the list after adding a user.", ioexception);
- }
-
+ this.save(); // Plazma - Save Json list asynchronously
}
@Nullable
@@ -62,13 +56,7 @@ public abstract class StoredUserList<K, V extends StoredUserEntry<K>> {
public void remove(K key) {
this.map.remove(this.getKeyForUser(key));
-
- try {
- this.save();
- } catch (IOException ioexception) {
- StoredUserList.LOGGER.warn("Could not save the list after removing a user.", ioexception);
- }
-
+ this.save(); // Plazma - Save Json list asynchronously
}
public void remove(StoredUserEntry<K> entry) {
@@ -102,7 +90,9 @@ public abstract class StoredUserList<K, V extends StoredUserEntry<K>> {
return this.map.values();
}
- public void save() throws IOException {
+ // Plazma start - Save Json list asynchronously
+ public void save()/* throws IOException*/ {
+ io.papermc.paper.util.MCUtil.scheduleAsyncTask(() -> {
this.removeExpired(); // Paper - remove expired values before saving
JsonArray jsonarray = new JsonArray();
Stream<JsonObject> stream = this.map.values().stream().map((jsonlistentry) -> { // CraftBukkit - decompile error
@@ -114,27 +104,16 @@ public abstract class StoredUserList<K, V extends StoredUserEntry<K>> {
Objects.requireNonNull(jsonarray);
stream.forEach(jsonarray::add);
- BufferedWriter bufferedwriter = Files.newWriter(this.file, StandardCharsets.UTF_8);
- try {
+ try (BufferedWriter bufferedwriter = Files.newWriter(this.file, StandardCharsets.UTF_8)) {
StoredUserList.GSON.toJson(jsonarray, StoredUserList.GSON.newJsonWriter(bufferedwriter));
- } catch (Throwable throwable) {
- if (bufferedwriter != null) {
- try {
- bufferedwriter.close();
- } catch (Throwable throwable1) {
- throwable.addSuppressed(throwable1);
- }
- }
-
- throw throwable;
- }
-
- if (bufferedwriter != null) {
- bufferedwriter.close();
+ } catch (IOException e) {
+ StoredUserList.LOGGER.warn("Failed to asynchronously save file " + this.file, e);
}
+ });
}
+ // Plazma end - Save Json list asynchronously
public void load() throws IOException {
if (this.file.exists()) {

View File

@@ -0,0 +1,164 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: AlphaKR93 <dev@alpha93.kr>
Date: Mon, 29 Apr 2024 14:49:37 +0900
Subject: [PATCH] Implement FreedomChat
ocelotpotpie/FreedomChat
Copyright (C) 2022-2024 ocelotpotpie, Licensed under GNU GPL v3.0
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 2707a96f9e22469d008ec7d2fa8a8c497efaf8cf..9eedd395b3eac5e2511c8267781938a3fd994d90 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -135,6 +135,7 @@ public abstract class PlayerList {
private static final Logger LOGGER = LogUtils.getLogger();
private static final int SEND_PLAYER_INFO_INTERVAL = 600;
private static final SimpleDateFormat BAN_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
+ private static final ru.bk.oharass.freedomchat.FreedomChat FREEDOM_HANDLER = new ru.bk.oharass.freedomchat.FreedomChat(); // Plazma - Implement FreedomChat
private final MinecraftServer server;
public final List<ServerPlayer> players = new java.util.concurrent.CopyOnWriteArrayList(); // CraftBukkit - ArrayList -> CopyOnWriteArrayList: Iterator safety
private final Map<UUID, ServerPlayer> playersByUUID = Maps.newHashMap();
@@ -285,6 +286,7 @@ public abstract class PlayerList {
// CraftBukkit - Moved message to after join
// PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ({}, {}, {})", new Object[]{entityplayer.getName().getString(), s1, entityplayer.getId(), entityplayer.getX(), entityplayer.getY(), entityplayer.getZ()});
LevelData worlddata = worldserver1.getLevelData();
+ connection.channel.pipeline().addAfter("packet_handler", "freedom_handler", FREEDOM_HANDLER); // Plazma - Implement FreedomChat
player.loadGameTypes((CompoundTag) optional.orElse(null)); // CraftBukkit - decompile error
ServerGamePacketListenerImpl playerconnection = new ServerGamePacketListenerImpl(this.server, connection, player, clientData);
diff --git a/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java b/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java
index 4f3ed01e12ccb8a6f1a5c4f605451bb36370a236..98f26e3de66a881163e84295e9156c7f362bf7cb 100644
--- a/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java
+++ b/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java
@@ -29,6 +29,16 @@ public class GlobalConfiguration extends ConfigurationPart {
public boolean checkSpectatorMovedToQuickly = !OPTIMIZE;
+ public FreedomChat freedomChat;
+ public class FreedomChat extends ConfigurationPart {
+
+ public boolean enabled = false;
+ public boolean rewriteChat = true;
+ public boolean claimSecureChatEnforced = true;
+ public boolean noChatReports = true;
+
+ }
+
}
@Setting("world-generation")
diff --git a/src/main/java/ru/bk/oharass/freedomchat/FreedomChat.java b/src/main/java/ru/bk/oharass/freedomchat/FreedomChat.java
new file mode 100644
index 0000000000000000000000000000000000000000..67f21c23e80881f52e7b92f22c6cbbe3a0bd55b5
--- /dev/null
+++ b/src/main/java/ru/bk/oharass/freedomchat/FreedomChat.java
@@ -0,0 +1,96 @@
+package ru.bk.oharass.freedomchat;
+
+import com.google.gson.JsonObject;
+import com.mojang.logging.LogUtils;
+import com.mojang.serialization.JsonOps;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.EncoderException;
+import io.netty.handler.codec.MessageToByteEncoder;
+import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
+import net.minecraft.network.Connection;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.chat.ChatType;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.protocol.Packet;
+import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket;
+import net.minecraft.network.protocol.game.ClientboundServerDataPacket;
+import net.minecraft.network.protocol.game.ClientboundSystemChatPacket;
+import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket;
+import net.minecraft.network.protocol.status.ServerStatus;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+
+import static org.plazmamc.plazma.configurations.GlobalConfiguration.get;
+import static net.minecraft.server.MinecraftServer.getServer;
+
+@ChannelHandler.Sharable
+public class FreedomChat extends MessageToByteEncoder<Packet<?>> {
+
+ private static final Logger LOGGER = LogUtils.getLogger();
+
+ @Override
+ public boolean acceptOutboundMessage(final Object msg) {
+ return get().player.freedomChat.rewriteChat && msg instanceof ClientboundPlayerChatPacket
+ || get().player.freedomChat.claimSecureChatEnforced && msg instanceof ClientboundServerDataPacket
+ || get().player.freedomChat.noChatReports && msg instanceof ClientboundStatusResponsePacket;
+ }
+
+ @Override
+ protected void encode(final ChannelHandlerContext context, final Packet<?> packet, final ByteBuf byteBuf) throws Exception {
+ final FriendlyByteBuf buf = new FriendlyByteBuf(byteBuf);
+
+ // TODO: JDK 21 - Change to pattern matching
+ if (packet instanceof ClientboundPlayerChatPacket chat)
+ encodeChat(context, chat, buf);
+ else if (packet instanceof ClientboundServerDataPacket data)
+ encodeData(context, data, buf);
+ else if (packet instanceof ClientboundStatusResponsePacket query)
+ encodeQuery(context, query, buf);
+ }
+
+ private static void encodeChat(
+ final ChannelHandlerContext context, final ClientboundPlayerChatPacket packet, final FriendlyByteBuf byteBuf
+ ) {
+ final Optional<ChatType.Bound> bound = packet.chatType().resolve(getServer().registryAccess());
+ if (bound.isEmpty()) {
+ LOGGER.warn("Failed to resolve chat type: {}", packet.chatType().chatType(), new Throwable());
+ return;
+ }
+
+ final ClientboundSystemChatPacket after = new ClientboundSystemChatPacket( bound.orElseThrow().decorate(
+ Optional.ofNullable( packet.unsignedContent() ).orElse( Component.literal(packet.body().content()) )
+ ), false );
+ write(context, after, byteBuf);
+ after.write(byteBuf);
+ }
+
+ private static void encodeData(
+ final ChannelHandlerContext context, final ClientboundServerDataPacket packet, final FriendlyByteBuf byteBuf
+ ) {
+ write(context, packet, byteBuf);
+ byteBuf.writeComponent(packet.getMotd());
+ byteBuf.writeOptional(packet.getIconBytes(), FriendlyByteBuf::writeByteArray);
+ byteBuf.writeBoolean(true);
+ }
+
+ private static void encodeQuery(
+ final ChannelHandlerContext context, final ClientboundStatusResponsePacket packet, final FriendlyByteBuf byteBuf
+ ) {
+ final JsonObject status = ServerStatus.CODEC.encodeStart(JsonOps.INSTANCE, packet.status()).get().left()
+ .orElseThrow(() -> new EncoderException("Failed to encode server status query response")).getAsJsonObject();
+
+ status.addProperty("preventsChatReports", true);
+ write(context, packet, byteBuf);
+ byteBuf.writeUtf(GsonComponentSerializer.gson().serializer().toJson(status));
+ }
+
+ private static void write(
+ final ChannelHandlerContext context, final Packet<?> packet, final FriendlyByteBuf byteBuf
+ ) {
+ byteBuf.writeVarInt(context.channel().attr(Connection.ATTRIBUTE_CLIENTBOUND_PROTOCOL).get().packetId(packet));
+ }
+
+}