-
Notifications
You must be signed in to change notification settings - Fork 84
Pokenet Specification
#summary Specification and guideline for PokeNet developers.
#labels Phase-Design
= Introduction =
This specification provides a development guide for developers of Pokenet.
= Coding Style =
== Comments ==
For large amounts of code (simple or complex), there must be comments explaining what is being done in the code.
== Javadoc ==
For all methods, classes and constructors, a javadoc comment must be placed above them to describe their purpose, e.g.
{{{
/**
- Default constructor
*/
public Game() {}
}}}
== Parameters ==
For methods with more than 2 parameters, there must be a line for each parameter, e.g.
{{{
public void startGame(
Game g,
String s,
int i) {
}
}}}
== Fields ==
All fields must named with an {{{’m_’}}}, e.g.
{{{
private String m_name;
private int m_index;
}}}
== Class Structure ==
Classes must be placed appropriately under their specified package:
{{{
org.pokenet.server.backend
org.pokenet.server.network
org.pokenet.server.feature
org.pokenet.server.visual
org.pokenet.server.battle
org.pokenet.client.backend
org.pokenet.client.network
org.pokenet.client.feature
org.pokenet.client.visual
}}}
== Threaded Objects ==
Objects that are threaded must implement Runnable and be structured with:
{{{
private Thread m_thread;
public void start()
public void stop()
public void run()
}}}
Example:
{{{
public ThreadedObject implements Runnable {
private Thread m_thread;
}}}
== Services ==
The server (and some parts of the client) implements services. These services consist of (usually) many threads. Some services consist of more than one of the same type of thread (e.g. ChatManager) to allow for faster processing of information (and so that the only lag is caused by the network, assuming the server has enough computing power). Hence, we call a method such as getChatManager(), it’ll return the ChatManager with the smallest processing load.
== Quests ==
Quests are implemented as a series of scripts stored in a quest-specific folder (e.g. /quests/001/1.py). Each player, when on a quest, stores a questID, lastQuestNpc (the id of the last quest NPC talked to) and a questItem (an item used for the quest, if needed). When they talk to a questNPC, a script is run for that player only, nobody else if affected by the script.
= Implementation =
== Game Client ==
== Game Server ==
The game server implements a threaded model whereby a thread is dedicated to each major task on the server:
- Logging In
- Logging Out
- Receiving data from client
- Chat
- Movement
- Battle
The server starts by starting each thread. Once all the threads have started, the server waits for a packet from the client. Upon receiving a packet, the server will do one of the following:
- If it is a login packet, it will queue the player to be logged in via the login thread
- If it is a movement packet, it will queue the movement for the next loop of the movement thread
- If it is a chat packet, it will queue the message for the next loop of the chat thread
- if it is a logout packet, it will queue the player to be logged out via the logout thread
- If it is a battle packet, it will be queue the action via the battle thread
- All other packets are executed immediately
It possible to have more than one thread for chat, battle and movement, providing that it is ensured a reference to a player can only exist once between all the threads.
= ServiceManager.java =
Fields:
{{{
private NetworkService m_networkService;
private BattleService [] m_battleService;
private MovementService m_movementService;
private TimeService m_timeService;
}}}
Methods:
getBattleService()
Returns the battle service with the smallest processing load
getMovementService()
Returns m_movementService
getNetworkService()
Returns m_networkService
getTimeService()
Returns m_timeService
start()
Starts all services (individual threads)
stop()
Stops all services (threads)
== Feature ==
The objective of the feature section is to provide frontend objects such as time, weather, npcs, etc. Time is implemented so that 1 hour (in-game) = 15 minutes.
= JythonService.java =
Fields:
{{{
private static JythonService m_instance = null;
}}}
Methods:
getInstance()
Returns m_instance
getJythonObject()
Returns an object based on a Jython module (Read: http://wiki.python.org/jython/JythonMonthly/Articles/September2006/1)
runQuestScript(PlayerChar player)
Runs a quest script for player
= TimeService.java =
Fields:
{{{
public enum Weather { NORMAL, RAIN, HAIL, SUN }
private Weather m_weather;
private static int m_hour;
private static int m_minutes;
}}}
Methods:
getWeather()
Returns m_weather
isNight()
Returns if it is night time
run()
Updates the time and weather
start()
Starts the thread
stop()
Stops the thread
== Backend ==
The objective of the backend is to provide, in a threaded model, a battle system, map loading, a movement system along with other backend features.
= MovementService.java =
Fields:
{{{
private ArrayList m_players;
private Thread m_thread;
}}}
Methods:
addPlayer(PlayerChar p)
Adds a player to this movement service
removePlayer(PlayerChar p)
Removes a player from this movement service
run()
Called when the thread is start. Loops through players and moves them if they have a movement queued
start()
Starts m_thread
stop()
Stops m_thread
= BattleService.java =
Fields:
{{{
private ArrayList m_battles;
private Thread m_thread;
}}}
Methods:
run()
Called by Thread.start(). Constantly loops through m_battles executing battle moves when moves have been selected by both participants.
start()
Starts the thread
startNpcBattle(PlayerChar player, NonPlayerChar npc)
Starts a new NPC battle and adds the battlefield to m_battles
startPvPBattle(PlayerChar player1, PlayerChar player2)
Starts a new PvP battle and adds the battlefield to m_battles.
startWildBattle(PlayerChar player, Pokemon poke)
Starts a new wild battle and adds the battlefield to m_battles.
stop()
Stops the thread
= Char.java =
Represents a generic character
= PlayerChar.java =
Represents a player
= NonPlayerChar.java =
Represents a Non-Playable character
= Bag.java =
Represents a bag of items
= BagItem.java =
Represents an item
== Battle ==
The battle package of the server is a modified version of ShoddyBattle. For information on ShoddyBattle, their source is available on their website http://shoddybattle.com/ .
We provide extra classes to support different battle types. The following is the stucture of a BattleField, other private methods may be added as needed.
= BattleField Structure (NpcBattleField, WildBattleField, PvPBattleField, etc.) =
extends BattleField
Constructors:
{{{
public NpcBattleField(PlayerChar player, NonPlayerChar npc) {
//Call super(BattleMechanics m, new Pokemon[][] {
player.getParty(),
npc.getParty())
//BattleMechanics can be retrieved using static access
}}}
Fields:
NpcBattleField
{{{
private Pokemon[] m_enemyParty;
private NonPlayerChar m_npc;
private PlayerChar mplayer;
}}}
WildBattleField
{{{
private PlayerChar mplayer;
}}}
PvPBattleField
{{{
private PlayerChar[] m_players;
private long m_prizeMoney;
}}}
All BattleFields
{{{
BattleTurn [] m_queuedTurns = new BattleTurn2;
Set mparticipatingPokemon = new LinkedHashSet();
}}}
Methods:
(private) calculateLevelling()
Calculates player’s exp gain
clearQueue()
Clears the move queue
endBattle(int scenario)
Ends the battle based on a senario (Lose, Error, etc.)
getTrainerName(int index)
Returns the name of the trainer with the specified index
informPokemonFainted(int trainer, int idx)
Informs trainer that the pokemon at index ‘idx’ in their party has fainted
informPokemonHealthChanged(Pokemon poke, int amount)
Informs player that poke’s health has change by amount
informStatusApplied(Pokemon poke, StatusEffect eff)
Informs player that p has received status effect eff
informStatusRemoved(Pokemon poke, StatusEffect eff)
Informs player that p has lost status effect eff
informSwitchInPokemon(int trainer, Pokemon p)
Informs player that trainer has switched out Pokemon p
informUseMove(Pokemon poke, String name)
Informs player that poke used move name
informVictory(int winner)
Informs player that the victor was trainer of index winner. Calls calculateLevelling()
queueMove(int trainer, BattleTurn move)
Queues the next move made by trainer
requestMoves()
Requests moves from both participants
requestPokemonReplacement(int i)
Requests a replacement Pokemon if one has fainted
showMessage(String message)
Sends message to both participants
== Networking ==
The objective of the networking section will be to provide a simple way of sending/receiving data to/from client/server, a way of storing player information and a way to implement a chat system, all in a threaded model.
= NetworkService.java =
Fields:
{{{
private ConnectionManager m_connectionManager;
private ChatManager [] m_chatManager;
private LoginManager m_loginManager;
private LogoutManager m_logoutManager;
}}}
Methods:
getChatManager()
Returns the chat manager with the smallest queue of messages
getConnectionManager()
Returns the connection manager (default manager if there is no user implementation)
getLoginManager()
Returns the login manager
getLogoutManager()
Returns the logout manager
start()
Starts all networking services by starting threads for LoginManager, LogoutManager, ChatManager and the ConnectionManager.
stop()
Stops all networking services by logging out all users and stopping all threads.
= ConnectionManager.java =
Constructors:
public ConnectionManager(LoginManager login, LogoutManager logout)
Fields:
{{{
private LoginManager m_loginManager;
private LogoutManager m_logoutManager;
private boolean m_shutdown = false;
}}}
Methods:
attemptUserLogin(IoSession session, String username, String password)
Attempts to login a player and attach their PlayerChar object to their session by putting them in the login queue in m_loginManager
attemptUserLogout(IoSession session)
Attempts to logout a player by queueing their PlayerChar object in the logout queue in m_logoutManager.
init()
This code is run once the connection manager is started.
messageReceived(IoSession session, Object o)
Code to be executed when a message is received from the client.
sessionCreated(IoSession session)
By default this closes the session if m_shutdown is true.
sessionClosed(IoSession session)
By default this calls attemptUserLogout(session).
= LoginManager.java =
Fields:
{{{
private Queue m_loginQueue;
private Thread m_thread;
}}}
Methods:
queuePlayer(IoSession session, String username, String password)
Adds a player to m_loginQueue to be logged in,
attemptLogin(IoSession session, String username, String password)
Attempts to login a player, sends a packet to the player upon success.
run()
Called when the thread is started. Logs players in one by one
start()
Starts the thread
stop()
Stops the thread
= LogoutManager.java =
Fields:
{{{
private Queue m_logoutQueue;
private Thread m_thread;
}}}
Methods:
attemptLogout(PlayerChar p)
Attempts to logout a player by saving their data.
queuePlayer(PlayerChar p)
Adds a player to m_logoutQueue to be logged out.
run()
Called when the thread is started. Logs players out one by one.
start()
Starts the thread
stop()
Stops the thread
= ChatManager.java =
Fields:
{{{
private Queue m_chatQueue;
private Thread m_thread;
}}}
Methods:
queueMessage(String sender, String receiver, String message)
Queues a message in m_chatQueue
run()
Called when the thread is started. Sends each message one by one. Support for local and private chats must be included.
start()
Starts the thread
stop()
Stops the thread