BettyBoop
New member
LEVEL 5
40 XP
Hey everyone,
This time, I’ve post a Multibox Limiter that works based on player IP and ensures a fair gameplay environment, especially for PvP and economy stability.
This system limits the number of characters (boxes) a player can have open from the same IP address. Here are the key features:
Configurable Limit:
The allowed number of boxes is set in players.properties via AllowedBoxes (default is 99, but you can easily change it).
Smart Detection:
The system scans all active players and counts how many characters are logged in with the same IP.
Live Syncing Across Boxes:
It keeps track of all active box character names per IP and syncs that info across all boxes, so players can see which of their characters are currently active.
Auto-Update:
When a player logs out, the box count is automatically decreased and updated for the other boxes using the same IP.
Multiboxing can cause balance issues on many servers. This system helps maintain fairness, prevents abuse, and still allows flexibility for players with a reasonable limit. It’s especially useful for managing farm zones, events, or competitive areas.
P.S. For some, it may be useful. For others... it may be completely useless. I just leave it here in case someone finds it helpful. If not, no worries.
This time, I’ve post a Multibox Limiter that works based on player IP and ensures a fair gameplay environment, especially for PvP and economy stability.
What It Does:
This system limits the number of characters (boxes) a player can have open from the same IP address. Here are the key features:
The allowed number of boxes is set in players.properties via AllowedBoxes (default is 99, but you can easily change it).

The system scans all active players and counts how many characters are logged in with the same IP.
- If the number exceeds the allowed box count, the new login will be kicked with a warning message.
- GMs are excluded from this check and can multibox freely.

It keeps track of all active box character names per IP and syncs that info across all boxes, so players can see which of their characters are currently active.

When a player logs out, the box count is automatically decreased and updated for the other boxes using the same IP.
Why Use It?
Multiboxing can cause balance issues on many servers. This system helps maintain fairness, prevents abuse, and still allows flexibility for players with a reasonable limit. It’s especially useful for managing farm zones, events, or competitive areas.
Java:
diff --git a/aCis_gameserver/config/players.properties b/aCis_gameserver/config/players.properties
index c645204fe81e6eecd45227f2c741c7876c80b5ff..4714211bb7a75a6885e286c98fcb47771ed496d1 100644
--- a/aCis_gameserver/config/players.properties
+++ b/aCis_gameserver/config/players.properties
@@ -257,4 +257,12 @@ SubClassWithoutQuests = False
MaxBuffsAmount = 20
# Store buffs/debuffs on user logout. Default: True
-StoreSkillCooltime = True
\ No newline at end of file
+StoreSkillCooltime = True
+
+#=============================================================
+# Allowed Boxes Config
+#=============================================================
+
+#Default AllowedBoxes = 99
+# Max number of boxes per IP
+AllowedBoxes = 99
\ No newline at end of file
diff --git a/aCis_gameserver/java/net/sf/l2j/Config.java b/aCis_gameserver/java/net/sf/l2j/Config.java
index 9f5c32305e43c78c0760e014c5954fe42d088200..1ffc1d4a3200b44e7ead248f79d4e3f6cb674a40 100644
--- a/aCis_gameserver/java/net/sf/l2j/Config.java
+++ b/aCis_gameserver/java/net/sf/l2j/Config.java
@@ -349,6 +349,9 @@ public final class Config
// Players
// --------------------------------------------------
+ /** Allowed Boxes */
+ public static int ALLOWED_BOXES;
+
/** Misc */
public static boolean EFFECT_CANCELING;
public static double HP_REGEN_MULTIPLIER;
@@ -1109,6 +1112,8 @@ public final class Config
MAX_BUFFS_AMOUNT = players.getProperty("MaxBuffsAmount", 20);
STORE_SKILL_COOLTIME = players.getProperty("StoreSkillCooltime", true);
+ ALLOWED_BOXES = players.getProperty("AllowedBoxes", 99);
+
}
/**
diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Player.java b/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Player.java
index f1491313b2102b39c9c121afc03cd5d676edd3dd..e6828650e46e96a534ed2722bef61e91cab19396 100644
--- a/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Player.java
+++ b/aCis_gameserver/java/net/sf/l2j/gameserver/model/actor/Player.java
@@ -263,6 +263,8 @@ public final class Player extends Playable
private static final Comparator<GeneralSkillNode> COMPARE_SKILLS_BY_LVL = Comparator.comparing(GeneralSkillNode::getValue);
private GameClient _client;
+ public int _activeBoxes = -1;
+ public List<String> _activeBoxCharacters = new ArrayList<>();
private final Map<Integer, String> _chars = new HashMap<>();
private final String _accountName;
@@ -5628,6 +5630,84 @@ public final class Player extends Playable
{
_isInOlympiadMode = b;
}
+
+ /**
+ * Check if local player can make multibox and also refresh local boxes instances number.
+ * @return true, if successful
+ */
+ public boolean canMultiBox()
+ {
+ if (isGM())
+ return true;
+
+ boolean canMultiBox = true;
+ int boxCount = 1;
+ final List<String> activeBoxes = new ArrayList<>();
+ if ((_client != null) && (getIPAddress() != null) && !_client.isDetached())
+ {
+ final String playerIP = getIPAddress();
+ for (Player player : World.getInstance().getPlayers())
+ {
+ if ((player != null) && (player != this) && player.isOnline() && (player.getClient() != null) && (player.getIPAddress() != null) && !player.getClient().isDetached() && playerIP.equals(player.getIPAddress()))
+ {
+ // Ignore GMs when counting boxes
+ if (player.isGM())
+ continue;
+
+ boxCount++;
+ activeBoxes.add(player.getName());
+
+ if (boxCount > Config.ALLOWED_BOXES)
+ {
+ canMultiBox = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (canMultiBox)
+ {
+ _activeBoxes = boxCount;
+ if (!activeBoxes.contains(getName()))
+ {
+ activeBoxes.add(getName());
+ _activeBoxCharacters = activeBoxes;
+ }
+ refreshOtherBoxes();
+ }
+
+ return canMultiBox;
+ }
+
+ /**
+ * Increase active boxes number for local player and other boxer for same IP.
+ */
+ public void refreshOtherBoxes()
+ {
+ if ((_client != null) && (getIPAddress() != null) && !_client.isDetached())
+ {
+ final String playerIP = getIPAddress();
+ for (Player player : World.getInstance().getPlayers())
+ {
+ if ((player != null) && (player != this) && player.isOnline() && (player.getClient() != null) && (player.getIPAddress() != null) && !player.getClient().isDetached() && !player.getName().equals(getName()) && playerIP.equals(player.getIPAddress()))
+ {
+ player._activeBoxes = _activeBoxes;
+ player._activeBoxCharacters = _activeBoxCharacters;
+ }
+ }
+ }
+ }
+
+ /**
+ * Decrease active boxes number for local player and other boxer for same IP.
+ */
+ public void decreaseBoxes()
+ {
+ _activeBoxes = _activeBoxes - 1;
+ _activeBoxCharacters.remove(getName());
+ refreshOtherBoxes();
+ }
public boolean isInDuel()
{
@@ -7414,6 +7494,17 @@ public final class Player extends Playable
return gms;
}
+ public String getIPAddress()
+ {
+ try
+ {
+ return getClient().getConnection().getInetAddress().getHostAddress().intern();
+ }
+ catch(final Exception e)
+ {
+ return null;
+ }
+ }
public boolean isClanMemberWithClanHallorCastle()
{
diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java b/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java
index 6226e61ba95a91859cb2ad87e1c456b2e61b7ca3..bcf553d7b3a425e3012ce5c053584f7d74efd938 100644
--- a/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java
+++ b/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java
@@ -104,6 +104,14 @@ public class EnterWorld extends L2GameClientPacket
player.sendPacket(new HennaInfo(player));
player.updateEffectIcons();
player.sendPacket(new EtcStatusUpdate(player));
+
+ // Means that it's not ok multiBox situation, so logout.
+ if (!player.canMultiBox())
+ {
+ player.sendMessage("I'm sorry, but you have reached the total number of boxes.");
+ player.logout(true);
+ return;
+ }
// Clan checks.
final Clan clan = player.getClan();
P.S. For some, it may be useful. For others... it may be completely useless. I just leave it here in case someone finds it helpful. If not, no worries.
Last edited by a moderator: