mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-03 00:38:21 +00:00
Modularise! Also add some unit tests.
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>apollo</groupId>
|
||||
<artifactId>org.apollo</artifactId>
|
||||
<version>0.0.1</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>game</artifactId>
|
||||
<version>0.0.1</version>
|
||||
|
||||
<name>Apollo Game</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src/main</sourceDirectory>
|
||||
<testSourceDirectory>src/test</testSourceDirectory>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>apollo</groupId>
|
||||
<artifactId>cache</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>apollo</groupId>
|
||||
<artifactId>net</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>apollo</groupId>
|
||||
<artifactId>util</artifactId>
|
||||
<version>0.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,160 @@
|
||||
package org.apollo;
|
||||
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apollo.cache.IndexedFileSystem;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.plugin.PluginContext;
|
||||
import org.apollo.game.plugin.PluginManager;
|
||||
import org.apollo.game.release.r317.Release317;
|
||||
import org.apollo.game.session.ApolloHandler;
|
||||
import org.apollo.net.HttpChannelInitializer;
|
||||
import org.apollo.net.JagGrabChannelInitializer;
|
||||
import org.apollo.net.NetworkConstants;
|
||||
import org.apollo.net.ServiceChannelInitializer;
|
||||
import org.apollo.net.release.Release;
|
||||
|
||||
import com.google.common.base.Stopwatch;
|
||||
|
||||
/**
|
||||
* The core class of the Apollo server.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class Server {
|
||||
|
||||
/**
|
||||
* The logger for this class.
|
||||
*/
|
||||
private static final Logger logger = Logger.getLogger(Server.class.getName());
|
||||
|
||||
/**
|
||||
* The entry point of the Apollo server application.
|
||||
*
|
||||
* @param args The command-line arguments passed to the application.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Stopwatch stopwatch = Stopwatch.createStarted();
|
||||
|
||||
try {
|
||||
Server server = new Server();
|
||||
server.init(args.length == 1 ? args[0] : Release317.class.getName());
|
||||
|
||||
SocketAddress service = new InetSocketAddress(NetworkConstants.SERVICE_PORT);
|
||||
SocketAddress http = new InetSocketAddress(NetworkConstants.HTTP_PORT);
|
||||
SocketAddress jaggrab = new InetSocketAddress(NetworkConstants.JAGGRAB_PORT);
|
||||
|
||||
server.bind(service, http, jaggrab);
|
||||
} catch (Throwable t) {
|
||||
logger.log(Level.SEVERE, "Error whilst starting server.", t);
|
||||
}
|
||||
|
||||
logger.fine("Starting apollo took " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + " ms.");
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link ServerBootstrap} for the HTTP listener.
|
||||
*/
|
||||
private final ServerBootstrap httpBootstrap = new ServerBootstrap();
|
||||
|
||||
/**
|
||||
* The {@link ServerBootstrap} for the JAGGRAB listener.
|
||||
*/
|
||||
private final ServerBootstrap jagGrabBootstrap = new ServerBootstrap();
|
||||
|
||||
/**
|
||||
* The {@link ServerBootstrap} for the service listener.
|
||||
*/
|
||||
private final ServerBootstrap serviceBootstrap = new ServerBootstrap();
|
||||
|
||||
/**
|
||||
* The event loop group.
|
||||
*/
|
||||
private final EventLoopGroup loopGroup = new NioEventLoopGroup();
|
||||
|
||||
/**
|
||||
* Creates the Apollo server.
|
||||
*/
|
||||
public Server() {
|
||||
logger.info("Starting Apollo...");
|
||||
}
|
||||
|
||||
/**
|
||||
* Binds the server to the specified address.
|
||||
*
|
||||
* @param serviceAddress The service address to bind to.
|
||||
* @param httpAddress The HTTP address to bind to.
|
||||
* @param jagGrabAddress The JAGGRAB address to bind to.
|
||||
*/
|
||||
public void bind(SocketAddress serviceAddress, SocketAddress httpAddress, SocketAddress jagGrabAddress) {
|
||||
try {
|
||||
logger.fine("Binding service listener to address: " + serviceAddress + "...");
|
||||
serviceBootstrap.bind(serviceAddress).sync();
|
||||
|
||||
logger.fine("Binding HTTP listener to address: " + httpAddress + "...");
|
||||
httpBootstrap.bind(httpAddress).sync();
|
||||
|
||||
logger.fine("Binding JAGGRAB listener to address: " + jagGrabAddress + "...");
|
||||
jagGrabBootstrap.bind(jagGrabAddress).sync();
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, "Binding to a port failed: ensure apollo isn't already running.", e);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
logger.info("Ready for connections.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialises the server.
|
||||
*
|
||||
* @param releaseClassName The class name of the current active {@link Release}.
|
||||
* @throws Exception If an error occurs.
|
||||
*/
|
||||
public void init(String releaseClassName) throws Exception {
|
||||
Class<?> clazz = Class.forName(releaseClassName);
|
||||
Release release = (Release) clazz.newInstance();
|
||||
int releaseNo = release.getReleaseNumber();
|
||||
|
||||
logger.info("Initialized release #" + releaseNo + ".");
|
||||
|
||||
serviceBootstrap.group(loopGroup);
|
||||
httpBootstrap.group(loopGroup);
|
||||
jagGrabBootstrap.group(loopGroup);
|
||||
|
||||
World world = new World();
|
||||
ServiceManager services = new ServiceManager(world);
|
||||
IndexedFileSystem fs = new IndexedFileSystem(Paths.get("data/fs", Integer.toString(releaseNo)), true);
|
||||
ServerContext context = new ServerContext(release, services, fs);
|
||||
ApolloHandler handler = new ApolloHandler(context);
|
||||
|
||||
ChannelInitializer<SocketChannel> serviceInitializer = new ServiceChannelInitializer(handler);
|
||||
serviceBootstrap.channel(NioServerSocketChannel.class);
|
||||
serviceBootstrap.childHandler(serviceInitializer);
|
||||
|
||||
ChannelInitializer<SocketChannel> httpInitializer = new HttpChannelInitializer(handler);
|
||||
httpBootstrap.channel(NioServerSocketChannel.class);
|
||||
httpBootstrap.childHandler(httpInitializer);
|
||||
|
||||
ChannelInitializer<SocketChannel> jagGrabInitializer = new JagGrabChannelInitializer(handler);
|
||||
jagGrabBootstrap.channel(NioServerSocketChannel.class);
|
||||
jagGrabBootstrap.childHandler(jagGrabInitializer);
|
||||
|
||||
PluginManager manager = new PluginManager(world, new PluginContext(context));
|
||||
services.startAll();
|
||||
|
||||
world.init(releaseNo, fs, manager);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package org.apollo;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apollo.cache.IndexedFileSystem;
|
||||
import org.apollo.game.service.GameService;
|
||||
import org.apollo.game.service.LoginService;
|
||||
import org.apollo.game.service.UpdateService;
|
||||
import org.apollo.net.release.Release;
|
||||
|
||||
/**
|
||||
* A {@link ServerContext} is created along with the {@link Server} object. The primary difference is that a reference
|
||||
* to the current context should be passed around within the server. The {@link Server} should not be as it allows
|
||||
* access to some methods such as {@link Server#bind} which user scripts/code should not be able to access.
|
||||
*
|
||||
* @author Graham
|
||||
* @author Major
|
||||
*/
|
||||
public final class ServerContext {
|
||||
|
||||
/**
|
||||
* The IndexedFileSystem.
|
||||
*/
|
||||
private final IndexedFileSystem fileSystem;
|
||||
|
||||
/**
|
||||
* The current release.
|
||||
*/
|
||||
private final Release release;
|
||||
|
||||
/**
|
||||
* The service manager.
|
||||
*/
|
||||
private final ServiceManager services;
|
||||
|
||||
/**
|
||||
* Creates a new server context.
|
||||
*
|
||||
* @param release The current release.
|
||||
* @param services The service manager.
|
||||
* @param fileSystem The indexed file system.
|
||||
*/
|
||||
protected ServerContext(Release release, ServiceManager services, IndexedFileSystem fileSystem) {
|
||||
this.release = Objects.requireNonNull(release);
|
||||
this.services = Objects.requireNonNull(services);
|
||||
this.services.setContext(this);
|
||||
this.fileSystem = Objects.requireNonNull(fileSystem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the IndexeFileSystem
|
||||
*
|
||||
* @return The IndexedFileSystem.
|
||||
*/
|
||||
public IndexedFileSystem getFileSystem() {
|
||||
return fileSystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link GameService}.
|
||||
*
|
||||
* @return The GameService.
|
||||
*/
|
||||
public GameService getGameService() {
|
||||
return services.getGame();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link LoginService}.
|
||||
*
|
||||
* @return The LoginService.
|
||||
*/
|
||||
public LoginService getLoginService() {
|
||||
return services.getLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current release.
|
||||
*
|
||||
* @return The current release.
|
||||
*/
|
||||
public Release getRelease() {
|
||||
return release;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link UpdateService}.
|
||||
*
|
||||
* @return The UpdateService.
|
||||
*/
|
||||
public UpdateService getUpdateService() {
|
||||
return services.getUpdate();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.apollo;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a service that the server provides for a World.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public abstract class Service {
|
||||
|
||||
/**
|
||||
* The server context.
|
||||
*/
|
||||
protected ServerContext context;
|
||||
|
||||
/**
|
||||
* Gets the {@link ServerContext}.
|
||||
*
|
||||
* @return The context.
|
||||
*/
|
||||
public final ServerContext getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ServerContext}.
|
||||
*
|
||||
* @param context The context.
|
||||
*/
|
||||
public final void setContext(ServerContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the service.
|
||||
*/
|
||||
public abstract void start();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package org.apollo;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.service.GameService;
|
||||
import org.apollo.game.service.LoginService;
|
||||
import org.apollo.game.service.UpdateService;
|
||||
|
||||
/**
|
||||
* A class which manages {@link Service}s.
|
||||
*
|
||||
* @author Graham
|
||||
* @author Major
|
||||
*/
|
||||
public final class ServiceManager {
|
||||
|
||||
/**
|
||||
* The Logger for this class.
|
||||
*/
|
||||
private static final Logger logger = Logger.getLogger(ServiceManager.class.getName());
|
||||
|
||||
/**
|
||||
* The GameService.
|
||||
*/
|
||||
private final GameService game;
|
||||
|
||||
/**
|
||||
* The LoginService.
|
||||
*/
|
||||
private final LoginService login;
|
||||
|
||||
/**
|
||||
* The UpdateService.
|
||||
*/
|
||||
private final UpdateService update = new UpdateService();
|
||||
|
||||
/**
|
||||
* Creates and initializes the {@link ServiceManager}.
|
||||
*
|
||||
* @param world The {@link World} to create the {@link Service}s for.
|
||||
* @throws Exception If there is an error creating the Services.
|
||||
*/
|
||||
public ServiceManager(World world) throws Exception {
|
||||
game = new GameService(world);
|
||||
login = new LoginService(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link GameService}.
|
||||
*
|
||||
* @return The GameService.
|
||||
*/
|
||||
public GameService getGame() {
|
||||
return game;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link LoginService}.
|
||||
*
|
||||
* @return The LoginService.
|
||||
*/
|
||||
public LoginService getLogin() {
|
||||
return login;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link UpdateService}.
|
||||
*
|
||||
* @return The UpdateService.
|
||||
*/
|
||||
public UpdateService getUpdate() {
|
||||
return update;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context of all services.
|
||||
*
|
||||
* @param context The server context.
|
||||
*/
|
||||
public void setContext(ServerContext context) {
|
||||
game.setContext(context);
|
||||
login.setContext(context);
|
||||
update.setContext(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts all the services.
|
||||
*/
|
||||
public void startAll() {
|
||||
logger.info("Starting services...");
|
||||
game.start();
|
||||
login.start();
|
||||
update.start();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.apollo.game;
|
||||
|
||||
/**
|
||||
* Contains game-related constants.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class GameConstants {
|
||||
|
||||
/**
|
||||
* The maximum amount of messages to process per pulse (per session).
|
||||
*/
|
||||
public static final int MESSAGES_PER_PULSE = 10;
|
||||
|
||||
/**
|
||||
* The delay between consecutive pulses, in milliseconds.
|
||||
*/
|
||||
public static final int PULSE_DELAY = 600;
|
||||
|
||||
/**
|
||||
* Default private constructor to prevent instantiation by other classes.
|
||||
*/
|
||||
private GameConstants() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.apollo.game;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apollo.game.service.GameService;
|
||||
|
||||
/**
|
||||
* A class which handles the logic for each pulse of the {@link GameService}.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class GamePulseHandler implements Runnable {
|
||||
|
||||
/**
|
||||
* The logger for this class.
|
||||
*/
|
||||
private static final Logger logger = Logger.getLogger(GamePulseHandler.class.getName());
|
||||
|
||||
/**
|
||||
* The {@link GameService}.
|
||||
*/
|
||||
private final GameService service;
|
||||
|
||||
/**
|
||||
* Creates the game pulse handler object.
|
||||
*
|
||||
* @param service The {@link GameService}.
|
||||
*/
|
||||
public GamePulseHandler(GameService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
service.pulse();
|
||||
} catch (Throwable reason) {
|
||||
logger.log(Level.SEVERE, "Exception occured during pulse!", reason);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.apollo.game.action;
|
||||
|
||||
import org.apollo.game.model.entity.Mob;
|
||||
import org.apollo.game.scheduling.ScheduledTask;
|
||||
|
||||
/**
|
||||
* An action is a specialised {@link ScheduledTask} that is specific to a {@link Mob}.
|
||||
* <p>
|
||||
* <strong>ALL</strong> actions <strong>MUST</strong> implement the {@link #equals(Object)} method. This is to check if
|
||||
* two actions are identical: if they are, then the new action does not replace the old one (so spam/accidental clicking
|
||||
* won't cancel your action, and start another from scratch).
|
||||
*
|
||||
* @author Graham
|
||||
* @param <T> The type of mob.
|
||||
*/
|
||||
public abstract class Action<T extends Mob> extends ScheduledTask {
|
||||
|
||||
/**
|
||||
* The mob performing the action.
|
||||
*/
|
||||
protected final T mob;
|
||||
|
||||
/**
|
||||
* A flag indicating if this action is stopping.
|
||||
*/
|
||||
private boolean stopping = false;
|
||||
|
||||
/**
|
||||
* Creates a new action.
|
||||
*
|
||||
* @param delay The delay in pulses.
|
||||
* @param immediate A flag indicating if the action should happen immediately.
|
||||
* @param mob The mob performing the action.
|
||||
*/
|
||||
public Action(int delay, boolean immediate, T mob) {
|
||||
super(delay, immediate);
|
||||
this.mob = mob;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mob which performed the action.
|
||||
*
|
||||
* @return The mob.
|
||||
*/
|
||||
public final T getMob() {
|
||||
return mob;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
super.stop();
|
||||
if (!stopping) {
|
||||
stopping = true;
|
||||
mob.stopAction();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.apollo.game.action;
|
||||
|
||||
import org.apollo.game.model.Position;
|
||||
import org.apollo.game.model.entity.Mob;
|
||||
|
||||
/**
|
||||
* An @{link Action} which fires when a distance requirement is met.
|
||||
*
|
||||
* @author Blake
|
||||
* @author Graham
|
||||
* @param <T> The type of {@link Mob}.
|
||||
*/
|
||||
public abstract class DistancedAction<T extends Mob> extends Action<T> {
|
||||
|
||||
/**
|
||||
* The delay once the threshold is reached.
|
||||
*/
|
||||
private final int delay;
|
||||
|
||||
/**
|
||||
* The minimum distance before the action fires.
|
||||
*/
|
||||
private final int distance;
|
||||
|
||||
/**
|
||||
* A flag indicating if this action fires immediately after the threshold is reached.
|
||||
*/
|
||||
private final boolean immediate;
|
||||
|
||||
/**
|
||||
* The position to distance check with.
|
||||
*/
|
||||
private final Position position;
|
||||
|
||||
/**
|
||||
* A flag indicating if the distance has been reached yet.
|
||||
*/
|
||||
private boolean reached = false;
|
||||
|
||||
/**
|
||||
* Creates a new DistancedAction.
|
||||
*
|
||||
* @param delay The delay between executions once the distance threshold is reached.
|
||||
* @param immediate Whether or not this action fires immediately after the distance threshold is reached.
|
||||
* @param mob The mob.
|
||||
* @param position The position.
|
||||
* @param distance The distance.
|
||||
*/
|
||||
public DistancedAction(int delay, boolean immediate, T mob, Position position, int distance) {
|
||||
super(0, true, mob);
|
||||
this.position = position;
|
||||
this.distance = distance;
|
||||
this.delay = delay;
|
||||
this.immediate = immediate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void execute() {
|
||||
if (reached) { // Don't check again in case the player has moved away since it was reached
|
||||
executeAction();
|
||||
// TODO checking the walking queue size is a really cheap fix, and relies on the client not
|
||||
// being edited... this class needs to be completely re-written.
|
||||
} else if (mob.getPosition().getDistance(position) <= distance && mob.getWalkingQueue().size() == 0) {
|
||||
reached = true;
|
||||
setDelay(delay);
|
||||
if (immediate) {
|
||||
executeAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the actual action. Called when the distance requirement is met.
|
||||
*/
|
||||
protected abstract void executeAction();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains classes related to actions, specialised scheduled tasks which mobs perform.
|
||||
*/
|
||||
package org.apollo.game.action;
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.apollo.game.command;
|
||||
|
||||
/**
|
||||
* Represents a command.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class Command {
|
||||
|
||||
/**
|
||||
* The command's arguments.
|
||||
*/
|
||||
private final String[] arguments;
|
||||
|
||||
/**
|
||||
* The name of the command.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Creates the command.
|
||||
*
|
||||
* @param name The name of the command.
|
||||
* @param arguments The command's arguments.
|
||||
*/
|
||||
public Command(String name, String[] arguments) {
|
||||
this.name = name;
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command's arguments.
|
||||
*
|
||||
* @return The command's arguments.
|
||||
*/
|
||||
public String[] getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the command.
|
||||
*
|
||||
* @return The name of the command.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.apollo.game.command;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apollo.game.model.entity.Player;
|
||||
|
||||
/**
|
||||
* A class that dispatches {@link Command}s to {@link CommandListener}s.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class CommandDispatcher {
|
||||
|
||||
/**
|
||||
* A map of command strings to command listeners.
|
||||
*/
|
||||
private final Map<String, CommandListener> listeners = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Initialises this CommandDispatcher.
|
||||
*
|
||||
* @param authors The {@link Set} of plugin authors.
|
||||
*/
|
||||
public void init(Set<String> authors) {
|
||||
listeners.put("credits", new CreditsCommandListener(authors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches a command to the appropriate listener.
|
||||
*
|
||||
* @param player The player.
|
||||
* @param command The command.
|
||||
*/
|
||||
public void dispatch(Player player, Command command) {
|
||||
CommandListener listener = listeners.get(command.getName().toLowerCase());
|
||||
if (listener != null) {
|
||||
listener.executePrivileged(player, command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a listener with the dispatcher.
|
||||
*
|
||||
* @param command The command's name.
|
||||
* @param listener The listener.
|
||||
*/
|
||||
public void register(String command, CommandListener listener) {
|
||||
listeners.put(command.toLowerCase(), listener);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.apollo.game.command;
|
||||
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.entity.setting.PrivilegeLevel;
|
||||
|
||||
/**
|
||||
* An interface which should be implemented to listen to {@link Command}s.
|
||||
*
|
||||
* @author Graham
|
||||
* @author Major
|
||||
*/
|
||||
public abstract class CommandListener {
|
||||
|
||||
/**
|
||||
* The minimum privilege level.
|
||||
*/
|
||||
private final PrivilegeLevel level;
|
||||
|
||||
/**
|
||||
* Creates a new command listener with a {@link PrivilegeLevel#STANDARD} requirement.
|
||||
*/
|
||||
public CommandListener() {
|
||||
this(PrivilegeLevel.STANDARD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new command listener.
|
||||
*
|
||||
* @param level The required {@link PrivilegeLevel}.
|
||||
*/
|
||||
public CommandListener(PrivilegeLevel level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the action for this command.
|
||||
*
|
||||
* @param player The player.
|
||||
* @param command The command.
|
||||
*/
|
||||
public abstract void execute(Player player, Command command);
|
||||
|
||||
/**
|
||||
* Executes a privileged command.
|
||||
*
|
||||
* @param player The player.
|
||||
* @param command The command.
|
||||
*/
|
||||
public final void executePrivileged(Player player, Command command) {
|
||||
if (player.getPrivilegeLevel().toInteger() >= level.toInteger()) {
|
||||
execute(player, command);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.apollo.game.command;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apollo.game.model.entity.Player;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
/**
|
||||
* Implements a {@code ::credits} command that lists the authors of all plugins used in the server.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class CreditsCommandListener extends CommandListener {
|
||||
|
||||
/**
|
||||
* The Set of authors.
|
||||
*/
|
||||
private final Set<String> authors;
|
||||
|
||||
/**
|
||||
* Creates the CreditsCommandListener.
|
||||
*
|
||||
* @param authors The {@link Set} of authors.
|
||||
*/
|
||||
public CreditsCommandListener(Set<String> authors) {
|
||||
this.authors = ImmutableSet.copyOf(authors);
|
||||
}
|
||||
|
||||
/*
|
||||
* If you are considering removing this command, please bear in mind that Apollo took several people thousands of
|
||||
* hours to create. We released it to the world for free and it isn't much to ask to leave this command in. It isn't
|
||||
* very obtrusive and gives us some well-deserved recognition for the work we have done. Thank you!
|
||||
*
|
||||
* The list of authors is generated from the plugin manager. If you create a custom plugin, make sure you add your
|
||||
* name to the plugin.xml file and it'll appear here automatically!
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void execute(Player player, Command command) {
|
||||
List<String> text = new ArrayList<>(12 + authors.size());
|
||||
text.add("@dre@Apollo");
|
||||
text.add("@dre@Introduction");
|
||||
text.add("");
|
||||
text.add("This server is based on Apollo, a lightweight, fast, secure");
|
||||
text.add("and open-source RuneScape emulator. For more");
|
||||
text.add("information about Apollo, visit the website at:");
|
||||
text.add("@dbl@https://github.com/apollo-rsps/apollo");
|
||||
text.add("");
|
||||
text.add("Apollo is released under the terms of the ISC license.");
|
||||
text.add("");
|
||||
text.add("@dre@Credits");
|
||||
text.add("");
|
||||
text.addAll(authors);
|
||||
|
||||
player.sendQuestInterface(text);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains classes related to in-game commands.
|
||||
*/
|
||||
package org.apollo.game.command;
|
||||
@@ -0,0 +1,269 @@
|
||||
package org.apollo.game.fs.decoder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apollo.cache.IndexedFileSystem;
|
||||
import org.apollo.cache.def.ObjectDefinition;
|
||||
import org.apollo.game.fs.decoder.MapFileDecoder.MapDefinition;
|
||||
import org.apollo.game.model.Position;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.area.Region;
|
||||
import org.apollo.game.model.area.RegionRepository;
|
||||
import org.apollo.game.model.area.collision.CollisionMatrix;
|
||||
import org.apollo.game.model.entity.obj.GameObject;
|
||||
import org.apollo.game.model.entity.obj.ObjectType;
|
||||
import org.apollo.game.model.entity.obj.StaticGameObject;
|
||||
import org.apollo.util.BufferUtil;
|
||||
import org.apollo.util.CompressionUtil;
|
||||
|
||||
import com.google.common.collect.Iterables;
|
||||
|
||||
/**
|
||||
* Parses static object definitions, which include map tiles and landscapes.
|
||||
*
|
||||
* @author Ryley
|
||||
* @author Major
|
||||
*/
|
||||
public final class GameObjectDecoder {
|
||||
|
||||
/**
|
||||
* A bit flag that indicates that the tile at the current Position is blocked.
|
||||
*/
|
||||
private static final int BLOCKED_TILE = 1;
|
||||
|
||||
/**
|
||||
* A bit flag that indicates that the tile at the current Position is a bridge tile.
|
||||
*/
|
||||
private static final int BRIDGE_TILE = 2;
|
||||
|
||||
/**
|
||||
* The {@link IndexedFileSystem}.
|
||||
*/
|
||||
private final IndexedFileSystem fs;
|
||||
|
||||
/**
|
||||
* A {@link List} of decoded GameObjects.
|
||||
*/
|
||||
private final List<GameObject> objects = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The RegionRepository.
|
||||
*/
|
||||
private final RegionRepository regions;
|
||||
|
||||
/**
|
||||
* Creates the GameObjectDecoder.
|
||||
*
|
||||
* @param fs The {@link IndexedFileSystem}.
|
||||
* @param regions The {@link RegionRepository}.
|
||||
*/
|
||||
public GameObjectDecoder(IndexedFileSystem fs, RegionRepository regions) {
|
||||
this.fs = fs;
|
||||
this.regions = regions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the GameObjects from their MapDefinitions.
|
||||
*
|
||||
* @param world The {@link World} containing the StaticGameObjects.
|
||||
* @return The decoded objects.
|
||||
* @throws IOException If there is an error decoding the {@link MapDefinition}s.
|
||||
*/
|
||||
public GameObject[] decode(World world) throws IOException {
|
||||
Map<Integer, MapDefinition> definitions = MapFileDecoder.decode(fs);
|
||||
|
||||
for (Entry<Integer, MapDefinition> entry : definitions.entrySet()) {
|
||||
MapDefinition definition = entry.getValue();
|
||||
|
||||
int packed = definition.getPackedCoordinates();
|
||||
int x = (packed >> 8 & 0xFF) * 64;
|
||||
int y = (packed & 0xFF) * 64;
|
||||
|
||||
ByteBuffer objects = fs.getFile(4, definition.getObjectFile());
|
||||
ByteBuffer decompressed = ByteBuffer.wrap(CompressionUtil.degzip(objects));
|
||||
decodeObjects(world, decompressed, x, y);
|
||||
|
||||
ByteBuffer terrain = fs.getFile(4, definition.getTerrainFile());
|
||||
decompressed = ByteBuffer.wrap(CompressionUtil.degzip(terrain));
|
||||
decodeTerrain(decompressed, x, y);
|
||||
}
|
||||
|
||||
return Iterables.toArray(objects, GameObject.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocks tiles covered by a GameObject, if applicable.
|
||||
*
|
||||
* @param object The {@link GameObject}.
|
||||
* @param position The position of the GameObject.
|
||||
*/
|
||||
private void block(GameObject object, Position position) {
|
||||
ObjectDefinition definition = ObjectDefinition.lookup(object.getId());
|
||||
int type = object.getType();
|
||||
|
||||
Region region = regions.fromPosition(position);
|
||||
int x = position.getX(), y = position.getY(), height = position.getHeight();
|
||||
|
||||
CollisionMatrix matrix = region.getMatrix(height);
|
||||
|
||||
boolean block = false;
|
||||
|
||||
if (type == ObjectType.FLOOR_DECORATION.getValue() && definition.isInteractive()) {
|
||||
block = true;
|
||||
}
|
||||
|
||||
Predicate<Integer> walls = (value) -> value >= ObjectType.LENGTHWISE_WALL.getValue()
|
||||
&& value <= ObjectType.RECTANGULAR_CORNER.getValue() || value == ObjectType.DIAGONAL_WALL.getValue();
|
||||
|
||||
Predicate<Integer> roofs = (value) -> value > ObjectType.DIAGONAL_INTERACTABLE.getValue()
|
||||
&& value < ObjectType.FLOOR_DECORATION.getValue();
|
||||
|
||||
if (walls.test(type) || roofs.test(type)) {
|
||||
block = true;
|
||||
}
|
||||
|
||||
if (type == 10 && definition.isSolid()) {
|
||||
block = true;
|
||||
}
|
||||
|
||||
if (block) {
|
||||
for (int dx = 0; dx < definition.getWidth(); dx++) {
|
||||
for (int dy = 0; dy < definition.getLength(); dy++) {
|
||||
int localX = x % Region.SIZE + dx, localY = y % Region.SIZE + dy;
|
||||
|
||||
if (localX > 7 || localY > 7) {
|
||||
int nextLocalX = localX > 7 ? x + localX - 7 : x + localX;
|
||||
int nextLocalY = localY > 7 ? y + localY - 7 : y - localY;
|
||||
Position nextPosition = new Position(nextLocalX, nextLocalY);
|
||||
Region next = regions.fromPosition(nextPosition);
|
||||
|
||||
int nextX = nextPosition.getX() % Region.SIZE + dx, nextY = nextPosition.getY() % Region.SIZE
|
||||
+ dy;
|
||||
if (nextX > 7) {
|
||||
nextX -= 7;
|
||||
}
|
||||
if (nextY > 7) {
|
||||
nextY -= 7;
|
||||
}
|
||||
|
||||
next.getMatrix(height).block(nextX, nextY);
|
||||
continue;
|
||||
}
|
||||
|
||||
matrix.block(localX, localY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the attributes of a terrain file, blocking the tile if necessary.
|
||||
*
|
||||
* @param attributes The terrain attributes.
|
||||
* @param position The {@link Position} of the tile whose attributes are being decoded.
|
||||
*/
|
||||
private void decodeAttributes(int attributes, Position position) {
|
||||
Region region = regions.fromPosition(position);
|
||||
int x = position.getX(), y = position.getY(), height = position.getHeight();
|
||||
|
||||
CollisionMatrix current = region.getMatrix(height);
|
||||
|
||||
boolean block = false;
|
||||
if ((attributes & BLOCKED_TILE) != 0) {
|
||||
block = true;
|
||||
}
|
||||
if ((attributes & BRIDGE_TILE) != 0) {
|
||||
if (height > 0) {
|
||||
block = true;
|
||||
height--;
|
||||
}
|
||||
}
|
||||
|
||||
if (block) {
|
||||
int localX = x % Region.SIZE, localY = y % Region.SIZE;
|
||||
current.block(localX, localY);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes object data stored in the specified {@link ByteBuffer}.
|
||||
*
|
||||
* @param world The {@link World} containing the StaticGameObjects.
|
||||
* @param buffer The ByteBuffer.
|
||||
* @param x The x coordinate of the top left tile of the map file.
|
||||
* @param y The y coordinate of the top left tile of the map file.
|
||||
*/
|
||||
private void decodeObjects(World world, ByteBuffer buffer, int x, int y) {
|
||||
int id = -1;
|
||||
int idOffset = BufferUtil.readSmart(buffer);
|
||||
|
||||
while (idOffset != 0) {
|
||||
id += idOffset;
|
||||
|
||||
int packed = 0;
|
||||
int positionOffset = BufferUtil.readSmart(buffer);
|
||||
|
||||
while (positionOffset != 0) {
|
||||
packed += positionOffset - 1;
|
||||
|
||||
int localY = packed & 0x3F;
|
||||
int localX = packed >> 6 & 0x3F;
|
||||
int height = packed >> 12 & 0x3;
|
||||
|
||||
int attributes = buffer.get() & 0xFF;
|
||||
int type = attributes >> 2;
|
||||
int orientation = attributes & 0x3;
|
||||
Position position = new Position(x + localX, y + localY, height);
|
||||
|
||||
GameObject object = new StaticGameObject(world, id, position, type, orientation);
|
||||
objects.add(object);
|
||||
|
||||
block(object, position);
|
||||
positionOffset = BufferUtil.readSmart(buffer);
|
||||
}
|
||||
|
||||
idOffset = BufferUtil.readSmart(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes terrain data stored in the specified {@link ByteBuffer}.
|
||||
*
|
||||
* @param buffer The ByteBuffer.
|
||||
* @param x The x coordinate of the top left tile of the map file.
|
||||
* @param y The y coordinate of the top left tile of the map file.
|
||||
*/
|
||||
private void decodeTerrain(ByteBuffer buffer, int x, int y) {
|
||||
for (int height = 0; height < 4; height++) {
|
||||
for (int localX = 0; localX < 64; localX++) {
|
||||
for (int localY = 0; localY < 64; localY++) {
|
||||
Position position = new Position(x + localX, y + localY, height);
|
||||
|
||||
int attributes = 0;
|
||||
while (true) {
|
||||
int attributeId = buffer.get() & 0xFF;
|
||||
if (attributeId == 0) {
|
||||
decodeAttributes(attributes, position);
|
||||
break;
|
||||
} else if (attributeId == 1) {
|
||||
buffer.get();
|
||||
decodeAttributes(attributes, position);
|
||||
break;
|
||||
} else if (attributeId <= 49) {
|
||||
buffer.get();
|
||||
} else if (attributeId <= 81) {
|
||||
attributes = attributeId - 49;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
package org.apollo.game.fs.decoder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apollo.cache.IndexedFileSystem;
|
||||
import org.apollo.cache.archive.Archive;
|
||||
import org.apollo.cache.archive.ArchiveEntry;
|
||||
import org.apollo.game.model.area.Region;
|
||||
|
||||
/**
|
||||
* Decodes {@link MapDefinition}s from the {@link IndexedFileSystem}.
|
||||
*
|
||||
* @author Ryley
|
||||
* @author Major
|
||||
*/
|
||||
public final class MapFileDecoder {
|
||||
|
||||
/**
|
||||
* The width (and length) of a map file, in tiles.
|
||||
*/
|
||||
public static final int MAP_FILE_WIDTH = Region.SIZE * Region.SIZE;
|
||||
|
||||
/**
|
||||
* The file id of the versions archive.
|
||||
*/
|
||||
private static final int VERSIONS_ARCHIVE_FILE_ID = 5;
|
||||
|
||||
/**
|
||||
* Decodes {@link MapDefinition}s from the specified {@link IndexedFileSystem}.
|
||||
*
|
||||
* @param fs The IndexedFileSystem.
|
||||
* @return A {@link Map} of packed coordinates to their MapDefinitions.
|
||||
* @throws IOException If there is an error reading or decoding the Archive.
|
||||
*/
|
||||
protected static Map<Integer, MapDefinition> decode(IndexedFileSystem fs) throws IOException {
|
||||
Archive archive = Archive.decode(fs.getFile(0, VERSIONS_ARCHIVE_FILE_ID));
|
||||
ArchiveEntry entry = archive.getEntry("map_index");
|
||||
Map<Integer, MapDefinition> definitions = new HashMap<>();
|
||||
|
||||
ByteBuffer buffer = entry.getBuffer();
|
||||
int count = buffer.capacity() / (3 * Short.BYTES + Byte.BYTES);
|
||||
|
||||
for (int times = 0; times < count; times++) {
|
||||
int packed = buffer.getShort() & 0xFFFF;
|
||||
int terrain = buffer.getShort() & 0xFFFF;
|
||||
int objects = buffer.getShort() & 0xFFFF;
|
||||
boolean members = buffer.get() == 1;
|
||||
|
||||
definitions.put(packed, new MapDefinition(packed, terrain, objects, members));
|
||||
}
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* A definition for a region.
|
||||
*/
|
||||
public static final class MapDefinition {
|
||||
|
||||
/**
|
||||
* The packed coordinates.
|
||||
*/
|
||||
private final int packedCoordinates;
|
||||
|
||||
/**
|
||||
* The terrain file id.
|
||||
*/
|
||||
private final int terrain;
|
||||
|
||||
/**
|
||||
* The object file id.
|
||||
*/
|
||||
private final int objects;
|
||||
|
||||
/**
|
||||
* Indicates whether or not this map is members-only.
|
||||
*/
|
||||
private final boolean members;
|
||||
|
||||
/**
|
||||
* Creates the {@link MapDefinition}.
|
||||
*
|
||||
* @param packedCoordinates The packed coordinates.
|
||||
* @param terrain The terrain file id.
|
||||
* @param objects The object file id.
|
||||
* @param members Indicates whether or not this map is members-only.
|
||||
*/
|
||||
public MapDefinition(int packedCoordinates, int terrain, int objects, boolean members) {
|
||||
this.packedCoordinates = packedCoordinates;
|
||||
this.terrain = terrain;
|
||||
this.objects = objects;
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the packed coordinates.
|
||||
*
|
||||
* @return The packed coordinates.
|
||||
*/
|
||||
public int getPackedCoordinates() {
|
||||
return packedCoordinates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id of the file containing the terrain data.
|
||||
*
|
||||
* @return The file id.
|
||||
*/
|
||||
public int getTerrainFile() {
|
||||
return terrain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id of the file containing the object data.
|
||||
*
|
||||
* @return The file id.
|
||||
*/
|
||||
public int getObjectFile() {
|
||||
return objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this MapDefinition is for a members-only area of the world.
|
||||
*
|
||||
* @return {@code true} if this MapDefinition is for a members-only area, {@code false} if not.
|
||||
*/
|
||||
public boolean isMembersOnly() {
|
||||
return members;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains decoders.
|
||||
*/
|
||||
package org.apollo.game.fs.decoder;
|
||||
@@ -0,0 +1,67 @@
|
||||
package org.apollo.game.io;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apollo.cache.def.EquipmentDefinition;
|
||||
|
||||
/**
|
||||
* A class that parses the {@code data/equipment-[release].dat} file to create an array of {@link EquipmentDefinition}s.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class EquipmentDefinitionParser {
|
||||
|
||||
/**
|
||||
* The input stream.
|
||||
*/
|
||||
private final InputStream is;
|
||||
|
||||
/**
|
||||
* Creates the equipment definition parser.
|
||||
*
|
||||
* @param is The input stream.
|
||||
*/
|
||||
public EquipmentDefinitionParser(InputStream is) {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the input stream.
|
||||
*
|
||||
* @return The equipment definition array.
|
||||
* @throws IOException If an I/O error occurs.
|
||||
*/
|
||||
public EquipmentDefinition[] parse() throws IOException {
|
||||
DataInputStream dis = new DataInputStream(is);
|
||||
|
||||
int count = dis.readShort() & 0xFFFF;
|
||||
EquipmentDefinition[] definitions = new EquipmentDefinition[count];
|
||||
|
||||
for (int id = 0; id < count; id++) {
|
||||
int slot = dis.readByte() & 0xFF;
|
||||
if (slot != 0xFF) {
|
||||
boolean twoHanded = dis.readBoolean();
|
||||
boolean fullBody = dis.readBoolean();
|
||||
boolean fullHat = dis.readBoolean();
|
||||
boolean fullMask = dis.readBoolean();
|
||||
int attack = dis.readByte() & 0xFF;
|
||||
int strength = dis.readByte() & 0xFF;
|
||||
int defence = dis.readByte() & 0xFF;
|
||||
int ranged = dis.readByte() & 0xFF;
|
||||
int magic = dis.readByte() & 0xFF;
|
||||
|
||||
EquipmentDefinition definition = new EquipmentDefinition(id);
|
||||
definition.setLevels(attack, strength, defence, ranged, magic);
|
||||
definition.setSlot(slot);
|
||||
definition.setFlags(twoHanded, fullBody, fullHat, fullMask);
|
||||
|
||||
definitions[id] = definition;
|
||||
}
|
||||
}
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package org.apollo.game.io;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apollo.game.message.handler.MessageHandler;
|
||||
import org.apollo.game.message.handler.MessageHandlerChain;
|
||||
import org.apollo.game.message.handler.MessageHandlerChainSet;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.net.message.Message;
|
||||
import org.apollo.util.xml.XmlNode;
|
||||
import org.apollo.util.xml.XmlParser;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* A class that parses the {@code messages.xml} file to produce {@link MessageHandlerChainSet}s.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class MessageHandlerChainSetParser {
|
||||
|
||||
/**
|
||||
* The source {@link InputStream}.
|
||||
*/
|
||||
private final InputStream is;
|
||||
|
||||
/**
|
||||
* The {@link XmlParser} instance.
|
||||
*/
|
||||
private final XmlParser parser = new XmlParser();
|
||||
|
||||
/**
|
||||
* Creates the message chain parser.
|
||||
*
|
||||
* @param is The source {@link InputStream}.
|
||||
* @throws SAXException If a SAX error occurs.
|
||||
*/
|
||||
public MessageHandlerChainSetParser(InputStream is) throws SAXException {
|
||||
this.is = is;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the XML and produces a group of {@link MessageHandlerChain}s.
|
||||
*
|
||||
* @param world The {@link World} this MessageHandlerChainGroup is for.
|
||||
* @return A {@link MessageHandlerChainSet}.
|
||||
* @throws IOException If an I/O error occurs.
|
||||
* @throws SAXException If a SAX error occurs.
|
||||
* @throws ReflectiveOperationException If a reflection error occurs.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public MessageHandlerChainSet parse(World world) throws IOException, SAXException, ReflectiveOperationException {
|
||||
XmlNode messages = parser.parse(is);
|
||||
if (!messages.getName().equals("messages")) {
|
||||
throw new IOException("Root node name is not 'messages'.");
|
||||
}
|
||||
|
||||
MessageHandlerChainSet chainSet = new MessageHandlerChainSet();
|
||||
|
||||
for (XmlNode message : messages) {
|
||||
if (!message.getName().equals("message")) {
|
||||
throw new IOException("Only expected nodes named 'message' beneath the root node.");
|
||||
}
|
||||
|
||||
XmlNode typeNode = message.getChild("type");
|
||||
if (typeNode == null) {
|
||||
throw new IOException("No node named 'type' beneath current message node.");
|
||||
}
|
||||
XmlNode chainNode = message.getChild("chain");
|
||||
if (chainNode == null) {
|
||||
throw new IOException("No node named 'chain' beneath current message node.");
|
||||
}
|
||||
|
||||
String messageClassName = typeNode.getValue();
|
||||
if (messageClassName == null) {
|
||||
throw new IOException("Type node must have a value.");
|
||||
}
|
||||
|
||||
Class<? extends Message> messageClass = (Class<? extends Message>) Class.forName(messageClassName);
|
||||
|
||||
for (XmlNode handlerNode : chainNode) {
|
||||
if (!handlerNode.getName().equals("handler")) {
|
||||
throw new IOException("Only expected nodes named 'handler' beneath the root node.");
|
||||
}
|
||||
|
||||
String handlerClassName = handlerNode.getValue();
|
||||
if (handlerClassName == null) {
|
||||
throw new IOException("Handler node must have a value.");
|
||||
}
|
||||
|
||||
Class<? extends MessageHandler<? extends Message>> handlerClass = (Class<? extends MessageHandler<? extends Message>>) Class.forName(handlerClassName);
|
||||
MessageHandler<? extends Message> handler = handlerClass.getConstructor(World.class).newInstance(world);
|
||||
chainSet.putHandler(messageClass, handler);
|
||||
}
|
||||
}
|
||||
|
||||
return chainSet;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package org.apollo.game.io;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apollo.game.plugin.PluginMetaData;
|
||||
import org.apollo.util.xml.XmlNode;
|
||||
import org.apollo.util.xml.XmlParser;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* A class that parses {@code plugin.xml} files into {@link PluginMetaData} objects.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class PluginMetaDataParser {
|
||||
|
||||
/**
|
||||
* An empty xml node array.
|
||||
*/
|
||||
private static final XmlNode[] EMPTY_NODE_ARRAY = new XmlNode[0];
|
||||
|
||||
/**
|
||||
* The input stream.
|
||||
*/
|
||||
private final InputStream is;
|
||||
|
||||
/**
|
||||
* The XML parser.
|
||||
*/
|
||||
private final XmlParser parser;
|
||||
|
||||
/**
|
||||
* Creates the plugin meta data parser.
|
||||
*
|
||||
* @param is The input stream.
|
||||
* @throws SAXException If a SAX error occurs.
|
||||
*/
|
||||
public PluginMetaDataParser(InputStream is) throws SAXException {
|
||||
this.is = is;
|
||||
parser = new XmlParser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the specified child element, if it exists.
|
||||
*
|
||||
* @param node The root node.
|
||||
* @param name The element name.
|
||||
* @return The node object.
|
||||
* @throws IOException If the element does not exist.
|
||||
*/
|
||||
private static XmlNode getElement(XmlNode node, String name) throws IOException {
|
||||
return Objects.requireNonNull(node.getChild(name), "No " + name + " element found.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the XML and creates a meta data object.
|
||||
*
|
||||
* @param base The base path for this plugin
|
||||
* @return The meta data object.
|
||||
* @throws SAXException If a SAX error occurs.
|
||||
* @throws IOException If an I/O error occurs.
|
||||
*/
|
||||
public PluginMetaData parse(File base) throws IOException, SAXException {
|
||||
XmlNode rootNode = parser.parse(is);
|
||||
if (!rootNode.getName().equals("plugin")) {
|
||||
throw new IOException("Root node must be named plugin.");
|
||||
}
|
||||
|
||||
XmlNode idNode = getElement(rootNode, "id");
|
||||
XmlNode nameNode = getElement(rootNode, "name");
|
||||
XmlNode descriptionNode = getElement(rootNode, "description");
|
||||
XmlNode authorsNode = getElement(rootNode, "authors");
|
||||
XmlNode scriptsNode = getElement(rootNode, "scripts");
|
||||
XmlNode dependenciesNode = getElement(rootNode, "dependencies");
|
||||
XmlNode versionNode = getElement(rootNode, "version");
|
||||
|
||||
String id = idNode.getValue();
|
||||
String name = nameNode.getValue();
|
||||
String description = descriptionNode.getValue();
|
||||
double version = Double.parseDouble(versionNode.getValue());
|
||||
|
||||
if (id == null || name == null || description == null) {
|
||||
throw new IOException("Id, name and description must have values.");
|
||||
}
|
||||
|
||||
XmlNode[] authorNodes = authorsNode.getChildren().toArray(EMPTY_NODE_ARRAY);
|
||||
XmlNode[] scriptNodes = scriptsNode.getChildren().toArray(EMPTY_NODE_ARRAY);
|
||||
XmlNode[] dependencyNodes = dependenciesNode.getChildren().toArray(EMPTY_NODE_ARRAY);
|
||||
|
||||
String[] authors = new String[authorNodes.length];
|
||||
String[] scripts = new String[scriptNodes.length];
|
||||
String[] dependencies = new String[dependencyNodes.length];
|
||||
|
||||
for (int i = 0; i < authorNodes.length; i++) {
|
||||
authors[i] = authorNodes[i].getValue();
|
||||
if (authors[i] == null) {
|
||||
throw new IOException("Author elements must have values.");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < scriptNodes.length; i++) {
|
||||
scripts[i] = scriptNodes[i].getValue();
|
||||
if (scripts[i] == null) {
|
||||
throw new IOException("Script elements must have values.");
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < dependencyNodes.length; i++) {
|
||||
dependencies[i] = dependencyNodes[i].getValue();
|
||||
if (dependencies[i] == null) {
|
||||
throw new IOException("Dependency elements must have values.");
|
||||
}
|
||||
}
|
||||
|
||||
return new PluginMetaData(id, base, name, description, authors, scripts, dependencies, version);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains classes which deal with input/output.
|
||||
*/
|
||||
package org.apollo.game.io;
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.apollo.game.io.player;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.apollo.util.NameUtil;
|
||||
|
||||
/**
|
||||
* A utility class with common functionality used by the binary player loader/ savers.
|
||||
*
|
||||
* @author Graham
|
||||
* @author Major
|
||||
*/
|
||||
public final class BinaryFileUtils {
|
||||
|
||||
/**
|
||||
* The Path to the saved games directory.
|
||||
*/
|
||||
private static final Path SAVED_GAMES_DIRECTORY = Paths.get("data/savedGames");
|
||||
|
||||
/**
|
||||
* Creates the saved games directory if it does not exist.
|
||||
*/
|
||||
static {
|
||||
try {
|
||||
if (!Files.exists(SAVED_GAMES_DIRECTORY)) {
|
||||
Files.createDirectory(SAVED_GAMES_DIRECTORY);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Error creating saved games directory.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the save {@link File} for the specified player.
|
||||
*
|
||||
* @param username The username of the player.
|
||||
* @return The file.
|
||||
*/
|
||||
public static Path getFile(String username) {
|
||||
String filtered = NameUtil.decodeBase37(NameUtil.encodeBase37(username));
|
||||
return SAVED_GAMES_DIRECTORY.resolve(filtered + ".dat");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sole private constructor to prevent instantiation.
|
||||
*/
|
||||
private BinaryFileUtils() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
package org.apollo.game.io.player;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apollo.game.model.Appearance;
|
||||
import org.apollo.game.model.Item;
|
||||
import org.apollo.game.model.Position;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.entity.Skill;
|
||||
import org.apollo.game.model.entity.SkillSet;
|
||||
import org.apollo.game.model.entity.attr.Attribute;
|
||||
import org.apollo.game.model.entity.attr.AttributeMap;
|
||||
import org.apollo.game.model.entity.attr.AttributePersistence;
|
||||
import org.apollo.game.model.entity.attr.AttributeType;
|
||||
import org.apollo.game.model.entity.attr.BooleanAttribute;
|
||||
import org.apollo.game.model.entity.attr.NumericalAttribute;
|
||||
import org.apollo.game.model.entity.attr.StringAttribute;
|
||||
import org.apollo.game.model.entity.setting.Gender;
|
||||
import org.apollo.game.model.entity.setting.MembershipStatus;
|
||||
import org.apollo.game.model.entity.setting.PrivacyState;
|
||||
import org.apollo.game.model.entity.setting.PrivilegeLevel;
|
||||
import org.apollo.game.model.entity.setting.ScreenBrightness;
|
||||
import org.apollo.game.model.inv.Inventory;
|
||||
import org.apollo.net.codec.login.LoginConstants;
|
||||
import org.apollo.util.NameUtil;
|
||||
import org.apollo.util.StreamUtil;
|
||||
import org.apollo.util.security.PlayerCredentials;
|
||||
|
||||
import com.lambdaworks.crypto.SCryptUtil;
|
||||
|
||||
/**
|
||||
* A {@link PlayerSerializer} implementation that uses a binary file to store player data.
|
||||
*
|
||||
* @author Graham
|
||||
* @author Major
|
||||
*/
|
||||
public final class BinaryPlayerSerializer extends PlayerSerializer {
|
||||
|
||||
/**
|
||||
* Creates the BinaryPlayerSerializer.
|
||||
*
|
||||
* @param world The {@link World} to place the {@link Player}s in.
|
||||
*/
|
||||
public BinaryPlayerSerializer(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Path to the saved games directory.
|
||||
*/
|
||||
private static final Path SAVED_GAMES_DIRECTORY = Paths.get("data/savedGames");
|
||||
|
||||
static {
|
||||
try {
|
||||
if (!Files.exists(SAVED_GAMES_DIRECTORY)) {
|
||||
Files.createDirectory(SAVED_GAMES_DIRECTORY);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Error creating saved games directory.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws IOException {
|
||||
Path path = getFile(credentials.getUsername());
|
||||
if (!Files.exists(path)) {
|
||||
Player player = new Player(world, credentials, TUTORIAL_ISLAND_SPAWN);
|
||||
|
||||
credentials.setPassword(SCryptUtil.scrypt(credentials.getPassword(), 16384, 8, 1));
|
||||
return new PlayerLoaderResponse(LoginConstants.STATUS_OK, player);
|
||||
}
|
||||
|
||||
try (DataInputStream in = new DataInputStream(new BufferedInputStream(Files.newInputStream(path)))) {
|
||||
String name = StreamUtil.readString(in);
|
||||
String password = StreamUtil.readString(in);
|
||||
|
||||
if (!name.equalsIgnoreCase(credentials.getUsername()) || !SCryptUtil.check(credentials.getPassword(), password)) {
|
||||
return new PlayerLoaderResponse(LoginConstants.STATUS_INVALID_CREDENTIALS);
|
||||
}
|
||||
|
||||
credentials.setPassword(password); // Update password to the hashed one.
|
||||
|
||||
PrivilegeLevel privilege = PrivilegeLevel.valueOf(in.readByte());
|
||||
MembershipStatus members = MembershipStatus.valueOf(in.readByte());
|
||||
|
||||
PrivacyState chatPrivacy = PrivacyState.valueOf(in.readByte(), true);
|
||||
PrivacyState friendPrivacy = PrivacyState.valueOf(in.readByte(), false);
|
||||
PrivacyState tradePrivacy = PrivacyState.valueOf(in.readByte(), false);
|
||||
ScreenBrightness brightness = ScreenBrightness.valueOf(in.readByte());
|
||||
|
||||
int x = in.readUnsignedShort();
|
||||
int y = in.readUnsignedShort();
|
||||
int height = in.readUnsignedByte();
|
||||
|
||||
Gender gender = in.readUnsignedByte() == Gender.MALE.toInteger() ? Gender.MALE : Gender.FEMALE;
|
||||
int[] style = new int[7];
|
||||
for (int slot = 0; slot < style.length; slot++) {
|
||||
style[slot] = in.readUnsignedByte();
|
||||
}
|
||||
|
||||
int[] colors = new int[5];
|
||||
for (int slot = 0; slot < colors.length; slot++) {
|
||||
colors[slot] = in.readUnsignedByte();
|
||||
}
|
||||
|
||||
Player player = new Player(world, credentials, new Position(x, y, height));
|
||||
player.setPrivilegeLevel(privilege);
|
||||
player.setMembers(members);
|
||||
player.setChatPrivacy(chatPrivacy);
|
||||
player.setFriendPrivacy(friendPrivacy);
|
||||
player.setTradePrivacy(tradePrivacy);
|
||||
player.setScreenBrightness(brightness);
|
||||
|
||||
player.setAppearance(new Appearance(gender, style, colors));
|
||||
|
||||
readInventory(in, player.getInventory());
|
||||
readInventory(in, player.getEquipment());
|
||||
readInventory(in, player.getBank());
|
||||
|
||||
int size = in.readUnsignedByte();
|
||||
SkillSet skills = player.getSkillSet();
|
||||
skills.stopFiringEvents();
|
||||
try {
|
||||
for (int i = 0; i < size; i++) {
|
||||
int level = in.readUnsignedByte();
|
||||
double experience = in.readDouble();
|
||||
skills.setSkill(i, new Skill(experience, level, SkillSet.getLevelForExperience(experience)));
|
||||
}
|
||||
} finally {
|
||||
skills.calculateCombatLevel();
|
||||
skills.startFiringEvents();
|
||||
}
|
||||
|
||||
int friendCount = in.readByte();
|
||||
List<String> friends = new ArrayList<>(friendCount);
|
||||
for (int i = 0; i < friendCount; i++) {
|
||||
friends.add(NameUtil.decodeBase37(in.readLong()));
|
||||
}
|
||||
player.setFriendUsernames(friends);
|
||||
|
||||
int ignoreCount = in.readByte();
|
||||
List<String> ignores = new ArrayList<>(ignoreCount);
|
||||
for (int times = 0; times < ignoreCount; times++) {
|
||||
ignores.add(NameUtil.decodeBase37(in.readLong()));
|
||||
}
|
||||
player.setIgnoredUsernames(ignores);
|
||||
|
||||
Map<String, Attribute<?>> attributes = readAttributes(in);
|
||||
attributes.forEach(player::setAttribute);
|
||||
|
||||
return new PlayerLoaderResponse(LoginConstants.STATUS_OK, player);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void savePlayer(Player player) throws IOException {
|
||||
Path file = getFile(player.getUsername());
|
||||
|
||||
try (DataOutputStream out = new DataOutputStream(Files.newOutputStream(file))) {
|
||||
StreamUtil.writeString(out, player.getUsername());
|
||||
StreamUtil.writeString(out, player.getCredentials().getPassword());
|
||||
out.writeByte(player.getPrivilegeLevel().toInteger());
|
||||
out.writeByte(player.getMembershipStatus().getValue());
|
||||
|
||||
out.writeByte(player.getChatPrivacy().toInteger(true));
|
||||
out.writeByte(player.getFriendPrivacy().toInteger(false));
|
||||
out.writeByte(player.getTradePrivacy().toInteger(false));
|
||||
out.writeByte(player.getScreenBrightness().toInteger());
|
||||
|
||||
Position position = player.getPosition();
|
||||
out.writeShort(position.getX());
|
||||
out.writeShort(position.getY());
|
||||
out.writeByte(position.getHeight());
|
||||
|
||||
Appearance appearance = player.getAppearance();
|
||||
out.writeByte(appearance.getGender().toInteger());
|
||||
int[] style = appearance.getStyle();
|
||||
for (int element : style) {
|
||||
out.writeByte(element);
|
||||
}
|
||||
int[] colors = appearance.getColors();
|
||||
for (int color : colors) {
|
||||
out.writeByte(color);
|
||||
}
|
||||
|
||||
writeInventory(out, player.getInventory());
|
||||
writeInventory(out, player.getEquipment());
|
||||
writeInventory(out, player.getBank());
|
||||
|
||||
SkillSet skills = player.getSkillSet();
|
||||
out.writeByte(skills.size());
|
||||
for (int id = 0; id < skills.size(); id++) {
|
||||
Skill skill = skills.getSkill(id);
|
||||
out.writeByte(skill.getCurrentLevel());
|
||||
out.writeDouble(skill.getExperience());
|
||||
}
|
||||
|
||||
List<String> usernames = player.getFriendUsernames();
|
||||
out.writeByte(usernames.size());
|
||||
for (String username : usernames) {
|
||||
out.writeLong(NameUtil.encodeBase37(username));
|
||||
}
|
||||
|
||||
usernames = player.getIgnoredUsernames();
|
||||
out.writeByte(usernames.size());
|
||||
for (String username : usernames) {
|
||||
out.writeLong(NameUtil.encodeBase37(username));
|
||||
}
|
||||
|
||||
Set<Entry<String, Attribute<?>>> attributes = player.getAttributes().entrySet();
|
||||
attributes.removeIf(e -> AttributeMap.getDefinition(e.getKey()).getPersistence() != AttributePersistence.PERSISTENT);
|
||||
out.writeInt(attributes.size());
|
||||
|
||||
for (Entry<String, Attribute<?>> entry : attributes) {
|
||||
String name = entry.getKey();
|
||||
StreamUtil.writeString(out, name);
|
||||
|
||||
Attribute<?> attribute = entry.getValue();
|
||||
out.writeByte(attribute.getType().getValue());
|
||||
out.write(attribute.encode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the save {@link File} for the specified player.
|
||||
*
|
||||
* @param username The username of the player.
|
||||
* @return The file.
|
||||
*/
|
||||
private Path getFile(String username) {
|
||||
String filtered = NameUtil.decodeBase37(NameUtil.encodeBase37(username));
|
||||
return SAVED_GAMES_DIRECTORY.resolve(filtered + ".dat");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the player's {@link Attribute}s.
|
||||
*
|
||||
* @param in The input stream.
|
||||
* @return The {@link Map} of attribute names to attributes.
|
||||
* @throws IOException If there is an error reading from the stream.
|
||||
*/
|
||||
private Map<String, Attribute<?>> readAttributes(DataInputStream in) throws IOException {
|
||||
int count = in.readInt();
|
||||
Map<String, Attribute<?>> attributes = new HashMap<>(count);
|
||||
|
||||
for (int times = 0; times < count; times++) {
|
||||
String name = StreamUtil.readString(in);
|
||||
AttributeType type = AttributeType.valueOf(in.read());
|
||||
Attribute<?> attribute;
|
||||
|
||||
switch (type) {
|
||||
case BOOLEAN:
|
||||
attribute = new BooleanAttribute(in.read() == 1);
|
||||
break;
|
||||
case DOUBLE:
|
||||
attribute = new NumericalAttribute(in.readDouble());
|
||||
break;
|
||||
case LONG:
|
||||
attribute = new NumericalAttribute(in.readLong());
|
||||
break;
|
||||
case STRING:
|
||||
case SYMBOL:
|
||||
attribute = new StringAttribute(StreamUtil.readString(in), type == AttributeType.SYMBOL);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Undefined attribute type: " + type + ".");
|
||||
}
|
||||
attributes.put(name, attribute);
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an inventory from the input stream.
|
||||
*
|
||||
* @param in The input stream.
|
||||
* @param inventory The inventory.
|
||||
* @throws IOException If an I/O error occurs.
|
||||
*/
|
||||
private void readInventory(DataInputStream in, Inventory inventory) throws IOException {
|
||||
int capacity = in.readUnsignedShort();
|
||||
|
||||
inventory.stopFiringEvents();
|
||||
try {
|
||||
for (int slot = 0; slot < capacity; slot++) {
|
||||
int id = in.readUnsignedShort();
|
||||
int amount = in.readInt();
|
||||
if (id != 0) {
|
||||
inventory.set(slot, new Item(id - 1, amount));
|
||||
} else {
|
||||
inventory.reset(slot);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
inventory.startFiringEvents();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an inventory to the specified output stream.
|
||||
*
|
||||
* @param out The output stream.
|
||||
* @param inventory The inventory.
|
||||
* @throws IOException If an I/O error occurs.
|
||||
*/
|
||||
private void writeInventory(DataOutputStream out, Inventory inventory) throws IOException {
|
||||
int capacity = inventory.capacity();
|
||||
out.writeShort(capacity);
|
||||
|
||||
for (int slot = 0; slot < capacity; slot++) {
|
||||
Item item = inventory.get(slot);
|
||||
if (item != null) {
|
||||
out.writeShort(item.getId() + 1);
|
||||
out.writeInt(item.getAmount());
|
||||
} else {
|
||||
out.writeShort(0);
|
||||
out.writeInt(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package org.apollo.game.io.player;
|
||||
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.entity.setting.MembershipStatus;
|
||||
import org.apollo.game.model.entity.setting.PrivilegeLevel;
|
||||
import org.apollo.net.codec.login.LoginConstants;
|
||||
import org.apollo.util.security.PlayerCredentials;
|
||||
|
||||
/**
|
||||
* A {@link PlayerSerializer} that saves no data and returns an administrator member account, ideal for debugging.
|
||||
*
|
||||
* @author Graham
|
||||
* @author Major
|
||||
*/
|
||||
public final class DummyPlayerSerializer extends PlayerSerializer {
|
||||
|
||||
/**
|
||||
* Creates the DummyPlayerSerializer.
|
||||
*
|
||||
* @param world The {@link World} to place the {@link Player}s in.
|
||||
*/
|
||||
public DummyPlayerSerializer(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) {
|
||||
int status = LoginConstants.STATUS_OK;
|
||||
|
||||
Player player = new Player(world, credentials, TUTORIAL_ISLAND_SPAWN);
|
||||
player.setPrivilegeLevel(PrivilegeLevel.ADMINISTRATOR);
|
||||
player.setMembers(MembershipStatus.PAID);
|
||||
|
||||
return new PlayerLoaderResponse(status, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void savePlayer(Player player) {
|
||||
/* discard player */
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.apollo.game.io.player;
|
||||
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.util.security.PlayerCredentials;
|
||||
|
||||
/**
|
||||
* A {@link PlayerSerializer} that utilises {@code JDBC} to communicate with an SQL database containing player data.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class JdbcPlayerSerializer extends PlayerSerializer {
|
||||
|
||||
/**
|
||||
* Creates the JdbcPlayerSerializer.
|
||||
*
|
||||
* @param world The {@link World} to place the {@link Player}s in.
|
||||
*/
|
||||
public JdbcPlayerSerializer(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void savePlayer(Player player) throws Exception {
|
||||
throw new UnsupportedOperationException("JDBC saving is not supported at this time.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws Exception {
|
||||
throw new UnsupportedOperationException("JDBC loading is not supported at this time.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.apollo.game.io.player;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.net.codec.login.LoginConstants;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
* A response for the {@link PlayerSerializer#loadPlayer} call.
|
||||
*
|
||||
* @author Graham
|
||||
* @author Major
|
||||
*/
|
||||
public final class PlayerLoaderResponse {
|
||||
|
||||
/**
|
||||
* The player.
|
||||
*/
|
||||
private final Optional<Player> player;
|
||||
|
||||
/**
|
||||
* The status code.
|
||||
*/
|
||||
private final int status;
|
||||
|
||||
/**
|
||||
* Creates a {@link PlayerLoaderResponse} with only a status code.
|
||||
*
|
||||
* @param status The status code.
|
||||
* @throws IllegalArgumentException If the status code is {@link LoginConstants#STATUS_OK} or
|
||||
* {@link LoginConstants#STATUS_RECONNECTION_OK}.
|
||||
*/
|
||||
public PlayerLoaderResponse(int status) {
|
||||
Preconditions.checkArgument(status != LoginConstants.STATUS_OK && status != LoginConstants.STATUS_RECONNECTION_OK, "Player required for this status code.");
|
||||
this.status = status;
|
||||
player = Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link PlayerLoaderResponse} with a status code and {@link Player}.
|
||||
*
|
||||
* @param status The status code.
|
||||
* @param player The player.
|
||||
* @throws IllegalArgumentException If the status code does not need a player.
|
||||
* @throws NullPointerException If the specified player is null.
|
||||
*/
|
||||
public PlayerLoaderResponse(int status, Player player) {
|
||||
Preconditions.checkArgument(status == LoginConstants.STATUS_OK || status == LoginConstants.STATUS_RECONNECTION_OK, "Player not required for this status code.");
|
||||
this.status = status;
|
||||
this.player = Optional.of(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player.
|
||||
*
|
||||
* @return The player, wrapped in an {@link Optional}.
|
||||
*/
|
||||
public Optional<Player> getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status code.
|
||||
*
|
||||
* @return The status code.
|
||||
*/
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.apollo.game.io.player;
|
||||
|
||||
import org.apollo.game.model.Position;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.util.security.PlayerCredentials;
|
||||
|
||||
/**
|
||||
* An interface which may be implemented by others which are capable of serializing and deserializing players. For
|
||||
* example, implementations might include text-based, binary and SQL serializers.
|
||||
*
|
||||
* @author Graham
|
||||
* @author Major
|
||||
*/
|
||||
public abstract class PlayerSerializer {
|
||||
|
||||
/**
|
||||
* The spawn point for Players, on Tutorial Island.
|
||||
*/
|
||||
protected static final Position TUTORIAL_ISLAND_SPAWN = new Position(3093, 3104);
|
||||
|
||||
/**
|
||||
* The World this PlayerSerializer is for.
|
||||
*/
|
||||
protected final World world;
|
||||
|
||||
/**
|
||||
* Creates the PlayerSerializer.
|
||||
*
|
||||
* @param world The {@link World} this PlayerSerializer is for.
|
||||
*/
|
||||
public PlayerSerializer(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a {@link Player}.
|
||||
*
|
||||
* @param credentials The {@link PlayerCredentials}.
|
||||
* @return The {@link PlayerLoaderResponse}.
|
||||
* @throws Exception If an error occurs.
|
||||
*/
|
||||
public abstract PlayerLoaderResponse loadPlayer(PlayerCredentials credentials) throws Exception;
|
||||
|
||||
/**
|
||||
* Saves a {@link Player}.
|
||||
*
|
||||
* @param player The Player to save.
|
||||
* @throws Exception If an error occurs.
|
||||
*/
|
||||
public abstract void savePlayer(Player player) throws Exception;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains classes which deal with loading and saving player files.
|
||||
*/
|
||||
package org.apollo.game.io.player;
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.apollo.game.login;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apollo.game.io.player.PlayerLoaderResponse;
|
||||
import org.apollo.game.io.player.PlayerSerializer;
|
||||
import org.apollo.game.session.LoginSession;
|
||||
import org.apollo.net.codec.login.LoginConstants;
|
||||
import org.apollo.net.codec.login.LoginRequest;
|
||||
|
||||
/**
|
||||
* A class which processes a single login request.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class PlayerLoaderWorker implements Runnable {
|
||||
|
||||
/**
|
||||
* The logger for this class.
|
||||
*/
|
||||
private static final Logger logger = Logger.getLogger(PlayerLoaderWorker.class.getName());
|
||||
|
||||
/**
|
||||
* The PlayerSerializer.
|
||||
*/
|
||||
private final PlayerSerializer loader;
|
||||
|
||||
/**
|
||||
* The request.
|
||||
*/
|
||||
private final LoginRequest request;
|
||||
|
||||
/**
|
||||
* The session that submitted the request.
|
||||
*/
|
||||
private final LoginSession session;
|
||||
|
||||
/**
|
||||
* Creates a {@link PlayerLoaderWorker} which will do the work for a single player load request.
|
||||
*
|
||||
* @param loader The {@link PlayerSerializer}.
|
||||
* @param session The {@link LoginSession} which initiated the request.
|
||||
* @param request The {@link LoginRequest} object.
|
||||
*/
|
||||
public PlayerLoaderWorker(PlayerSerializer loader, LoginSession session, LoginRequest request) {
|
||||
this.loader = loader;
|
||||
this.session = session;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
PlayerLoaderResponse response = loader.loadPlayer(request.getCredentials());
|
||||
session.handlePlayerLoaderResponse(request, response);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Unable to load player's game.", e);
|
||||
session.handlePlayerLoaderResponse(request, new PlayerLoaderResponse(LoginConstants.STATUS_COULD_NOT_COMPLETE));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.apollo.game.login;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apollo.game.io.player.PlayerSerializer;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.session.GameSession;
|
||||
|
||||
/**
|
||||
* A class which processes a single save request.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class PlayerSaverWorker implements Runnable {
|
||||
|
||||
/**
|
||||
* The logger for this class.
|
||||
*/
|
||||
private static final Logger logger = Logger.getLogger(PlayerSaverWorker.class.getName());
|
||||
|
||||
/**
|
||||
* The player to save.
|
||||
*/
|
||||
private final Player player;
|
||||
|
||||
/**
|
||||
* The player saver.
|
||||
*/
|
||||
private final PlayerSerializer saver;
|
||||
|
||||
/**
|
||||
* The game session.
|
||||
*/
|
||||
private final GameSession session;
|
||||
|
||||
/**
|
||||
* Creates the player saver worker.
|
||||
*
|
||||
* @param saver The player saver.
|
||||
* @param session The game session.
|
||||
* @param player The player to save.
|
||||
*/
|
||||
public PlayerSaverWorker(PlayerSerializer saver, GameSession session, Player player) {
|
||||
this.saver = saver;
|
||||
this.session = session;
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
saver.savePlayer(player);
|
||||
session.handlePlayerSaverResponse(true);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Unable to save player's game.", e);
|
||||
session.handlePlayerSaverResponse(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains classes related to the login service.
|
||||
*/
|
||||
package org.apollo.game.login;
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.ButtonMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that responds to {@link ButtonMessage}s for withdrawing items as notes.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class BankButtonMessageHandler extends MessageHandler<ButtonMessage> {
|
||||
|
||||
/**
|
||||
* Creates the BankButtonMessageHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link ButtonMessage} occurred in.
|
||||
*/
|
||||
public BankButtonMessageHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* The withdraw as item button id.
|
||||
*/
|
||||
private static final int WITHDRAW_AS_ITEM = 5387;
|
||||
|
||||
/**
|
||||
* The withdraw as note button id.
|
||||
*/
|
||||
private static final int WITHDRAW_AS_NOTE = 5386;
|
||||
|
||||
@Override
|
||||
public void handle(Player player, ButtonMessage message) {
|
||||
if (message.getWidgetId() == WITHDRAW_AS_ITEM) {
|
||||
player.setWithdrawingNotes(false);
|
||||
} else if (message.getWidgetId() == WITHDRAW_AS_NOTE) {
|
||||
player.setWithdrawingNotes(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.ItemActionMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.inter.EnterAmountListener;
|
||||
import org.apollo.game.model.inter.bank.BankConstants;
|
||||
import org.apollo.game.model.inter.bank.BankDepositEnterAmountListener;
|
||||
import org.apollo.game.model.inter.bank.BankUtils;
|
||||
import org.apollo.game.model.inter.bank.BankWithdrawEnterAmountListener;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that handles withdrawing and depositing items from/to a player's bank.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class BankMessageHandler extends MessageHandler<ItemActionMessage> {
|
||||
|
||||
/**
|
||||
* Converts an option to an amount.
|
||||
*
|
||||
* @param option The option.
|
||||
* @return The amount.
|
||||
* @throws IllegalArgumentException If the option is invalid.
|
||||
*/
|
||||
private static int optionToAmount(int option) {
|
||||
switch (option) {
|
||||
case 1:
|
||||
return 1;
|
||||
case 2:
|
||||
return 5;
|
||||
case 3:
|
||||
return 10;
|
||||
case 4:
|
||||
return Integer.MAX_VALUE;
|
||||
case 5:
|
||||
return -1;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Invalid option supplied.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the BankMessageHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link ItemActionMessage} occurred in.
|
||||
*/
|
||||
public BankMessageHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, ItemActionMessage message) {
|
||||
if (player.getInterfaceSet().contains(BankConstants.BANK_WINDOW_ID)) {
|
||||
if (message.getInterfaceId() == BankConstants.SIDEBAR_INVENTORY_ID) {
|
||||
deposit(player, message);
|
||||
} else if (message.getInterfaceId() == BankConstants.BANK_INVENTORY_ID) {
|
||||
withdraw(player, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a deposit action.
|
||||
*
|
||||
* @param player The player.
|
||||
* @param message The message.
|
||||
*/
|
||||
private void deposit(Player player, ItemActionMessage message) {
|
||||
int amount = optionToAmount(message.getOption());
|
||||
|
||||
if (amount == -1) {
|
||||
EnterAmountListener listener = new BankDepositEnterAmountListener(player, message.getSlot(), message.getId());
|
||||
player.getInterfaceSet().openEnterAmountDialogue(listener);
|
||||
} else if (!BankUtils.deposit(player, message.getSlot(), message.getId(), amount)) {
|
||||
message.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a withdraw action.
|
||||
*
|
||||
* @param player The player.
|
||||
* @param message The message.
|
||||
*/
|
||||
private void withdraw(Player player, ItemActionMessage message) {
|
||||
int amount = optionToAmount(message.getOption());
|
||||
|
||||
if (amount == -1) {
|
||||
EnterAmountListener listener = new BankWithdrawEnterAmountListener(player, message.getSlot(), message.getId());
|
||||
player.getInterfaceSet().openEnterAmountDialogue(listener);
|
||||
} else if (!BankUtils.withdraw(player, message.getSlot(), message.getId(), amount)) {
|
||||
message.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.ChatMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.sync.block.SynchronizationBlock;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that broadcasts public chat messages.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class ChatMessageHandler extends MessageHandler<ChatMessage> {
|
||||
|
||||
/**
|
||||
* Creates the ChatMessageHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link ChatMessage} occurred in.
|
||||
*/
|
||||
public ChatMessageHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, ChatMessage message) {
|
||||
player.getBlockSet().add(SynchronizationBlock.createChatBlock(player, message));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.ChatMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that verifies {@link ChatMessage}s.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class ChatVerificationHandler extends MessageHandler<ChatMessage> {
|
||||
|
||||
/**
|
||||
* Creates the ChatVerificationHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link ChatMessage} occurred in.
|
||||
*/
|
||||
public ChatVerificationHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, ChatMessage message) {
|
||||
int color = message.getTextColor();
|
||||
int effects = message.getTextEffects();
|
||||
if (color < 0 || color > 11 || effects < 0 || effects > 5) {
|
||||
message.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.ClosedInterfaceMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} for the {@link ClosedInterfaceMessage}.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class ClosedInterfaceMessageHandler extends MessageHandler<ClosedInterfaceMessage> {
|
||||
|
||||
/**
|
||||
* Creates the ClosedInterfaceMessageHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link ClosedInterfaceMessage} occurred in.
|
||||
*/
|
||||
public ClosedInterfaceMessageHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, ClosedInterfaceMessage message) {
|
||||
player.getInterfaceSet().interfaceClosed();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.command.Command;
|
||||
import org.apollo.game.message.impl.CommandMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that dispatches {@link CommandMessage}s.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class CommandMessageHandler extends MessageHandler<CommandMessage> {
|
||||
|
||||
/**
|
||||
* Creates the CommandMessageHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link Message} occurred in.
|
||||
*/
|
||||
public CommandMessageHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, CommandMessage message) {
|
||||
String[] components = message.getCommand().split(" ");
|
||||
String name = components[0];
|
||||
|
||||
String[] arguments = new String[components.length - 1];
|
||||
System.arraycopy(components, 1, arguments, 0, arguments.length);
|
||||
|
||||
Command command = new Command(name, arguments);
|
||||
world.getCommandDispatcher().dispatch(player, command);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.ButtonMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.inter.InterfaceType;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} which intercepts button clicks on dialogues, and forwards the message to the current
|
||||
* listener.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public final class DialogueButtonHandler extends MessageHandler<ButtonMessage> {
|
||||
|
||||
/**
|
||||
* Creates the DialogueButtonHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link ButtonMessage} occurred in.
|
||||
*/
|
||||
public DialogueButtonHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, ButtonMessage message) {
|
||||
if (player.getInterfaceSet().contains(InterfaceType.DIALOGUE)) {
|
||||
boolean terminate = player.getInterfaceSet().buttonClicked(message.getWidgetId());
|
||||
|
||||
if (terminate) {
|
||||
message.terminate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.DialogueContinueMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.inter.InterfaceType;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} for the {@link DialogueContinueMessage}.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public final class DialogueContinueMessageHandler extends MessageHandler<DialogueContinueMessage> {
|
||||
|
||||
/**
|
||||
* Creates the DialogueContinueMessageHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link DialogueContinueMessage} occurred in.
|
||||
*/
|
||||
public DialogueContinueMessageHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, DialogueContinueMessage message) {
|
||||
if (player.getInterfaceSet().contains(InterfaceType.DIALOGUE)) {
|
||||
player.getInterfaceSet().continueRequested();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.EnteredAmountMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} for the {@link EnteredAmountMessage}.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class EnteredAmountMessageHandler extends MessageHandler<EnteredAmountMessage> {
|
||||
|
||||
/**
|
||||
* Creates the EnteredAmountMessageHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link EnteredAmountMessage} occurred in.
|
||||
*/
|
||||
public EnteredAmountMessageHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, EnteredAmountMessage message) {
|
||||
player.getInterfaceSet().enteredAmount(message.getAmount());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.cache.def.EquipmentDefinition;
|
||||
import org.apollo.game.message.impl.ItemOptionMessage;
|
||||
import org.apollo.game.model.Item;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.EquipmentConstants;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.entity.Skill;
|
||||
import org.apollo.game.model.inv.Inventory;
|
||||
import org.apollo.game.model.inv.SynchronizationInventoryListener;
|
||||
import org.apollo.util.LanguageUtil;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that equips items.
|
||||
*
|
||||
* @author Major
|
||||
* @author Graham
|
||||
* @author Ryley
|
||||
*/
|
||||
public final class EquipItemHandler extends MessageHandler<ItemOptionMessage> {
|
||||
|
||||
/**
|
||||
* The option used when equipping an item.
|
||||
*/
|
||||
private static final int EQUIP_OPTION = 2;
|
||||
|
||||
/**
|
||||
* Creates the EquipItemHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link ItemOptionMessage} occurred in.
|
||||
*/
|
||||
public EquipItemHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, ItemOptionMessage message) {
|
||||
if (message.getOption() != EQUIP_OPTION || message.getInterfaceId() != SynchronizationInventoryListener.INVENTORY_ID) {
|
||||
return;
|
||||
}
|
||||
|
||||
int inventorySlot = message.getSlot();
|
||||
Item equipping = player.getInventory().get(inventorySlot);
|
||||
int equippingId = equipping.getId();
|
||||
EquipmentDefinition definition = EquipmentDefinition.lookup(equippingId);
|
||||
|
||||
if (definition == null) {
|
||||
// We don't break the chain here or any item option messages won't work!
|
||||
return;
|
||||
}
|
||||
|
||||
for (int id = 0; id < 5; id++) {
|
||||
int requirement = definition.getLevel(id);
|
||||
|
||||
if (player.getSkillSet().getMaximumLevel(id) < requirement) {
|
||||
String name = Skill.getName(id);
|
||||
String article = LanguageUtil.getIndefiniteArticle(name);
|
||||
|
||||
player.sendMessage("You need " + article + " " + name + " level of " + requirement + " to equip this item.");
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Inventory inventory = player.getInventory();
|
||||
Inventory equipment = player.getEquipment();
|
||||
|
||||
int equipmentSlot = definition.getSlot();
|
||||
|
||||
Item weapon = equipment.get(EquipmentConstants.WEAPON);
|
||||
Item shield = equipment.get(EquipmentConstants.SHIELD);
|
||||
|
||||
// XXX: This is still pretty ugly in some parts, improve.
|
||||
|
||||
if (definition.isTwoHanded()) {
|
||||
int slotsRequired = weapon != null && shield != null ? 1 : 0;
|
||||
if (inventory.freeSlots() < slotsRequired) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset the weapon and the shield slots.
|
||||
equipment.reset(EquipmentConstants.WEAPON);
|
||||
equipment.reset(EquipmentConstants.SHIELD);
|
||||
|
||||
// Set the two-handed weapon and clear it from the inventory.
|
||||
equipment.set(EquipmentConstants.WEAPON, inventory.reset(inventorySlot));
|
||||
|
||||
// Add previous shield or weapon, if present.
|
||||
if (shield != null) {
|
||||
inventory.add(shield);
|
||||
}
|
||||
if (weapon != null) {
|
||||
inventory.add(weapon);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (definition.getSlot() == EquipmentConstants.SHIELD && weapon != null && EquipmentDefinition.lookup(weapon.getId()).isTwoHanded()) {
|
||||
equipment.set(EquipmentConstants.SHIELD, inventory.reset(inventorySlot));
|
||||
inventory.add(equipment.reset(EquipmentConstants.WEAPON));
|
||||
return;
|
||||
}
|
||||
|
||||
Item current = equipment.get(equipmentSlot);
|
||||
|
||||
if (current != null && current.getId() == equipping.getId() && current.getDefinition().isStackable()) {
|
||||
long total = (long) current.getAmount() + equipping.getAmount();
|
||||
|
||||
// If the total has not over flown and we can add to the existing stack, do so.
|
||||
if (total <= Integer.MAX_VALUE && !equipment.add(inventory.reset(inventorySlot)).isPresent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int remaining = (int) (total - Integer.MAX_VALUE);
|
||||
int removed = equipping.getAmount() - remaining;
|
||||
|
||||
if (remaining == equipping.getAmount()) {
|
||||
equipment.set(equipmentSlot, equipping);
|
||||
inventory.set(inventorySlot, current);
|
||||
return;
|
||||
}
|
||||
|
||||
inventory.remove(equipping.getId(), removed);
|
||||
equipment.add(equipping.getId(), removed);
|
||||
return;
|
||||
}
|
||||
|
||||
Item previous = equipment.reset(equipmentSlot);
|
||||
inventory.remove(equipping);
|
||||
equipment.set(equipmentSlot, equipping);
|
||||
|
||||
if (previous != null) {
|
||||
inventory.set(inventorySlot, previous);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.ItemOnItemMessage;
|
||||
import org.apollo.game.model.Item;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.inter.bank.BankConstants;
|
||||
import org.apollo.game.model.inv.Inventory;
|
||||
import org.apollo.game.model.inv.SynchronizationInventoryListener;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that verifies the target item in {@link ItemOnItemMessage}s.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public final class ItemOnItemVerificationHandler extends MessageHandler<ItemOnItemMessage> {
|
||||
|
||||
/**
|
||||
* Creates the ItemOnItemVerificationHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link ItemOnItemMessage} occurred in.
|
||||
*/
|
||||
public ItemOnItemVerificationHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, ItemOnItemMessage message) {
|
||||
Inventory inventory;
|
||||
|
||||
switch (message.getInterfaceId()) {
|
||||
case SynchronizationInventoryListener.INVENTORY_ID:
|
||||
case BankConstants.SIDEBAR_INVENTORY_ID:
|
||||
inventory = player.getInventory();
|
||||
break;
|
||||
case SynchronizationInventoryListener.EQUIPMENT_ID:
|
||||
inventory = player.getEquipment();
|
||||
break;
|
||||
case BankConstants.BANK_INVENTORY_ID:
|
||||
inventory = player.getBank();
|
||||
break;
|
||||
default:
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
int slot = message.getTargetSlot();
|
||||
if (slot < 0 || slot >= inventory.capacity()) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
Item item = inventory.get(slot);
|
||||
if (item == null || item.getId() != message.getTargetId()) {
|
||||
message.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.ItemOnObjectMessage;
|
||||
import org.apollo.game.model.Item;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.inter.bank.BankConstants;
|
||||
import org.apollo.game.model.inv.Inventory;
|
||||
import org.apollo.game.model.inv.SynchronizationInventoryListener;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that verifies {@link ItemOnObjectMessage}s.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class ItemOnObjectVerificationHandler extends MessageHandler<ItemOnObjectMessage> {
|
||||
|
||||
/**
|
||||
* Creates the ItemOnObjectVerificationHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link ItemOnObjectMessage} occurred in.
|
||||
*/
|
||||
public ItemOnObjectVerificationHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, ItemOnObjectMessage message) {
|
||||
if (message.getInterfaceId() != SynchronizationInventoryListener.INVENTORY_ID && message.getInterfaceId() != BankConstants.SIDEBAR_INVENTORY_ID) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
Inventory inventory = player.getInventory();
|
||||
|
||||
int slot = message.getSlot();
|
||||
if (slot < 0 || slot >= inventory.capacity()) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
Item item = inventory.get(slot);
|
||||
if (item == null || item.getId() != message.getId()) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apollo.game.message.impl.InventoryItemMessage;
|
||||
import org.apollo.game.model.Item;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.inter.bank.BankConstants;
|
||||
import org.apollo.game.model.inv.Inventory;
|
||||
import org.apollo.game.model.inv.SynchronizationInventoryListener;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that verifies {@link InventoryItemMessage}s.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
* @author Major
|
||||
*/
|
||||
public final class ItemVerificationHandler extends MessageHandler<InventoryItemMessage> {
|
||||
|
||||
/**
|
||||
* Creates the ItemVerificationHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link InventoryItemMessage} occurred in.
|
||||
*/
|
||||
public ItemVerificationHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
/**
|
||||
* A supplier for an {@link Inventory}.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public static interface InventorySupplier {
|
||||
|
||||
/**
|
||||
* Gets the appropriate {@link Inventory}.
|
||||
*
|
||||
* @param player The {@link Player} who prompted the verification call.
|
||||
* @return The inventory. Must not be {@code null}.
|
||||
*/
|
||||
public Inventory getInventory(Player player);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The map of interface ids to inventories.
|
||||
*/
|
||||
private static final Map<Integer, InventorySupplier> inventories = new HashMap<>();
|
||||
|
||||
static {
|
||||
inventories.put(SynchronizationInventoryListener.INVENTORY_ID, Player::getInventory);
|
||||
inventories.put(BankConstants.SIDEBAR_INVENTORY_ID, Player::getInventory);
|
||||
inventories.put(SynchronizationInventoryListener.EQUIPMENT_ID, Player::getEquipment);
|
||||
inventories.put(BankConstants.BANK_INVENTORY_ID, Player::getBank);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an {@link Inventory} with the specified interface id to the {@link Map} of supported ones,
|
||||
* <strong>iff</strong> the specified id does <strong>not</strong> already have a mapping.
|
||||
*
|
||||
* @param id The id of the interface.
|
||||
* @param supplier The {@link InventorySupplier}.
|
||||
*/
|
||||
public static void addInventory(int id, InventorySupplier supplier) {
|
||||
inventories.putIfAbsent(id, supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, InventoryItemMessage message) {
|
||||
InventorySupplier supplier = inventories.get(message.getInterfaceId());
|
||||
if (supplier == null) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
Inventory inventory = supplier.getInventory(player);
|
||||
|
||||
int slot = message.getSlot();
|
||||
if (slot < 0 || slot >= inventory.capacity()) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
Item item = inventory.get(slot);
|
||||
if (item == null || item.getId() != message.getId()) {
|
||||
message.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* Listens for {@link Message}s received from the client.
|
||||
*
|
||||
* @author Graham
|
||||
* @author Ryley
|
||||
* @param <M> The type of Message this class is listening for.
|
||||
*/
|
||||
public abstract class MessageHandler<M extends Message> {
|
||||
|
||||
/**
|
||||
* The World the Message occurred in.
|
||||
*/
|
||||
protected final World world;
|
||||
|
||||
/**
|
||||
* Creates the MessageListener.
|
||||
*
|
||||
* @param world The {@link World} the {@link Message} occurred in.
|
||||
*/
|
||||
public MessageHandler(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the Message that was received.
|
||||
*
|
||||
* @param player The player to handle the Message for.
|
||||
* @param message The Message.
|
||||
*/
|
||||
public abstract void handle(Player player, M message);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
import com.google.common.base.MoreObjects;
|
||||
|
||||
/**
|
||||
* A chain of {@link MessageHandler}s
|
||||
*
|
||||
* @author Graham
|
||||
* @author Ryley
|
||||
* @param <M> The Message type this chain represents.
|
||||
*/
|
||||
public final class MessageHandlerChain<M extends Message> {
|
||||
|
||||
/**
|
||||
* The handlers.
|
||||
*/
|
||||
private final List<MessageHandler<M>> handlers = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The Class type of this chain.
|
||||
*/
|
||||
private final Class<M> type;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link MessageHandlerChain}.
|
||||
*
|
||||
* @param type The Class type of this chain.
|
||||
*/
|
||||
public MessageHandlerChain(Class<M> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified {@link MessageHandler} to this chain.
|
||||
*
|
||||
* @param handler The MessageHandler.
|
||||
*/
|
||||
public void addHandler(MessageHandler<M> handler) {
|
||||
handlers.add(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies each {@link MessageHandler} in this chain that a {@link Message} has been received.
|
||||
*
|
||||
* @param player The Player to handle this message for.
|
||||
* @param message The Message.
|
||||
* @return {@code true} if and only if the Message propagated down the chain without being terminated, otherwise
|
||||
* {@code false}.
|
||||
*/
|
||||
public boolean notify(Player player, M message) {
|
||||
for (MessageHandler<M> handler : handlers) {
|
||||
handler.handle(player, message);
|
||||
|
||||
if (message.terminated()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this).add("type", type).add("handlers", handlers).toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A group of {@link MessageHandlerChain}s classified by the {@link Message} type.
|
||||
*
|
||||
* @author Graham
|
||||
* @author Ryley
|
||||
* @author Major
|
||||
*/
|
||||
public final class MessageHandlerChainSet {
|
||||
|
||||
/**
|
||||
* The {@link Map} of Message types to {@link MessageHandlerChain}s
|
||||
*/
|
||||
private final Map<Class<? extends Message>, MessageHandlerChain<? extends Message>> chains = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Notifies the appropriate {@link MessageHandlerChain} that a {@link Message} has been received.
|
||||
*
|
||||
* @param player The {@link Player} receiving the Message.
|
||||
* @param message The Message.
|
||||
* @return {@code true} if the Message propagated down the chain without being terminated or if the chain for the
|
||||
* Message was not found, otherwise {@code false}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <M extends Message> boolean notify(Player player, M message) {
|
||||
Class<M> clazz = (Class<M>) message.getClass();
|
||||
while (clazz.getSuperclass() != Message.class) {
|
||||
clazz = (Class<M>) clazz.getSuperclass();
|
||||
}
|
||||
|
||||
MessageHandlerChain<M> chain = (MessageHandlerChain<M>) chains.computeIfAbsent(clazz, MessageHandlerChain::new);
|
||||
return chain.notify(player, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the {@link MessageHandlerChain} into this set.
|
||||
*
|
||||
* @param clazz The {@link Class} to associate the MessageHandlerChain with.
|
||||
* @param handler The MessageHandlerChain.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <M extends Message> void putHandler(Class<M> clazz, MessageHandler<? extends Message> handler) {
|
||||
MessageHandlerChain<M> chain = (MessageHandlerChain<M>) chains.computeIfAbsent(clazz, MessageHandlerChain::new);
|
||||
chain.addHandler((MessageHandler<M>) handler);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.cache.def.NpcDefinition;
|
||||
import org.apollo.game.message.impl.NpcActionMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.MobRepository;
|
||||
import org.apollo.game.model.entity.Npc;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
|
||||
/**
|
||||
* A verification {@link MessageHandler} for the {@link NpcActionMessage}.
|
||||
*
|
||||
* @author Stuart
|
||||
* @author Major
|
||||
*/
|
||||
public final class NpcActionVerificationHandler extends MessageHandler<NpcActionMessage> {
|
||||
|
||||
/**
|
||||
* Creates the NpcActionVerificationHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link NpcActionMessage} occurred in.
|
||||
*/
|
||||
public NpcActionVerificationHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, NpcActionMessage message) {
|
||||
int index = message.getIndex();
|
||||
MobRepository<Npc> repository = world.getNpcRepository();
|
||||
|
||||
if (index < 0 || index >= repository.capacity()) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
Npc npc = repository.get(index);
|
||||
|
||||
if (npc == null || !player.getPosition().isWithinDistance(npc.getPosition(), player.getViewingDistance() + 1)) {
|
||||
// +1 in case it was decremented after the player clicked the action.
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
NpcDefinition definition = npc.getDefinition();
|
||||
if (message.getOption() >= definition.getInteractions().length) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apollo.cache.def.ObjectDefinition;
|
||||
import org.apollo.game.message.impl.ObjectActionMessage;
|
||||
import org.apollo.game.model.Position;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.area.Region;
|
||||
import org.apollo.game.model.entity.EntityType;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.entity.obj.GameObject;
|
||||
|
||||
/**
|
||||
* A verification {@link MessageHandler} for the {@link ObjectActionMessage}.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class ObjectActionVerificationHandler extends MessageHandler<ObjectActionMessage> {
|
||||
|
||||
/**
|
||||
* Indicates whether or not the {@link List} of {@link GameObject}s contains the object with the specified id.
|
||||
*
|
||||
* @param id The id of the object.
|
||||
* @param objects The list of objects.
|
||||
* @return {@code true} if the list does contain the object with the specified id, otherwise {@code false}.
|
||||
*/
|
||||
private static boolean containsObject(int id, Set<GameObject> objects) {
|
||||
return objects.stream().anyMatch(object -> object.getId() == id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the ObjectActionVerificationHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link ObjectActionMessage} occurred in.
|
||||
*/
|
||||
public ObjectActionVerificationHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, ObjectActionMessage message) {
|
||||
int id = message.getId();
|
||||
if (id < 0 || id >= ObjectDefinition.count()) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
Position position = message.getPosition();
|
||||
Region region = world.getRegionRepository().fromPosition(position);
|
||||
Set<GameObject> objects = region.getEntities(position, EntityType.STATIC_OBJECT, EntityType.DYNAMIC_OBJECT);
|
||||
|
||||
if (!player.getPosition().isWithinDistance(position, 15) || !containsObject(id, objects)) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectDefinition definition = ObjectDefinition.lookup(id);
|
||||
if (message.getOption() >= definition.getMenuActions().length) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.PlayerActionMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.MobRepository;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
|
||||
/**
|
||||
* A verification {@link MessageHandler} for the {@link PlayerActionMessage}.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class PlayerActionVerificationHandler extends MessageHandler<PlayerActionMessage> {
|
||||
|
||||
/**
|
||||
* Creates the PlayerActionVerificationHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link PlayerActionMessage} occurred in.
|
||||
*/
|
||||
public PlayerActionVerificationHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, PlayerActionMessage message) {
|
||||
int index = message.getIndex();
|
||||
MobRepository<Player> repository = world.getPlayerRepository();
|
||||
|
||||
if (index < 0 || index >= repository.capacity()) {
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
Player other = repository.get(index);
|
||||
if (other == null || !player.getPosition().isWithinDistance(other.getPosition(), player.getViewingDistance() + 1)) {
|
||||
// +1 in case it was decremented after the player clicked the action.
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.CloseInterfaceMessage;
|
||||
import org.apollo.game.message.impl.PlayerDesignMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that handles {@link PlayerDesignMessage}s.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class PlayerDesignMessageHandler extends MessageHandler<PlayerDesignMessage> {
|
||||
|
||||
/**
|
||||
* Creates the PlayerDesignMessageHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link PlayerDesignMessage} occurred in.
|
||||
*/
|
||||
public PlayerDesignMessageHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, PlayerDesignMessage message) {
|
||||
player.setAppearance(message.getAppearance());
|
||||
player.send(new CloseInterfaceMessage());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.PlayerDesignMessage;
|
||||
import org.apollo.game.model.Appearance;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.entity.setting.Gender;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that verifies {@link PlayerDesignMessage}s.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class PlayerDesignVerificationHandler extends MessageHandler<PlayerDesignMessage> {
|
||||
|
||||
/**
|
||||
* Creates the PlayerDesignVerificationHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link PlayerDesignMessage} occurred in.
|
||||
*/
|
||||
public PlayerDesignVerificationHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, PlayerDesignMessage message) {
|
||||
if (!valid(message.getAppearance())) {
|
||||
message.terminate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an appearance combination is valid.
|
||||
*
|
||||
* @param appearance The appearance combination.
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
private boolean valid(Appearance appearance) {
|
||||
int[] colors = appearance.getColors();
|
||||
int[] maxColors = new int[] { 11, 15, 15, 5, 7 };
|
||||
|
||||
for (int i = 0; i < colors.length; i++) {
|
||||
if (colors[i] < 0 || colors[i] > maxColors[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (appearance.getGender()) {
|
||||
case FEMALE:
|
||||
return validFemaleStyle(appearance);
|
||||
case MALE:
|
||||
return validMaleStyle(appearance);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Player can only be either male or female.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a {@link Gender#FEMALE} style combination is valid.
|
||||
*
|
||||
* @param appearance The appearance combination.
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
private boolean validFemaleStyle(Appearance appearance) {
|
||||
int[] styles = appearance.getStyle();
|
||||
int[] minStyles = new int[] { 45, 255, 56, 61, 67, 70, 79 };
|
||||
int[] maxStyles = new int[] { 54, 255, 60, 65, 68, 77, 80 };
|
||||
|
||||
for (int i = 0; i < styles.length; i++) {
|
||||
if (styles[i] < minStyles[i] || styles[i] > maxStyles[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a {@link Gender#MALE} style combination is valid.
|
||||
*
|
||||
* @param appearance The appearance combination.
|
||||
* @return {@code true} if so, {@code false} if not.
|
||||
*/
|
||||
private boolean validMaleStyle(Appearance appearance) {
|
||||
int[] styles = appearance.getStyle();
|
||||
int[] minStyles = new int[] { 0, 10, 18, 26, 33, 36, 42 };
|
||||
int[] maxStyles = new int[] { 8, 17, 25, 31, 34, 40, 43 };
|
||||
|
||||
for (int i = 0; i < styles.length; i++) {
|
||||
if (styles[i] < minStyles[i] || styles[i] > maxStyles[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.ItemActionMessage;
|
||||
import org.apollo.game.model.Item;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.inv.Inventory;
|
||||
import org.apollo.game.model.inv.SynchronizationInventoryListener;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that removes equipped items.
|
||||
*
|
||||
* @author Graham
|
||||
* @author Major
|
||||
*/
|
||||
public final class RemoveEquippedItemHandler extends MessageHandler<ItemActionMessage> {
|
||||
|
||||
/**
|
||||
* Creates the RemoveEquippedItemHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link ItemActionMessage} occurred in.
|
||||
*/
|
||||
public RemoveEquippedItemHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, ItemActionMessage message) {
|
||||
if (message.getOption() == 1 && message.getInterfaceId() == SynchronizationInventoryListener.EQUIPMENT_ID) {
|
||||
Inventory inventory = player.getInventory();
|
||||
Inventory equipment = player.getEquipment();
|
||||
|
||||
int slot = message.getSlot();
|
||||
Item item = equipment.get(slot);
|
||||
int id = item.getId();
|
||||
|
||||
if (inventory.freeSlots() == 0 && !item.getDefinition().isStackable()) {
|
||||
inventory.forceCapacityExceeded();
|
||||
message.terminate();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean removed = true;
|
||||
|
||||
inventory.stopFiringEvents();
|
||||
equipment.stopFiringEvents();
|
||||
|
||||
try {
|
||||
int remaining = inventory.add(id, item.getAmount());
|
||||
removed = remaining == 0;
|
||||
equipment.set(slot, removed ? null : new Item(id, remaining));
|
||||
} finally {
|
||||
inventory.startFiringEvents();
|
||||
equipment.startFiringEvents();
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
inventory.forceRefresh();
|
||||
equipment.forceRefresh(slot);
|
||||
} else {
|
||||
inventory.forceCapacityExceeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.SwitchItemMessage;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.inter.bank.BankConstants;
|
||||
import org.apollo.game.model.inv.Inventory;
|
||||
import org.apollo.game.model.inv.SynchronizationInventoryListener;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} which updates an {@link Inventory} when the client sends a {@link SwitchItemMessage} to the
|
||||
* server.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class SwitchItemMessageHandler extends MessageHandler<SwitchItemMessage> {
|
||||
|
||||
/**
|
||||
* Creates the SwitchItemMessageHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link SwitchItemMessage} occurred in.
|
||||
*/
|
||||
public SwitchItemMessageHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, SwitchItemMessage message) {
|
||||
Inventory inventory;
|
||||
boolean insertPermitted = false;
|
||||
|
||||
switch (message.getInterfaceId()) {
|
||||
case SynchronizationInventoryListener.INVENTORY_ID:
|
||||
case BankConstants.SIDEBAR_INVENTORY_ID:
|
||||
inventory = player.getInventory();
|
||||
break;
|
||||
case SynchronizationInventoryListener.EQUIPMENT_ID:
|
||||
inventory = player.getEquipment();
|
||||
break;
|
||||
case BankConstants.BANK_INVENTORY_ID:
|
||||
inventory = player.getBank();
|
||||
insertPermitted = true;
|
||||
break;
|
||||
default:
|
||||
return; // not a known inventory, ignore
|
||||
}
|
||||
|
||||
int old = message.getOldSlot(), next = message.getNewSlot();
|
||||
if (old >= 0 && next >= 0 && old < inventory.capacity() && next < inventory.capacity()) {
|
||||
// events must be fired for it to work if a sidebar inventory overlay is used
|
||||
inventory.swap(insertPermitted && message.isInserting(), old, next);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.apollo.game.message.handler;
|
||||
|
||||
import org.apollo.game.message.impl.WalkMessage;
|
||||
import org.apollo.game.model.Position;
|
||||
import org.apollo.game.model.World;
|
||||
import org.apollo.game.model.entity.Player;
|
||||
import org.apollo.game.model.entity.WalkingQueue;
|
||||
|
||||
/**
|
||||
* A {@link MessageHandler} that handles {@link WalkMessage}s.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class WalkMessageHandler extends MessageHandler<WalkMessage> {
|
||||
|
||||
/**
|
||||
* Creates the WalkMessageHandler.
|
||||
*
|
||||
* @param world The {@link World} the {@link WalkMessage} occurred in.
|
||||
*/
|
||||
public WalkMessageHandler(World world) {
|
||||
super(world);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Player player, WalkMessage message) {
|
||||
WalkingQueue queue = player.getWalkingQueue();
|
||||
|
||||
Position[] steps = message.getSteps();
|
||||
for (int index = 0; index < steps.length; index++) {
|
||||
Position step = steps[index];
|
||||
if (index == 0) {
|
||||
if (!queue.addFirstStep(step)) {
|
||||
return; // ignore packet
|
||||
}
|
||||
} else {
|
||||
queue.addStep(step);
|
||||
}
|
||||
}
|
||||
|
||||
queue.setRunningQueue(message.isRunning() || player.isRunning());
|
||||
player.getInterfaceSet().close();
|
||||
|
||||
if (queue.size() > 0) {
|
||||
player.stopAction();
|
||||
}
|
||||
|
||||
if (player.getInteractingMob() != null) {
|
||||
player.resetInteractingMob();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
/**
|
||||
* Contains message handler implementations.
|
||||
*/
|
||||
package org.apollo.game.message.handler;
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client when a player adds someone to their friends list.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class AddFriendMessage extends Message {
|
||||
|
||||
/**
|
||||
* The username of the befriended player.
|
||||
*/
|
||||
private final String username;
|
||||
|
||||
/**
|
||||
* Creates a new befriend user message.
|
||||
*
|
||||
* @param username The befriended player's username.
|
||||
*/
|
||||
public AddFriendMessage(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the username of the befriended player.
|
||||
*
|
||||
* @return The username.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client when a player adds someone to their ignore list.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class AddIgnoreMessage extends Message {
|
||||
|
||||
/**
|
||||
* The username of the ignored player.
|
||||
*/
|
||||
private final String username;
|
||||
|
||||
/**
|
||||
* Creates a new ignore player message.
|
||||
*
|
||||
* @param username The ignored player's username.
|
||||
*/
|
||||
public AddIgnoreMessage(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the username of the ignored player.
|
||||
*
|
||||
* @return The username.
|
||||
*/
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client when the user has pressed an arrow key.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class ArrowKeyMessage extends Message {
|
||||
|
||||
/**
|
||||
* The camera roll.
|
||||
*/
|
||||
private final int roll;
|
||||
|
||||
/**
|
||||
* The camera yaw.
|
||||
*/
|
||||
private final int yaw;
|
||||
|
||||
/**
|
||||
* Creates a new arrow key message.
|
||||
*
|
||||
* @param roll The camera roll.
|
||||
* @param yaw The camera yaw.
|
||||
*/
|
||||
public ArrowKeyMessage(int roll, int yaw) {
|
||||
this.roll = roll;
|
||||
this.yaw = yaw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the roll of the camera.
|
||||
*
|
||||
* @return The roll.
|
||||
*/
|
||||
public int getRoll() {
|
||||
return roll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the yaw of the camera.
|
||||
*
|
||||
* @return The yaw.
|
||||
*/
|
||||
public int getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client when a player clicks a button.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class ButtonMessage extends Message {
|
||||
|
||||
/**
|
||||
* The widget id.
|
||||
*/
|
||||
private final int widgetId;
|
||||
|
||||
/**
|
||||
* Creates the button message.
|
||||
*
|
||||
* @param widgetId The widget id.
|
||||
*/
|
||||
public ButtonMessage(int widgetId) {
|
||||
this.widgetId = widgetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the widget id.
|
||||
*
|
||||
* @return The widget id.
|
||||
*/
|
||||
public int getWidgetId() {
|
||||
return widgetId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client to send a public chat message to other players.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class ChatMessage extends Message {
|
||||
|
||||
/**
|
||||
* The text color.
|
||||
*/
|
||||
private final int color;
|
||||
|
||||
/**
|
||||
* The compressed message.
|
||||
*/
|
||||
private final byte[] compressedMessage;
|
||||
|
||||
/**
|
||||
* The text effects.
|
||||
*/
|
||||
private final int effects;
|
||||
|
||||
/**
|
||||
* The message.
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
/**
|
||||
* Creates a new chat message.
|
||||
*
|
||||
* @param message The message.
|
||||
* @param compressedMessage The compressed message.
|
||||
* @param color The text color.
|
||||
* @param effects The text effects.
|
||||
*/
|
||||
public ChatMessage(String message, byte[] compressedMessage, int color, int effects) {
|
||||
this.message = message;
|
||||
this.compressedMessage = compressedMessage;
|
||||
this.color = color;
|
||||
this.effects = effects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the compressed message.
|
||||
*
|
||||
* @return The compressed message.
|
||||
*/
|
||||
public byte[] getCompressedMessage() {
|
||||
return compressedMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the message.
|
||||
*
|
||||
* @return The message.
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text color.
|
||||
*
|
||||
* @return The text color.
|
||||
*/
|
||||
public int getTextColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text effects.
|
||||
*
|
||||
* @return The text effects.
|
||||
*/
|
||||
public int getTextEffects() {
|
||||
return effects;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.game.model.Position;
|
||||
import org.apollo.game.model.area.RegionCoordinates;
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent to the client to remove all spawned objects and items from a Region.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class ClearRegionMessage extends Message {
|
||||
|
||||
/**
|
||||
* The Position of the Player.
|
||||
*/
|
||||
private final Position player;
|
||||
|
||||
/**
|
||||
* The Position in the Region being cleared.
|
||||
*/
|
||||
private final Position region;
|
||||
|
||||
/**
|
||||
* Creates the ClearRegionMessage.
|
||||
*
|
||||
* @param player The {@link Position} of the Player this {@link Message} is being sent to.
|
||||
* @param region The {@link RegionCoordinates} of the Region being cleared.
|
||||
*/
|
||||
public ClearRegionMessage(Position player, RegionCoordinates region) {
|
||||
this.player = player;
|
||||
this.region = new Position(region.getAbsoluteX(), region.getAbsoluteY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Position} of the Player this {@link Message} is being sent to..
|
||||
*
|
||||
* @return The Position.
|
||||
*/
|
||||
public Position getPlayerPosition() {
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Position} of the Region being cleared.
|
||||
*
|
||||
* @return The Position.
|
||||
*/
|
||||
public Position getRegionPosition() {
|
||||
return region;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent to the client that closes the open interface.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class CloseInterfaceMessage extends Message {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client when the current interface is closed.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class ClosedInterfaceMessage extends Message {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client to send a {@code ::} command.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class CommandMessage extends Message {
|
||||
|
||||
/**
|
||||
* The command.
|
||||
*/
|
||||
private final String command;
|
||||
|
||||
/**
|
||||
* Creates the command message.
|
||||
*
|
||||
* @param command The command.
|
||||
*/
|
||||
public CommandMessage(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the command.
|
||||
*
|
||||
* @return The command.
|
||||
*/
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent to the client to adjust a certain config or attribute setting.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public final class ConfigMessage extends Message {
|
||||
|
||||
/**
|
||||
* The identifier.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
private final int value;
|
||||
|
||||
/**
|
||||
* Creates a new config message.
|
||||
*
|
||||
* @param id The config's identifier.
|
||||
* @param value The value.
|
||||
*/
|
||||
public ConfigMessage(int id, int value) {
|
||||
this.id = id;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the config's identifier.
|
||||
*
|
||||
* @return The config id.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the config's value.
|
||||
*
|
||||
* @return The config value.
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client when the player clicks the "Click here to continue" button on a dialogue
|
||||
* interface.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public final class DialogueContinueMessage extends Message {
|
||||
|
||||
/**
|
||||
* The interface id.
|
||||
*/
|
||||
private final int interfaceId;
|
||||
|
||||
/**
|
||||
* Creates a new dialogue continue message.
|
||||
*
|
||||
* @param interfaceId The interface id.
|
||||
*/
|
||||
public DialogueContinueMessage(int interfaceId) {
|
||||
this.interfaceId = interfaceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the interface id of the button.
|
||||
*
|
||||
* @return The interface id.
|
||||
*/
|
||||
public int getInterfaceId() {
|
||||
return interfaceId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent to the client to display crossbones when the player enters a multi-combat zone.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class DisplayCrossbonesMessage extends Message {
|
||||
|
||||
/**
|
||||
* Whether or not the crossbones should be displayed.
|
||||
*/
|
||||
private final boolean display;
|
||||
|
||||
/**
|
||||
* Creates a display crossbones message.
|
||||
*
|
||||
* @param display Whether or not the crossbones should be displayed.
|
||||
*/
|
||||
public DisplayCrossbonesMessage(boolean display) {
|
||||
this.display = display;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the crossbones will be displayed.
|
||||
*
|
||||
* @return {@code true} if the crossbones will be displayed, otherwise {@code false}.
|
||||
*/
|
||||
public boolean isDisplayed() {
|
||||
return display;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent to the client to change the currently displayed tab interface.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public final class DisplayTabInterfaceMessage extends Message {
|
||||
|
||||
/**
|
||||
* The tab index.
|
||||
*/
|
||||
private final int tab;
|
||||
|
||||
/**
|
||||
* Creates a new display tab interface message.
|
||||
*
|
||||
* @param tab The index of the tab to display.
|
||||
*/
|
||||
public DisplayTabInterfaceMessage(int tab) {
|
||||
this.tab = tab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the tab to display.
|
||||
*
|
||||
* @return The tab index.
|
||||
*/
|
||||
public int getTab() {
|
||||
return tab;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent to the client to open up the enter amount interface.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class EnterAmountMessage extends Message {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client when the player has entered an amount.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class EnteredAmountMessage extends Message {
|
||||
|
||||
/**
|
||||
* The amount.
|
||||
*/
|
||||
private final int amount;
|
||||
|
||||
/**
|
||||
* Creates the entered amount message.
|
||||
*
|
||||
* @param amount The amount.
|
||||
*/
|
||||
public EnteredAmountMessage(int amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount.
|
||||
*
|
||||
* @return The amount.
|
||||
*/
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* The fifth {@link ItemActionMessage}.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class FifthItemActionMessage extends ItemActionMessage {
|
||||
|
||||
/**
|
||||
* Creates the fifth item action message.
|
||||
*
|
||||
* @param interfaceId The interface id.
|
||||
* @param id The item id.
|
||||
* @param slot The item slot.
|
||||
*/
|
||||
public FifthItemActionMessage(int interfaceId, int id, int slot) {
|
||||
super(5, interfaceId, id, slot);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* The fifth {@link ItemOptionMessage}.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public final class FifthItemOptionMessage extends ItemOptionMessage {
|
||||
|
||||
/**
|
||||
* Creates the fifth item option message.
|
||||
*
|
||||
* @param interfaceId The interface id.
|
||||
* @param id The id.
|
||||
* @param slot The slot.
|
||||
*/
|
||||
public FifthItemOptionMessage(int interfaceId, int id, int slot) {
|
||||
super(5, interfaceId, id, slot);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* The fifth {@link NpcActionMessage}.
|
||||
*
|
||||
* @author Major
|
||||
* @author Stuart
|
||||
*/
|
||||
public final class FifthNpcActionMessage extends NpcActionMessage {
|
||||
|
||||
/**
|
||||
* Creates the FifthNpcActionMessage.
|
||||
*
|
||||
* @param index The index of the Npc.
|
||||
*/
|
||||
public FifthNpcActionMessage(int index) {
|
||||
super(5, index);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* The fifth {@link PlayerActionMessage}.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class FifthPlayerActionMessage extends PlayerActionMessage {
|
||||
|
||||
/**
|
||||
* Creates a fifth player action message.
|
||||
*
|
||||
* @param playerIndex The index of the clicked player.
|
||||
*/
|
||||
public FifthPlayerActionMessage(int playerIndex) {
|
||||
super(5, playerIndex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* The first {@link ItemActionMessage}.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class FirstItemActionMessage extends ItemActionMessage {
|
||||
|
||||
/**
|
||||
* Creates the first item action message.
|
||||
*
|
||||
* @param interfaceId The interface id.
|
||||
* @param id The item id.
|
||||
* @param slot The item slot.
|
||||
*/
|
||||
public FirstItemActionMessage(int interfaceId, int id, int slot) {
|
||||
super(1, interfaceId, id, slot);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* The first {@link ItemOptionMessage}.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public final class FirstItemOptionMessage extends ItemOptionMessage {
|
||||
|
||||
/**
|
||||
* Creates the first item option message.
|
||||
*
|
||||
* @param interfaceId The interface id.
|
||||
* @param id The id.
|
||||
* @param slot The slot.
|
||||
*/
|
||||
public FirstItemOptionMessage(int interfaceId, int id, int slot) {
|
||||
super(1, interfaceId, id, slot);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* The first {@link NpcActionMessage}.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class FirstNpcActionMessage extends NpcActionMessage {
|
||||
|
||||
/**
|
||||
* Creates a new first npc action message.
|
||||
*
|
||||
* @param index The index of the npc.
|
||||
*/
|
||||
public FirstNpcActionMessage(int index) {
|
||||
super(1, index);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.game.model.Position;
|
||||
|
||||
/**
|
||||
* The first {@link ObjectActionMessage}.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class FirstObjectActionMessage extends ObjectActionMessage {
|
||||
|
||||
/**
|
||||
* Creates the first object action message.
|
||||
*
|
||||
* @param id The id.
|
||||
* @param position The position.
|
||||
*/
|
||||
public FirstObjectActionMessage(int id, Position position) {
|
||||
super(1, id, position);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* The first {@link PlayerActionMessage}.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class FirstPlayerActionMessage extends PlayerActionMessage {
|
||||
|
||||
/**
|
||||
* Creates a first player action message.
|
||||
*
|
||||
* @param playerIndex The index of the clicked player.
|
||||
*/
|
||||
public FirstPlayerActionMessage(int playerIndex) {
|
||||
super(1, playerIndex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client when the player clicks with their mouse (or mousekeys etc).
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class FlaggedMouseEventMessage extends Message {
|
||||
|
||||
/**
|
||||
* The number of clicks on this point (i.e. the point ({@link #x}, {@link #y})).
|
||||
*/
|
||||
private final int clickCount;
|
||||
|
||||
/**
|
||||
* The x coordinate of the mouse click.
|
||||
*/
|
||||
private final int x;
|
||||
|
||||
/**
|
||||
* The y coordinate of the mouse click.
|
||||
*/
|
||||
private final int y;
|
||||
|
||||
/**
|
||||
* Indicates whether the {@link #x} and {@link #y} values represent the deviation from the last click or an actual
|
||||
* point.
|
||||
*/
|
||||
private final boolean delta;
|
||||
|
||||
/**
|
||||
* Creates a new mouse click message.
|
||||
*
|
||||
* @param clickCount The number of clicks on this point.
|
||||
* @param x The x coordinate of the mouse click.
|
||||
* @param y The y coordinate of the mouse click.
|
||||
* @param delta If the coordinates represent a change in x/y, rather than the values themselves.
|
||||
*/
|
||||
public FlaggedMouseEventMessage(int clickCount, int x, int y, boolean delta) {
|
||||
this.clickCount = clickCount;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.delta = delta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of clicks on this point - maximum value of 2047.
|
||||
*
|
||||
* @return The number of clicks.
|
||||
*/
|
||||
public int getClickCount() {
|
||||
return clickCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* The x coordinate of the click.
|
||||
*
|
||||
* @return The x coordinate.
|
||||
*/
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* The y coordinate of the click.
|
||||
*
|
||||
* @return The y coordinate.
|
||||
*/
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value indicating whether the {@link #x} and {@link #y} values represent the deviation from the last
|
||||
* click or an actual point.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
public boolean getDelta() {
|
||||
return delta;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent to the client to
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class FlashTabInterfaceMessage extends Message {
|
||||
|
||||
/**
|
||||
* The id of the tab to flash.
|
||||
*/
|
||||
private final int tab;
|
||||
|
||||
/**
|
||||
* Creates the FlashTabInterfaceMessage.
|
||||
*
|
||||
* @param tab The id of the tab to flash.
|
||||
*/
|
||||
public FlashTabInterfaceMessage(int tab) {
|
||||
this.tab = tab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id of the tab to flash.
|
||||
*
|
||||
* @return The id.
|
||||
*/
|
||||
public int getTab() {
|
||||
return tab;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client indicating a flashing tab has been clicked.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class FlashingTabClickedMessage extends Message {
|
||||
|
||||
/**
|
||||
* The tab that was clicked.
|
||||
*/
|
||||
private final int tab;
|
||||
|
||||
/**
|
||||
* Creates the FlashingTabClickedMessage.
|
||||
*
|
||||
* @param tab The tab that was clicked.
|
||||
*/
|
||||
public FlashingTabClickedMessage(int tab) {
|
||||
this.tab = tab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the tab that was clicked.
|
||||
*
|
||||
* @return The tab index.
|
||||
*/
|
||||
public int getTab() {
|
||||
return tab;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client to indicate a change in the client's focus (i.e. if it is the active window).
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class FocusUpdateMessage extends Message {
|
||||
|
||||
/**
|
||||
* Indicates whether the client is focused or not.
|
||||
*/
|
||||
private final boolean focused;
|
||||
|
||||
/**
|
||||
* Creates a new focus update message.
|
||||
*
|
||||
* @param focused The data received.
|
||||
*/
|
||||
public FocusUpdateMessage(boolean focused) {
|
||||
this.focused = focused;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether or not the client is focused.
|
||||
*
|
||||
* @return {@code true} if the client is focused, otherwise {@code false}.
|
||||
*/
|
||||
public boolean isFocused() {
|
||||
return focused;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.game.model.entity.setting.PrivilegeLevel;
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent to the client that forwards a private chat.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class ForwardPrivateChatMessage extends Message {
|
||||
|
||||
/**
|
||||
* The username of the player sending the message.
|
||||
*/
|
||||
private final String username;
|
||||
|
||||
/**
|
||||
* The privilege level of the player.
|
||||
*/
|
||||
private final PrivilegeLevel privilege;
|
||||
|
||||
/**
|
||||
* The message.
|
||||
*/
|
||||
private final byte[] message;
|
||||
|
||||
/**
|
||||
* Creates a new forward private message message.
|
||||
*
|
||||
* @param username The username of the player sending the message.
|
||||
* @param level The {@link PrivilegeLevel} of the player sending the message.
|
||||
* @param message The compressed message.
|
||||
*/
|
||||
public ForwardPrivateChatMessage(String username, PrivilegeLevel level, byte[] message) {
|
||||
this.username = username;
|
||||
privilege = level;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the username of the sender.
|
||||
*
|
||||
* @return The username.
|
||||
*/
|
||||
public String getSenderUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link PrivilegeLevel} of the sender.
|
||||
*
|
||||
* @return The privilege level.
|
||||
*/
|
||||
public PrivilegeLevel getSenderPrivilege() {
|
||||
return privilege;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the compressed message.
|
||||
*
|
||||
* @return The message.
|
||||
*/
|
||||
public byte[] getCompressedMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* The fourth {@link ItemActionMessage}.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class FourthItemActionMessage extends ItemActionMessage {
|
||||
|
||||
/**
|
||||
* Creates the fourth item action message.
|
||||
*
|
||||
* @param interfaceId The interface id.
|
||||
* @param id The item id.
|
||||
* @param slot The item slot.
|
||||
*/
|
||||
public FourthItemActionMessage(int interfaceId, int id, int slot) {
|
||||
super(4, interfaceId, id, slot);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* The fourth {@link ItemOptionMessage}.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public final class FourthItemOptionMessage extends ItemOptionMessage {
|
||||
|
||||
/**
|
||||
* Creates the fourth item option message.
|
||||
*
|
||||
* @param interfaceId The interface id.
|
||||
* @param id The id.
|
||||
* @param slot The slot.
|
||||
*/
|
||||
public FourthItemOptionMessage(int interfaceId, int id, int slot) {
|
||||
super(4, interfaceId, id, slot);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* The fourth {@link NpcActionMessage}.
|
||||
*
|
||||
* @author Major
|
||||
* @author Stuart
|
||||
*/
|
||||
public final class FourthNpcActionMessage extends NpcActionMessage {
|
||||
|
||||
/**
|
||||
* Creates the FourthNpcActionMessage.
|
||||
*
|
||||
* @param index The index of the Npc.
|
||||
*/
|
||||
public FourthNpcActionMessage(int index) {
|
||||
super(4, index);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* The fourth {@link PlayerActionMessage}.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class FourthPlayerActionMessage extends PlayerActionMessage {
|
||||
|
||||
/**
|
||||
* Creates a fourth player action message.
|
||||
*
|
||||
* @param playerIndex The index of the clicked player.
|
||||
*/
|
||||
public FourthPlayerActionMessage(int playerIndex) {
|
||||
super(4, playerIndex);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.game.model.entity.setting.ServerStatus;
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent to the client to update the friend server status.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class FriendServerStatusMessage extends Message {
|
||||
|
||||
/**
|
||||
* The status code of the friend server.
|
||||
*/
|
||||
private final int status;
|
||||
|
||||
/**
|
||||
* Creates a new friend server status message.
|
||||
*
|
||||
* @param status The status.
|
||||
*/
|
||||
public FriendServerStatusMessage(ServerStatus status) {
|
||||
this.status = status.getCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the status code of the friend server.
|
||||
*
|
||||
* @return The status code.
|
||||
*/
|
||||
public int getStatusCode() {
|
||||
return status;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apollo.game.model.Position;
|
||||
import org.apollo.game.model.area.RegionCoordinates;
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent to the client that contains multiple
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class GroupedRegionUpdateMessage extends Message {
|
||||
|
||||
/**
|
||||
* The last known region Position of the Player.
|
||||
*/
|
||||
private final Position lastKnownRegion;
|
||||
|
||||
/**
|
||||
* The Position of the Region being updated.
|
||||
*/
|
||||
private final Position region;
|
||||
|
||||
/**
|
||||
* The List of RegionUpdateMessages to be sent.
|
||||
*/
|
||||
private final List<RegionUpdateMessage> messages;
|
||||
|
||||
/**
|
||||
* Creates the GroupedRegionUpdateMessage.
|
||||
*
|
||||
* @param lastKnownRegion The last known region {@link Position} of the Player.
|
||||
* @param coordinates The {@link RegionCoordinates} of the Region being updated.
|
||||
* @param messages The {@link List} of {@link RegionUpdateMessage}s.
|
||||
*/
|
||||
public GroupedRegionUpdateMessage(Position lastKnownRegion, RegionCoordinates coordinates, List<RegionUpdateMessage> messages) {
|
||||
this.lastKnownRegion = lastKnownRegion;
|
||||
region = new Position(coordinates.getAbsoluteX(), coordinates.getAbsoluteY());
|
||||
this.messages = messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Position} of the Player.
|
||||
*
|
||||
* @return The Position.
|
||||
*/
|
||||
public Position getLastKnownRegion() {
|
||||
return lastKnownRegion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link List} of {@link RegionUpdateMessage}s.
|
||||
*
|
||||
* @return The Collection.
|
||||
*/
|
||||
public List<RegionUpdateMessage> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Position} of the Region these updates affect.
|
||||
*
|
||||
* @return The Position.
|
||||
*/
|
||||
public Position getRegionPosition() {
|
||||
return region;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
import org.apollo.game.model.Position;
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} that displays a hint icon over an Npc, tile, or player.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class HintIconMessage extends Message {
|
||||
|
||||
// TODO identify the other types.
|
||||
|
||||
/**
|
||||
* The type of a HintIcon.
|
||||
*/
|
||||
public enum Type {
|
||||
|
||||
/**
|
||||
* A HintIcon that hovers over an Npc.
|
||||
*/
|
||||
NPC(1),
|
||||
|
||||
/**
|
||||
* A HintIcon that hovers over a Player.
|
||||
*/
|
||||
PLAYER(10);
|
||||
|
||||
/**
|
||||
* The integer value of this type.
|
||||
*/
|
||||
private final int value;
|
||||
|
||||
/**
|
||||
* Creates the Type.
|
||||
*
|
||||
* @param value The value.
|
||||
*/
|
||||
private Type(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of this type.
|
||||
*
|
||||
* @return The value.
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a HintIconMessage for the Npc with the specified index.
|
||||
*
|
||||
* @param index The index of the Npc.
|
||||
* @return The HintIconMessage.
|
||||
*/
|
||||
public static HintIconMessage forNpc(int index) {
|
||||
return new HintIconMessage(Type.NPC, OptionalInt.of(index), Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a HintIconMessage for the Player with the specified index.
|
||||
*
|
||||
* @param index The index of the Player.
|
||||
* @return The HintIconMessage.
|
||||
*/
|
||||
public static HintIconMessage forPlayer(int index) {
|
||||
return new HintIconMessage(Type.PLAYER, OptionalInt.of(index), Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a HintIconMessage that removes the current Npc hint icon.
|
||||
*
|
||||
* @return The HintIconMessage.
|
||||
*/
|
||||
public static HintIconMessage resetNpc() {
|
||||
return forNpc(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a HintIconMessage that removes the current Player hint icon.
|
||||
*
|
||||
* @return The HintIconMessage.
|
||||
*/
|
||||
public static HintIconMessage resetPlayer() {
|
||||
return forPlayer(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The index of the Mob, if applicable.
|
||||
*/
|
||||
private final OptionalInt index;
|
||||
|
||||
/**
|
||||
* The Position of the tile, if applicable.
|
||||
*/
|
||||
private final Optional<Position> position;
|
||||
|
||||
/**
|
||||
* The Type of entity this HintIconMessage is directed at.
|
||||
*/
|
||||
private final Type type;
|
||||
|
||||
/**
|
||||
* Creates the HintIconMessage.
|
||||
*
|
||||
* @param type The {@link Type} of this HintIconMessage.
|
||||
* @param index The index of the Mob, if applicable.
|
||||
* @param position The Position of the tile, if applicable.
|
||||
*/
|
||||
private HintIconMessage(Type type, OptionalInt index, Optional<Position> position) {
|
||||
this.type = type;
|
||||
this.index = index;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the entity, if applicable.
|
||||
*
|
||||
* @return The index.
|
||||
* @throws NoSuchElementException If no index is available for this HintIcon.
|
||||
*/
|
||||
public int getIndex() {
|
||||
return index.getAsInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link Position} of the tile, if applicable.
|
||||
*
|
||||
* @return The Position.
|
||||
* @throws NoSuchElementException If no Position is available for this HintIcon.
|
||||
*/
|
||||
public Position getPosition() {
|
||||
return position.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type this HintIconMessage is directed at.
|
||||
*
|
||||
* @return The type.
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.game.model.entity.setting.MembershipStatus;
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent to the client that specifies the local id and membership status of the current player.
|
||||
*
|
||||
* @author Graham
|
||||
*/
|
||||
public final class IdAssignmentMessage extends Message {
|
||||
|
||||
/**
|
||||
* The id of this player.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* The MembershipStatus.
|
||||
*/
|
||||
private final MembershipStatus members;
|
||||
|
||||
/**
|
||||
* Creates the local id message.
|
||||
*
|
||||
* @param id The id.
|
||||
* @param members The MembershipStatus.
|
||||
*/
|
||||
public IdAssignmentMessage(int id, MembershipStatus members) {
|
||||
this.id = id;
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id.
|
||||
*
|
||||
* @return The id.
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether or not the Player is a {@link MembershipStatus#PAID paying member}.
|
||||
*
|
||||
* @return {@code true} if the Player is a paying member, {@code false} if not.
|
||||
*/
|
||||
public boolean isMembers() {
|
||||
return members == MembershipStatus.PAID;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent to the client that updates the ignored user list.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class IgnoreListMessage extends Message {
|
||||
|
||||
/**
|
||||
* The list of ignored player usernames.
|
||||
*/
|
||||
private final List<String> usernames;
|
||||
|
||||
/**
|
||||
* Creates a new ignore list message.
|
||||
*
|
||||
* @param usernames The {@link List} of usernames to send.
|
||||
*/
|
||||
public IgnoreListMessage(List<String> usernames) {
|
||||
this.usernames = usernames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of ignored usernames.
|
||||
*
|
||||
* @return The usernames.
|
||||
*/
|
||||
public List<String> getUsernames() {
|
||||
return usernames;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} that represents some sort of action on an item in an inventory. Note that this is the parent of
|
||||
* both item option and item action message, and so cannot be used to determine when one of those messages is fired.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public abstract class InventoryItemMessage extends Message {
|
||||
|
||||
/**
|
||||
* The item id.
|
||||
*/
|
||||
private final int id;
|
||||
|
||||
/**
|
||||
* The interface id.
|
||||
*/
|
||||
private final int interfaceId;
|
||||
|
||||
/**
|
||||
* The option number (1-5).
|
||||
*/
|
||||
private final int option;
|
||||
|
||||
/**
|
||||
* The item's slot.
|
||||
*/
|
||||
private final int slot;
|
||||
|
||||
/**
|
||||
* Creates the item action message.
|
||||
*
|
||||
* @param option The option number.
|
||||
* @param interfaceId The interface id.
|
||||
* @param id The id.
|
||||
* @param slot The slot.
|
||||
*/
|
||||
protected InventoryItemMessage(int option, int interfaceId, int id, int slot) {
|
||||
this.option = option;
|
||||
this.interfaceId = interfaceId;
|
||||
this.id = id;
|
||||
this.slot = slot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the item id.
|
||||
*
|
||||
* @return The item id.
|
||||
*/
|
||||
public final int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the interface id.
|
||||
*
|
||||
* @return The interface id.
|
||||
*/
|
||||
public final int getInterfaceId() {
|
||||
return interfaceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the option number.
|
||||
*
|
||||
* @return The option number.
|
||||
*/
|
||||
public final int getOption() {
|
||||
return option;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the slot.
|
||||
*
|
||||
* @return The slot.
|
||||
*/
|
||||
public final int getSlot() {
|
||||
return slot;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client that represents some sort of action on an item. Note that the actual message
|
||||
* sent by the client is one of the five item action messages, but this is the message that should be intercepted (and
|
||||
* the option verified).
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public abstract class ItemActionMessage extends InventoryItemMessage {
|
||||
|
||||
/**
|
||||
* Creates the item action message.
|
||||
*
|
||||
* @param option The option number.
|
||||
* @param interfaceId The interface id.
|
||||
* @param id The id.
|
||||
* @param slot The slot.
|
||||
*/
|
||||
public ItemActionMessage(int option, int interfaceId, int id, int slot) {
|
||||
super(option, interfaceId, id, slot);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* A {@link InventoryItemMessage} sent by the client when a player uses one inventory item on another.
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public final class ItemOnItemMessage extends InventoryItemMessage {
|
||||
|
||||
/**
|
||||
* The id of the target item.
|
||||
*/
|
||||
private final int targetId;
|
||||
|
||||
/**
|
||||
* The interface id of the target item.
|
||||
*/
|
||||
private final int targetInterface;
|
||||
|
||||
/**
|
||||
* The slot of the target item.
|
||||
*/
|
||||
private final int targetSlot;
|
||||
|
||||
/**
|
||||
* Creates a new item-on-item message.
|
||||
*
|
||||
* @param usedInterface The interface id of the used item.
|
||||
* @param usedId The id of the used item.
|
||||
* @param usedSlot The slot of the target item.
|
||||
* @param targetInterface The interface id of the target item.
|
||||
* @param targetId The id of the target item.
|
||||
* @param targetSlot The slot of the target item.
|
||||
*/
|
||||
public ItemOnItemMessage(int usedInterface, int usedId, int usedSlot, int targetInterface, int targetId, int targetSlot) {
|
||||
super(0, usedInterface, usedId, usedSlot);
|
||||
this.targetInterface = targetInterface;
|
||||
this.targetSlot = targetSlot;
|
||||
this.targetId = targetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id of the target item.
|
||||
*
|
||||
* @return The target item's interface id.
|
||||
*/
|
||||
public int getTargetId() {
|
||||
return targetId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the interface id of the target item.
|
||||
*
|
||||
* @return The target item's interface id.
|
||||
*/
|
||||
public int getTargetInterfaceId() {
|
||||
return targetInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the slot of the target item.
|
||||
*
|
||||
* @return The slot of the target item.
|
||||
*/
|
||||
public int getTargetSlot() {
|
||||
return targetSlot;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
import org.apollo.game.model.Position;
|
||||
import org.apollo.net.message.Message;
|
||||
|
||||
/**
|
||||
* A {@link Message} sent by the client when an item is used on an object.
|
||||
*
|
||||
* @author Major
|
||||
*/
|
||||
public final class ItemOnObjectMessage extends InventoryItemMessage {
|
||||
|
||||
/**
|
||||
* The object id the item was used on.
|
||||
*/
|
||||
private final int objectId;
|
||||
|
||||
/**
|
||||
* The position of the object.
|
||||
*/
|
||||
private final Position position;
|
||||
|
||||
/**
|
||||
* Creates an item on object message.
|
||||
*
|
||||
* @param interfaceId The interface id.
|
||||
* @param itemId The item id.
|
||||
* @param itemSlot The slot the item is in.
|
||||
* @param objectId The object id.
|
||||
* @param x The x coordinate.
|
||||
* @param y The y coordinate.
|
||||
*/
|
||||
public ItemOnObjectMessage(int interfaceId, int itemId, int itemSlot, int objectId, int x, int y) {
|
||||
super(0, interfaceId, itemId, itemSlot);
|
||||
this.objectId = objectId;
|
||||
position = new Position(x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the object id.
|
||||
*
|
||||
* @return The object id.
|
||||
*/
|
||||
public int getObjectId() {
|
||||
return objectId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the position of the object.
|
||||
*
|
||||
* @return The position.
|
||||
*/
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package org.apollo.game.message.impl;
|
||||
|
||||
/**
|
||||
* An {@link InventoryItemMessage} sent by the client when an item's option is clicked (e.g. equip, eat, drink, etc).
|
||||
* Note that the actual message sent by the client is one of the five item option messages, but this is the message that
|
||||
* should be intercepted (and the option verified).
|
||||
*
|
||||
* @author Chris Fletcher
|
||||
*/
|
||||
public abstract class ItemOptionMessage extends InventoryItemMessage {
|
||||
|
||||
/**
|
||||
* Creates the item option message.
|
||||
*
|
||||
* @param option The option number.
|
||||
* @param interfaceId The interface id.
|
||||
* @param id The id.
|
||||
* @param slot The slot.
|
||||
*/
|
||||
public ItemOptionMessage(int option, int interfaceId, int id, int slot) {
|
||||
super(option, interfaceId, id, slot);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user