Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0c59615
feat: implement command forwarding from backend to proxy for /freesia…
NguyenDevs Apr 17, 2026
204d00f
feat: implement remote command forwarding and real-time NPC skin upda…
NguyenDevs Apr 17, 2026
f161d70
Update ServerLoginPacketListenerImplMixin.java
NguyenDevs Apr 17, 2026
7283ccb
Update MinecraftServerMixin.java
NguyenDevs Apr 17, 2026
3b28809
Update ServerGamePacketListenerImplMixin.java
NguyenDevs Apr 17, 2026
7ad8f43
Update ConnectionMixin.java
NguyenDevs Apr 17, 2026
d87bd5a
Update YsmPacketProxy.java
NguyenDevs Apr 17, 2026
7b3fe70
Update VirtualPlayerManager.java
NguyenDevs Apr 17, 2026
72e1fa6
Update FreesiaPlayerTracker.java
NguyenDevs Apr 17, 2026
e3c39f4
Update Freesia.java
NguyenDevs Apr 17, 2026
6adeacc
Final NPC backend optimization: multi-server persistence, context ext…
NguyenDevs Apr 17, 2026
d555593
Fix: backend proxy command forwarding logic and security
NguyenDevs Apr 17, 2026
612756c
Fix: command payload encoding compatibility between backend and proxy
NguyenDevs Apr 17, 2026
a2270dd
Fix: command payload compatibility and missing imports
NguyenDevs Apr 17, 2026
c66c591
Fix: implement missing reload command in proxy plugins
NguyenDevs Apr 17, 2026
d79d6e4
Fix: correct syntax in Waterfall FreesiaCommand
NguyenDevs Apr 17, 2026
084050b
Feature: dynamic setskin visibility based on NPC module detection
NguyenDevs Apr 17, 2026
2ea4407
Refactor: externalize hardcoded messages to i18n language files
NguyenDevs Apr 17, 2026
c3c4432
Add prefix
NguyenDevs Apr 17, 2026
9d0aaf3
Update FreesiaNPCPlugin.java
NguyenDevs Apr 17, 2026
56a7694
Update build.gradle.kts
NguyenDevs Apr 17, 2026
d593b60
Delete Citizens-2.0.41-b4138.jar
NguyenDevs Apr 17, 2026
a5c74cd
Delete CommandMessageReceiver.java
NguyenDevs Apr 17, 2026
5f8c765
Delete CommandMessageReceiver.java
NguyenDevs Apr 17, 2026
d88b627
Update Freesia.java
NguyenDevs Apr 17, 2026
64e88fe
Update Freesia.java
NguyenDevs Apr 17, 2026
fb1c76d
Delete FreesiaCommandExecutor.java
NguyenDevs Apr 17, 2026
f83b70a
Update FreesiaBackend.java
NguyenDevs Apr 17, 2026
cba1f6e
Update plugin.yml
NguyenDevs Apr 17, 2026
ca8783e
Update FreesiaCommand.java
NguyenDevs Apr 17, 2026
a783b50
Update FreesiaCommand.java
NguyenDevs Apr 17, 2026
03f42be
Fix prefix
NguyenDevs Apr 17, 2026
709b643
Refactor: Rename Freesia-NPC module to Freesia-Citizens and update pa…
NguyenDevs Apr 17, 2026
489fe55
Refactor(Waterfall): Update proxy logic for Citizens module and renam…
NguyenDevs Apr 17, 2026
e7c8955
Refactor(Velocity): Update proxy logic for Citizens module and rename…
NguyenDevs Apr 17, 2026
116be95
Remove Freesia NPC
NguyenDevs Apr 17, 2026
1a35a35
Fix: Update i18n placeholder keys to match Citizens naming in lang files
NguyenDevs Apr 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file removed Citizens-2.0.41-b4138.jar
Binary file not shown.
3 changes: 0 additions & 3 deletions Freesia-Backend/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ repositories {
dependencies {
compileOnly("io.papermc.paper:paper-api:1.21.1-R0.1-SNAPSHOT")
compileOnly("io.netty:netty-all:4.1.118.Final")
compileOnly("net.citizensnpcs:citizens-main:2.0.41-SNAPSHOT") {
exclude(group = "*", module = "*")
}
}

tasks.build {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ public void onEnable() {
Bukkit.getMessenger().registerIncomingPluginChannel(this, VirtualPlayerManager.CHANNEL_NAME, this.virtualPlayerManager);
Bukkit.getMessenger().registerOutgoingPluginChannel(this, VirtualPlayerManager.CHANNEL_NAME);


Bukkit.getPluginManager().registerEvents(this.trackerProcessor, this);
Bukkit.getConsoleSender().sendMessage(ChatColor.translateAlternateColorCodes('&',
"&5[&dFreesia&5] &aFreesia Backend plugin enabled successfully!"));

Bukkit.getConsoleSender().sendMessage(ChatColor.translateAlternateColorCodes('&',
"&5[&dFreesia-Backend&5] &aFreesia Backend plugin enabled successfully!"));
}

public VirtualPlayerManager getVirtualPlayerManager() {
Expand All @@ -38,6 +37,6 @@ public VirtualPlayerManager getVirtualPlayerManager() {
@Override
public void onDisable() {
Bukkit.getConsoleSender().sendMessage(ChatColor.translateAlternateColorCodes('&',
"&5[&dFreesia&5] &cFreesia Backend plugin disabled!"));
"&5[&dFreesia-Backend&5] &cFreesia Backend plugin disabled!"));
}
}
1 change: 0 additions & 1 deletion Freesia-Backend/src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ version: '1.0.3-YSM-2.6.4'
main: com.nguyendevs.freesia.backend.FreesiaBackend
api-version: '1.16'
folia-supported: true
softdepend: [Citizens]
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ java {

tasks.shadowJar {
archiveClassifier.set("")
archiveFileName.set("Freesia-NPC-${project.version}.jar")
archiveFileName.set("Freesia-Citizens-${project.version}.jar")
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package com.nguyendevs.freesia.npc;
package com.nguyendevs.freesia.citizens;

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;

public class FreesiaNPCPlugin extends JavaPlugin {
public class FreesiaCitizensPlugin extends JavaPlugin {

public static final String CHANNEL_NAME = "freesia:npc";
public static FreesiaNPCPlugin INSTANCE;
public static FreesiaCitizensPlugin INSTANCE;

@Override
public void onEnable() {
Expand All @@ -19,14 +19,17 @@ public void onEnable() {

getServer().getPluginManager().registerEvents(new TrackerListener(), this);
Bukkit.getConsoleSender().sendMessage(ChatColor.translateAlternateColorCodes('&',
"&5[&dFreesia-NPC&5] &a Enabled successfully. Hooked Citizens for proxy model injection!"));
"&6[&eFreesia-Citizens&6] &aFreesia Citizens plugin enabled successfully."));
Bukkit.getConsoleSender().sendMessage(ChatColor.translateAlternateColorCodes('&',
"&6[&eFreesia-Citizens&6] &aHooked Citizens for proxy model injection!"));
}

@Override
public void onDisable() {
Bukkit.getMessenger().unregisterIncomingPluginChannel(this, CHANNEL_NAME);
Bukkit.getMessenger().unregisterOutgoingPluginChannel(this, CHANNEL_NAME);
getLogger().info(ChatColor.RED + "[Freesia-NPC] Disabled!");
Bukkit.getConsoleSender().sendMessage(ChatColor.translateAlternateColorCodes('&',
"&6[&eFreesia-Citizens&6] &aFreesia Citizens plugin disabled!"));
}

public void sendProxyPayload(Player player, byte[] payload) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.nguyendevs.freesia.citizens;

import io.papermc.paper.event.player.PlayerTrackEntityEvent;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.npc.NPC;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.jetbrains.annotations.NotNull;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.util.Collection;

public class TrackerListener implements Listener, PluginMessageListener {

private static final byte OP_TRACK_SYNC = 0;
private static final byte OP_REQ_LIST = 1;
private static final byte OP_RES_LIST = 2;
private static final byte OP_UNTRACK_SYNC = 3;

@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
sendNpcList(event.getPlayer());
}

@EventHandler
public void onUntrackEntity(io.papermc.paper.event.player.PlayerUntrackEntityEvent event) {
final Entity beingWatched = event.getEntity();
final Player watcher = event.getPlayer();

if (beingWatched.hasMetadata("NPC")) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(beingWatched);
if (npc != null) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(OP_UNTRACK_SYNC);
dos.writeLong(watcher.getUniqueId().getMostSignificantBits());
dos.writeLong(watcher.getUniqueId().getLeastSignificantBits());
dos.writeInt(npc.getId());
dos.flush();

FreesiaCitizensPlugin.INSTANCE.sendProxyPayload(watcher, bos.toByteArray());
} catch (Exception e) {
FreesiaCitizensPlugin.INSTANCE.getLogger().warning("Failed to send untrack sync: " + e.getMessage());
}
}
}
}

@EventHandler
public void onTrackEntity(PlayerTrackEntityEvent event) {
final Entity beingWatched = event.getEntity();
final Player watcher = event.getPlayer();

if (beingWatched.hasMetadata("NPC")) {
NPC npc = CitizensAPI.getNPCRegistry().getNPC(beingWatched);
if (npc != null) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(OP_TRACK_SYNC);
dos.writeLong(watcher.getUniqueId().getMostSignificantBits());
dos.writeLong(watcher.getUniqueId().getLeastSignificantBits());
dos.writeInt(npc.getId());
dos.writeInt(beingWatched.getEntityId());
dos.flush();

FreesiaCitizensPlugin.INSTANCE.sendProxyPayload(watcher, bos.toByteArray());
} catch (Exception e) {
FreesiaCitizensPlugin.INSTANCE.getLogger().warning("Failed to send track sync: " + e.getMessage());
}
}
}
}

@Override
public void onPluginMessageReceived(@NotNull String channel, @NotNull Player player, byte[] message) {
if (!channel.equals(FreesiaCitizensPlugin.CHANNEL_NAME)) return;

try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(message))) {
byte opcode = in.readByte();
if (opcode == OP_REQ_LIST) {
sendNpcList(player);
}
} catch (Exception e) {
FreesiaCitizensPlugin.INSTANCE.getLogger().warning("Failed to parse plugin messaging: " + e.getMessage());
}
}

private void sendNpcList(Player player) {
try {
Collection<NPC> npcs = (Collection<NPC>) CitizensAPI.getNPCRegistry().sorted();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeByte(OP_RES_LIST);
dos.writeInt(npcs.size());
for (NPC npc : npcs) {
dos.writeInt(npc.getId());
dos.writeUTF(npc.getName());
}
dos.flush();
FreesiaCitizensPlugin.INSTANCE.sendProxyPayload(player, bos.toByteArray());
} catch (Exception e) {
FreesiaCitizensPlugin.INSTANCE.getLogger().warning("Failed to send NPC list: " + e.getMessage());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Freesia-NPC
name: Freesia-Citizens
version: 1.0.0
main: com.nguyendevs.freesia.npc.FreesiaNPCPlugin
main: com.nguyendevs.freesia.citizens.FreesiaCitizensPlugin
api-version: '1.20'
depend: [Citizens]
description: Freesia expansion for mapping Citizens NPCs to YesSteveModel environments via Velocity/Waterfall arrays.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.nguyendevs.freesia.common.communicating.message.w2m.W2MPlayerDataGetRequestMessage;
import com.nguyendevs.freesia.common.communicating.message.w2m.W2MUpdatePlayerDataRequestMessage;
import com.nguyendevs.freesia.common.communicating.message.w2m.W2MWorkerInfoMessage;
import com.nguyendevs.freesia.common.communicating.message.w2m.W2MDispatchCommandRequestMessage;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
Expand All @@ -25,6 +26,7 @@ public class BuiltinMessageRegitres {
registerMessage(W2MCommandResultMessage.class, W2MCommandResultMessage::new);
registerMessage(M2WDispatchCommandMessage.class, M2WDispatchCommandMessage::new);
registerMessage(W2MWorkerInfoMessage.class, W2MWorkerInfoMessage::new);
registerMessage(W2MDispatchCommandRequestMessage.class, W2MDispatchCommandRequestMessage::new);
}

public static void registerMessage(Class<? extends IMessage<?>> clazz, Supplier<IMessage<?>> creator) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,7 @@ public void sendMessage(IMessage<NettyClientChannelHandlerLayer> packet) {
public abstract void onCommandDispatchResult(int traceId, @Nullable String result);

public abstract void updateWorkerInfo(UUID workerUUID, String workerName);

public abstract void onCommandFromWorker(String command);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.nguyendevs.freesia.common.communicating.message.w2m;

import io.netty.buffer.ByteBuf;
import com.nguyendevs.freesia.common.communicating.handler.NettyServerChannelHandlerLayer;
import com.nguyendevs.freesia.common.communicating.message.IMessage;
import org.jetbrains.annotations.NotNull;

import java.nio.charset.StandardCharsets;

public class W2MDispatchCommandRequestMessage implements IMessage<NettyServerChannelHandlerLayer> {
private String command;

public W2MDispatchCommandRequestMessage() {
}

public W2MDispatchCommandRequestMessage(String command) {
this.command = command;
}

@Override
public void writeMessageData(@NotNull ByteBuf buffer) {
buffer.writeCharSequence(this.command, StandardCharsets.UTF_8);
}

@Override
public void readMessageData(@NotNull ByteBuf buffer) {
this.command = buffer.readCharSequence(buffer.readableBytes(), StandardCharsets.UTF_8).toString();
}

@Override
public void process(@NotNull NettyServerChannelHandlerLayer handler) {
handler.onCommandFromWorker(this.command);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public class Freesia implements PacketListener {
public static YsmClientKickingDetector kickChecker;
public static YsmMapperPayloadManager mapperManager;
public static NettySocketServer masterServer;
public static com.nguyendevs.freesia.velocity.network.misc.NpcMessageReceiver npcMessageReceiver;
public static com.nguyendevs.freesia.velocity.network.misc.CitizensMessageReceiver citizensMessageReceiver;

@Inject
private Logger logger;
Expand Down Expand Up @@ -92,7 +92,7 @@ public void onProxyStart(ProxyInitializeEvent event) {
LOGGER = this.logger;
PROXY_SERVER = this.proxyServer;

EntryPoint.initLogger(this.logger); // Common module
EntryPoint.initLogger(this.logger);

printLogo();

Expand All @@ -115,8 +115,8 @@ public void onProxyStart(ProxyInitializeEvent event) {

virtualPlayerManager.init();

npcMessageReceiver = new com.nguyendevs.freesia.velocity.network.misc.NpcMessageReceiver();
this.proxyServer.getEventManager().register(this, npcMessageReceiver);
citizensMessageReceiver = new com.nguyendevs.freesia.velocity.network.misc.CitizensMessageReceiver();
this.proxyServer.getEventManager().register(this, citizensMessageReceiver);

io.netty.handler.ssl.SslContext sslContext = null;
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ public static final class FileConstants {
public static final class PermissionConstants {
public static final String LIST_PLAYER_COMMAND = "freesia.commands.listysmplayers",
DISPATCH_WORKER_COMMAND = "freesia.commands.dworkerc",
SET_SKIN_COMMAND = "freesia.commands.setskin";
SET_SKIN_COMMAND = "freesia.commands.setskin",
RELOAD_COMMAND = "freesia.commands.reload";
}

public static final class LanguageConstants {
Expand All @@ -40,7 +41,18 @@ public static final class LanguageConstants {

HANDSHAKE_TIMED_OUT = "freesia.mod_handshake_time_outed",
WORKER_TERMINATED_CONNECTION = "freesia.backend.disconnected",
WORKER_NOT_CONNECTED = "freesia.backend.not_connected";
WORKER_NOT_CONNECTED = "freesia.backend.not_connected",

COMMAND_NO_PERMISSION = "freesia.command.no_permission",
COMMAND_PROVIDE_SERVER_NAME = "freesia.command.provide_server_name",
COMMAND_RELOAD_SUCCESS = "freesia.command.reload_success",
COMMAND_RELOAD_FAIL = "freesia.command.reload_fail",
COMMAND_CITIZENS_ID_INTEGER = "freesia.command.citizens_id_integer",
COMMAND_USAGE_HEADER = "freesia.command.usage.header",
COMMAND_USAGE_LISTPLAYERS = "freesia.command.usage.listplayers",
COMMAND_USAGE_DWORKERC = "freesia.command.usage.dworkerc",
COMMAND_USAGE_SETSKIN = "freesia.command.usage.setskin",
COMMAND_USAGE_RELOAD = "freesia.command.usage.reload";

}

Expand Down
Loading
Loading