Patterns

"Where Does X Live?" Cheat Sheet

The shortest distance from "I want to change this" to "this is the file I open".

I want to...                        Look in...
────────────────────────────────    ──────────────────────────────
add a new item                      dist/data/stats/items/*.xml
                                    + optional handler in
                                      handler/itemhandlers/

add a new skill effect              data/EnchantSkill*, SkillData
                                    + new EffectHandler entry

add a quest                         dist/data/scripts/quests/
                                    + register in QuestMasterHandler.java

change rates / drops                dist/game/config/Rates.ini

change spawn locations              dist/data/spawns/*.xml

touch packet structure              gameserver/network/clientpackets
                                    gameserver/network/serverpackets
                                    ClientPackets / ServerPackets tables

add admin command                   dist/data/scripts/handlers/
                                      chat/commands/admin/
                                    + dist/game/config/AdminCommands.xml

tweak siege / castle                managers/Castle*Manager,
                                    config/Siege.ini

alter login flow                    java/.../loginserver/

schema change                       dist/db_installer/*.sql
                                    + matching data/sql/*Table.java

chronicle-specific quirk            ONLY inside that chronicle's
                                    folder ─ never assume code is
                                    shared with another era.

Common edit recipes

"I want to make my character an administrator"

  1. Create a character in-game and log out.
  2. Find your character's row in the characters SQL table.
  3. Set the accesslevel field to 100.
  4. Log back in. Admin commands (//) are now available.

"I want to add an admin command"

  1. Create a class under dist/data/scripts/handlers/chat/commands/admin/ implementing IAdminCommandHandler. Admin commands are scripts, compiled at boot by the in-process JDK compiler, they do not live in the core jar.
  2. Declare which commands it handles in its getCommandList() return.
  3. Register it in dist/data/scripts/handlers/MasterHandler.java: add the import (import handlers.chat.commands.admin.MyAdmin;) and add MyAdmin.class, to the admin command handler array. Without this, the class is compiled but never registered.
  4. Add an entry in dist/game/config/AdminCommands.xml specifying the minimum access level (and optionally confirmDlg="true" for destructive actions).
  5. Restart or //reload handler to re-run MasterHandler and pick up the new script, then run it in-game with //yourcommand.

"I want to change a config value at runtime"

You usually cannot, most config is read once at boot into typed fields. A handful of values (//reload config targets) support hot reload; the rest need a restart.

"I want to add a new item that does X"

  1. Define the item in dist/data/stats/items/*.xml. Pick a free ID, set name, type, weight, stats.
  2. If "X" is more than a stat change, add a handler in handler/itemhandlers/ implementing IItemHandler.
  3. Reference the handler by name in the XML (handler="MyNewItem").
  4. Restart the server. The item appears in the world; admin-spawn it to test.

"I want to change spawn locations"

  1. Find the right XML under dist/data/spawns/ (organized by region / boss / instance).
  2. Edit coords / respawn delay / amount.
  3. Restart. Some spawn groups can be reloaded via admin commands, check //list_spawngroup.

"I want to add a new quest"

  1. Create a new directory under dist/data/scripts/quests/Qxxxxx_QuestName/.
  2. Write the quest class extending Quest with onTalk, onKill, etc.
  3. Restart. The quest compiles on boot and the NPC starts offering it.

"I want to touch packet structure"

Three things need to stay in sync:

  1. The opcode in ClientPackets.java / ServerPackets.java / ExClientPackets.java.
  2. The packet class in clientpackets/ or serverpackets/ (the read / write implementation).
  3. Every caller of that packet, since the constructor signature usually changes.

If the client and server disagree even by one byte, the connection drops. Test against the actual chronicle's client version.

Chronicle hopping

Code is not shared across chronicle folders. If you fix a bug in L2J_Mobius_GD_3.0_Lindvior/ the same bug may exist (or may not, or may be already fixed) in L2J_Mobius_GD_1.0_Awakening/. Treat every port as a fresh review:

  • The file path may match exactly, but the surrounding code may differ.
  • Method signatures, class hierarchies and packet structures shift between chronicles.
  • An XML field that existed in one chronicle may have been renamed or replaced in the next.

Diff before you copy. Compile after you paste. Test in-game.