mirror of
https://gitlab.com/2009scape/2009scape.git
synced 2025-12-09 16:45:44 -07:00
Added initial version
This commit is contained in:
commit
b452bd670c
13290 changed files with 1178433 additions and 0 deletions
12
CONTRIBUTING.md
Normal file
12
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
### Pull Requests
|
||||
* Pull Requests should ALWAYS be made into the development branch and ONLY the development branch.
|
||||
* Please try to include as much detail as you can/follow the template provided for pull requests.
|
||||
|
||||
### Code Guidelines
|
||||
* ALL new code MUST be Kotlin. The only exception is when modifying old java files, in which case we would still *prefer* that it be converted to Kotlin if possible.
|
||||
* Code must be clean
|
||||
* You must include a javadoc-style comment at the top of each file stating the file's purpose and your @author tag. Ex: @author Ceikry
|
||||
* If you are making significant changes to a file that already has a tagged author, add yours below theirs.
|
||||
* If you are completely rewriting a file, you may replace the @author tag with your own. Rewrites should only be done when the resulting improvements are significant.
|
||||
* If you come across a file without a mentioned @author, it's a safe bet that it was written by Ceikry. Feel free to add his @author tag to that file.
|
||||
* You are responsible for the bugs your code causes. If your code results in a bug, you are expected to fix it yourself.
|
||||
54
FishingTrawlerSoloGuide.md
Normal file
54
FishingTrawlerSoloGuide.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
## Fishing Trawler Solo-player Guide
|
||||
### Notes
|
||||
* You require level 15 fishing to play this minigame.
|
||||
* This minigame is not 100% authentic.
|
||||
|
||||
### Inventory Setup
|
||||
<img src="fishing-trawler-inventory.png"/>
|
||||
|
||||
* 100-200 Swamp Paste
|
||||
* 3-4 Bailing Buckets
|
||||
* 12-16 Ropes
|
||||
|
||||
### Playing the game
|
||||
When you first start the game you'll be prompted with a brief tutorial telling you <br/>
|
||||
what each item does. You should plug leaks as fast as possible as the boat <br/>
|
||||
can fill with water very quickly. Occasionally, the net will rip. Go on the top deck <br/>
|
||||
and inspect the net in order to repair it. If your net is good and all leaks <br/>
|
||||
are already plugged, spam click your bailing buckets to remove water as fast as <br/>
|
||||
possible.
|
||||
|
||||
### Rewards
|
||||
Our fishing trawler has all the authentic rewards, including:
|
||||
* Raw Shrimp
|
||||
* Raw Sardine
|
||||
* Raw Anchovie
|
||||
* Raw Lobster
|
||||
* Raw Manta Ray
|
||||
* Raw Sea Turtle
|
||||
* Raw Sharks
|
||||
* Various Junk Items
|
||||
|
||||
However, somewhat inauthentically, I wanted to make this minigame <br/>
|
||||
somewhat worth doing, as in its vanilla state it is pretty much <br/>
|
||||
pointless. So all the above fish can be caught at any level, and <br/>
|
||||
there's been a few inauthentic rewards added. Those are as follows:
|
||||
* Loop half of key
|
||||
* Tooth half of key
|
||||
* Caskets (can award gems, coins, talismans, and a few other things)
|
||||
* Pirate's Hat (very rare)
|
||||
* Lucky Cutlass (very rare)
|
||||
|
||||
### Experience
|
||||
I tweaked how experience is gained as well, again to make this somewhat worth doing.
|
||||
The exact formula for experience gained at x1 xp is: <br/>
|
||||
`((1.5% of Fishing Level) * Fishing Level) * Number of Fish Caught`
|
||||
<br/>
|
||||
What this generally works out to mean is that at level 99, you get roughly<br/>
|
||||
20k experience per trip at x1 xp at level 99, and 438.75 xp per trip at x1 <br/>
|
||||
at level 15. These are both based on catching around 130 fish, which is the expected <br/>
|
||||
average when soloing.
|
||||
|
||||
### Other players
|
||||
Playing with more players is more relaxed but you get less fish <br/>
|
||||
and xp, as the haul is divided evenly between all players.
|
||||
95
LICENSE
Normal file
95
LICENSE
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License
|
||||
By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.
|
||||
|
||||
Section 1 – Definitions.
|
||||
|
||||
Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
|
||||
Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.
|
||||
BY-NC-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License.
|
||||
Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
|
||||
Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
|
||||
Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
|
||||
License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution, NonCommercial, and ShareAlike.
|
||||
Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License.
|
||||
Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
|
||||
Licensor means the individual(s) or entity(ies) granting rights under this Public License.
|
||||
NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange.
|
||||
Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.
|
||||
Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
|
||||
You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.
|
||||
Section 2 – Scope.
|
||||
|
||||
License grant.
|
||||
Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
|
||||
reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and
|
||||
produce, reproduce, and Share Adapted Material for NonCommercial purposes only.
|
||||
Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
|
||||
Term. The term of this Public License is specified in Section 6(a).
|
||||
Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
|
||||
Downstream recipients.
|
||||
Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
|
||||
Additional offer from the Licensor – Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply.
|
||||
No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.
|
||||
No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).
|
||||
Other rights.
|
||||
|
||||
Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.
|
||||
Patent and trademark rights are not licensed under this Public License.
|
||||
To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes.
|
||||
Section 3 – License Conditions.
|
||||
|
||||
Your exercise of the Licensed Rights is expressly made subject to the following conditions.
|
||||
|
||||
Attribution.
|
||||
|
||||
If You Share the Licensed Material (including in modified form), You must:
|
||||
|
||||
retain the following if it is supplied by the Licensor with the Licensed Material:
|
||||
identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
|
||||
a copyright notice;
|
||||
a notice that refers to this Public License;
|
||||
a notice that refers to the disclaimer of warranties;
|
||||
a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
|
||||
indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
|
||||
indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
|
||||
You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.
|
||||
If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.
|
||||
ShareAlike.
|
||||
In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply.
|
||||
|
||||
The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC-SA Compatible License.
|
||||
You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material.
|
||||
You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply.
|
||||
Section 4 – Sui Generis Database Rights.
|
||||
|
||||
Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:
|
||||
|
||||
for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only;
|
||||
if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and
|
||||
You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.
|
||||
For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.
|
||||
Section 5 – Disclaimer of Warranties and Limitation of Liability.
|
||||
|
||||
Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.
|
||||
To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.
|
||||
The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
|
||||
Section 6 – Term and Termination.
|
||||
|
||||
This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.
|
||||
Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
|
||||
|
||||
automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or
|
||||
upon express reinstatement by the Licensor.
|
||||
For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.
|
||||
For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
|
||||
Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
|
||||
Section 7 – Other Terms and Conditions.
|
||||
|
||||
The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.
|
||||
Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.
|
||||
Section 8 – Interpretation.
|
||||
|
||||
For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.
|
||||
To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.
|
||||
No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
|
||||
Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.
|
||||
17
Management-Server/build.gradle
Normal file
17
Management-Server/build.gradle
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
apply plugin: 'application'
|
||||
|
||||
archivesBaseName = 'managementserver'
|
||||
|
||||
mainClassName = 'ms.Management'
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.guava:guava:29.0-jre'
|
||||
implementation 'mysql:mysql-connector-java:8.0.21'
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes 'Main-Class': 'ms.Management'
|
||||
}
|
||||
from { configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
|
||||
}
|
||||
BIN
Management-Server/build/classes/java/main/ms/Management$1.class
Normal file
BIN
Management-Server/build/classes/java/main/ms/Management$1.class
Normal file
Binary file not shown.
BIN
Management-Server/build/classes/java/main/ms/Management$2.class
Normal file
BIN
Management-Server/build/classes/java/main/ms/Management$2.class
Normal file
Binary file not shown.
BIN
Management-Server/build/classes/java/main/ms/Management$3.class
Normal file
BIN
Management-Server/build/classes/java/main/ms/Management$3.class
Normal file
Binary file not shown.
BIN
Management-Server/build/classes/java/main/ms/Management$4.class
Normal file
BIN
Management-Server/build/classes/java/main/ms/Management$4.class
Normal file
Binary file not shown.
BIN
Management-Server/build/classes/java/main/ms/Management$5.class
Normal file
BIN
Management-Server/build/classes/java/main/ms/Management$5.class
Normal file
Binary file not shown.
BIN
Management-Server/build/classes/java/main/ms/Management$6.class
Normal file
BIN
Management-Server/build/classes/java/main/ms/Management$6.class
Normal file
Binary file not shown.
BIN
Management-Server/build/classes/java/main/ms/Management$7.class
Normal file
BIN
Management-Server/build/classes/java/main/ms/Management$7.class
Normal file
Binary file not shown.
BIN
Management-Server/build/classes/java/main/ms/Management$8.class
Normal file
BIN
Management-Server/build/classes/java/main/ms/Management$8.class
Normal file
Binary file not shown.
BIN
Management-Server/build/classes/java/main/ms/Management.class
Normal file
BIN
Management-Server/build/classes/java/main/ms/Management.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Management-Server/build/classes/java/main/ms/net/IoSession.class
Normal file
BIN
Management-Server/build/classes/java/main/ms/net/IoSession.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Management-Server/build/kotlin/compileKotlin/build-history.bin
Normal file
BIN
Management-Server/build/kotlin/compileKotlin/build-history.bin
Normal file
Binary file not shown.
BIN
Management-Server/build/kotlin/compileKotlin/last-build.bin
Normal file
BIN
Management-Server/build/kotlin/compileKotlin/last-build.bin
Normal file
Binary file not shown.
|
|
@ -0,0 +1,102 @@
|
|||
ms/system/ShutdownSequence.java
|
||||
ms.system.ShutdownSequence
|
||||
ms/world/GameServer.java
|
||||
ms.world.GameServer
|
||||
ms/ServerConstants.java
|
||||
ms.ServerConstants
|
||||
ms/world/WorldDatabase.java
|
||||
ms.world.WorldDatabase
|
||||
ms/system/util/StringUtils.java
|
||||
ms.system.util.StringUtils
|
||||
ms/net/event/PacketWriteEvent.java
|
||||
ms.net.event.PacketWriteEvent
|
||||
ms.net.event.PacketWriteEvent$1
|
||||
ms/net/event/RegistryWriteEvent.java
|
||||
ms.net.event.RegistryWriteEvent
|
||||
ms/net/EventProducer.java
|
||||
ms.net.EventProducer
|
||||
ms/system/mysql/SQLTable.java
|
||||
ms.system.mysql.SQLTable
|
||||
ms/classloader/ClassLoadServer.java
|
||||
ms.classloader.ClassLoadServer
|
||||
ms/system/mysql/SQLEntryHandler.java
|
||||
ms.system.mysql.SQLEntryHandler
|
||||
ms/system/mysql/SQLColumn.java
|
||||
ms.system.mysql.SQLColumn
|
||||
ms/net/IoEventHandler.java
|
||||
ms.net.IoEventHandler
|
||||
ms/world/info/UIDInfo.java
|
||||
ms.world.info.UIDInfo
|
||||
ms/Management.java
|
||||
ms.Management
|
||||
ms.Management$1
|
||||
ms.Management$2
|
||||
ms.Management$3
|
||||
ms.Management$4
|
||||
ms.Management$5
|
||||
ms.Management$6
|
||||
ms.Management$7
|
||||
ms.Management$8
|
||||
ms/system/mysql/WorldListSQLHandler.java
|
||||
ms.system.mysql.WorldListSQLHandler
|
||||
ms/world/PlayerSession.java
|
||||
ms.world.PlayerSession
|
||||
ms/system/PunishmentStorage.java
|
||||
ms.system.PunishmentStorage
|
||||
ms/net/packet/WorldPacketRepository.java
|
||||
ms.net.packet.WorldPacketRepository
|
||||
ms/system/mysql/SQLManager.java
|
||||
ms.system.mysql.SQLManager
|
||||
ms/classloader/WorkerThread.java
|
||||
ms.classloader.WorkerThread
|
||||
ms/net/event/PacketReadEvent.java
|
||||
ms.net.event.PacketReadEvent
|
||||
ms/system/communication/CommunicationInfo.java
|
||||
ms.system.communication.CommunicationInfo
|
||||
ms/net/event/HSWriteEvent.java
|
||||
ms.net.event.HSWriteEvent
|
||||
ms/net/event/HSReadEvent.java
|
||||
ms.net.event.HSReadEvent
|
||||
ms/net/packet/PacketHeader.java
|
||||
ms.net.packet.PacketHeader
|
||||
ms/world/info/WorldInfo.java
|
||||
ms.world.info.WorldInfo
|
||||
ms/net/producer/RegistryEventProducer.java
|
||||
ms.net.producer.RegistryEventProducer
|
||||
ms/world/info/Response.java
|
||||
ms.world.info.Response
|
||||
ms/net/IoWriteEvent.java
|
||||
ms.net.IoWriteEvent
|
||||
ms/system/util/Command.java
|
||||
ms.system.util.Command
|
||||
ms/system/communication/ClanRepository.java
|
||||
ms.system.communication.ClanRepository
|
||||
ms/system/util/EncryptionManager.java
|
||||
ms.system.util.EncryptionManager
|
||||
ms.system.util.EncryptionManager$BCrypt
|
||||
ms/net/NioReactor.java
|
||||
ms.net.NioReactor
|
||||
ms/system/communication/ClanRank.java
|
||||
ms.system.communication.ClanRank
|
||||
ms/system/OperatingSystem.java
|
||||
ms.system.OperatingSystem
|
||||
ms/net/IoSession.java
|
||||
ms.net.IoSession
|
||||
ms/system/util/TaskExecutor.java
|
||||
ms.system.util.TaskExecutor
|
||||
ms/world/info/CountryFlag.java
|
||||
ms.world.info.CountryFlag
|
||||
ms/net/event/RegistryReadEvent.java
|
||||
ms.net.event.RegistryReadEvent
|
||||
ms/net/producer/HSEventProducer.java
|
||||
ms.net.producer.HSEventProducer
|
||||
ms/net/IoReadEvent.java
|
||||
ms.net.IoReadEvent
|
||||
ms/net/producer/PacketEventProducer.java
|
||||
ms.net.producer.PacketEventProducer
|
||||
ms/net/packet/IoBuffer.java
|
||||
ms.net.packet.IoBuffer
|
||||
ms/system/util/ByteBufferUtils.java
|
||||
ms.system.util.ByteBufferUtils
|
||||
ms/system/util/PlayerDatabaseGen.java
|
||||
ms.system.util.PlayerDatabaseGen
|
||||
172
Management-Server/src/main/java/ms/Management.java
Normal file
172
Management-Server/src/main/java/ms/Management.java
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
package ms;
|
||||
|
||||
import ms.classloader.ClassLoadServer;
|
||||
import ms.net.NioReactor;
|
||||
import ms.net.packet.WorldPacketRepository;
|
||||
import ms.system.ShutdownSequence;
|
||||
import ms.system.mysql.SQLManager;
|
||||
import ms.system.util.Command;
|
||||
import ms.world.GameServer;
|
||||
import ms.world.PlayerSession;
|
||||
import ms.world.WorldDatabase;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* The main class.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class Management {
|
||||
|
||||
/**
|
||||
* If the shutdown hook is active.
|
||||
*/
|
||||
public static boolean active = true;
|
||||
|
||||
/**
|
||||
* The commands.
|
||||
*/
|
||||
private static final Command[] COMMANDS = {
|
||||
new Command("-commands", "Print a list of all commands.") {
|
||||
@Override
|
||||
public void run(String...args) {
|
||||
for (Command c : COMMANDS) {
|
||||
System.out.println("Command " + c.getName() + ": " + c.getInfo());
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("-s", "Safely shuts down the server.") {
|
||||
@Override
|
||||
public void run(String...args) {
|
||||
System.out.println("Shutting down Management server...");
|
||||
ShutdownSequence.shutdown();
|
||||
}
|
||||
},
|
||||
new Command("-debug", "Debug world info.") {
|
||||
@Override
|
||||
public void run(String...args) {
|
||||
System.out.println("---------------------------------------------");
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null) {
|
||||
System.out.println("World [id=" + server.getInfo().getWorldId() + ", IP=" + server.getInfo().getAddress() + ", country=" + server.getInfo().getCountry() + ", members=" + server.getInfo().isMembers() + ", players=" + server.getPlayers().size() + ", active=" + server.isActive() + "].");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("-pinfo", "Debugs player information (usage: -pinfo emperor).") {
|
||||
@Override
|
||||
public void run(String...args) {
|
||||
String name = args[1];
|
||||
PlayerSession player = WorldDatabase.getPlayer(name);
|
||||
if (player == null) {
|
||||
System.out.println("Player " + name + " was not registered!");
|
||||
return;
|
||||
}
|
||||
System.out.println("Player [name=" + name + ", world=" + player.getWorldId() + ", active=" + player.isActive() + "].");
|
||||
}
|
||||
},
|
||||
new Command("-update", "Calls an update on all the game servers (-update -1 to cancel).") {
|
||||
@Override
|
||||
public void run(String...args) {
|
||||
int ticks = Integer.parseInt(args[1]);
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null && server.isActive()) {
|
||||
WorldPacketRepository.sendUpdate(server, ticks);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Command("-reloadconfig", "Reloads the configurations of all worlds.") {
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if(server == null) {
|
||||
continue;
|
||||
}
|
||||
WorldPacketRepository.sendConfigReload(server);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
new Command("-rlcache", "Reloads launcher/client resource cache") {
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
ClassLoadServer.resetResourceCache();
|
||||
System.out.println("Reloaded resource cache!");
|
||||
}
|
||||
},
|
||||
|
||||
new Command("-kick", "Kicks a player from the MS (not ingame).") {
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
String name = args[1];
|
||||
PlayerSession player = WorldDatabase.getPlayer(name);
|
||||
if (player == null) {
|
||||
System.out.println("Player " + name + " was not registered!");
|
||||
return;
|
||||
}
|
||||
player.getWorld().getPlayers().remove(name);
|
||||
player.setWorldId(0);
|
||||
System.out.println("Kicked player " + name + "!");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The main method.
|
||||
* @param args The arguments cast on runtime.
|
||||
* @throws Throwable When an exception occurs.
|
||||
*/
|
||||
public static void main(String...args) throws Throwable {
|
||||
if (!isLocallyHosted(ServerConstants.HOST_ADDRESS)) {
|
||||
System.err.println("WARNING: Configure host address in server constants!");
|
||||
}
|
||||
System.out.println("-------- 530 Management server --------");
|
||||
System.out.println("Starting up...");
|
||||
SQLManager.init();
|
||||
//NioReactor.configure(ServerConstants.PORT).start();
|
||||
NioReactor.configure(5555).start();
|
||||
new ClassLoadServer().start();
|
||||
Runtime.getRuntime().addShutdownHook(new ShutdownSequence());
|
||||
System.out.println("Status: ready.");
|
||||
System.out.println("Use -commands for a list of commands!");
|
||||
Scanner s = new Scanner(System.in);
|
||||
while (s.hasNext()) {
|
||||
try {
|
||||
String command = s.nextLine();
|
||||
if (!command.startsWith("-")) {
|
||||
continue;
|
||||
}
|
||||
String[] arguments = command.split(" ");
|
||||
command = arguments[0];
|
||||
for (Command c : COMMANDS) {
|
||||
if (c.getName().equals(command)) {
|
||||
System.out.println("Handling command \"" + command + "\"!");
|
||||
c.run(arguments);
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
s.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the Management server is locally hosted.
|
||||
* @return {@code True} if so.
|
||||
* @throws IOException When an I/O exception occurs.
|
||||
*/
|
||||
private static boolean isLocallyHosted(String ip) throws IOException {
|
||||
InetAddress address = InetAddress.getByName(ip);
|
||||
if (address.isAnyLocalAddress() || address.isLoopbackAddress()) {
|
||||
return true;
|
||||
}
|
||||
return NetworkInterface.getByInetAddress(address) != null;
|
||||
}
|
||||
}
|
||||
84
Management-Server/src/main/java/ms/ServerConstants.java
Normal file
84
Management-Server/src/main/java/ms/ServerConstants.java
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
package ms;
|
||||
|
||||
import ms.system.OperatingSystem;
|
||||
|
||||
/**
|
||||
* Holds constants for the management server.
|
||||
* @author v4rg
|
||||
*
|
||||
*/
|
||||
public final class ServerConstants {
|
||||
|
||||
/**
|
||||
* The port to be used for communications.
|
||||
*/
|
||||
public static final String SERVER_NAME = "2009Scape";
|
||||
|
||||
/**
|
||||
* The port to be used for communications.
|
||||
*/
|
||||
public static final int PORT = 5555;
|
||||
|
||||
/**
|
||||
* The maximum amount of worlds.
|
||||
*/
|
||||
public static final int WORLD_LIMIT = 10;
|
||||
|
||||
/**
|
||||
* The world switching delay in milliseconds.
|
||||
*/
|
||||
public static final long WORLD_SWITCH_DELAY = 20_000l;
|
||||
|
||||
/**
|
||||
* The address of the Management server.
|
||||
*/
|
||||
public static final String HOST_ADDRESS = "127.0.0.1";
|
||||
|
||||
/**
|
||||
* The store path.
|
||||
*/
|
||||
public static final String STORE_PATH = "./store/";
|
||||
|
||||
/**
|
||||
* The maximum amount of players per world.
|
||||
*/
|
||||
public static final int MAX_PLAYERS = (1 << 11) - 1;
|
||||
|
||||
/**
|
||||
* The operating system of the management server
|
||||
*/
|
||||
public static final OperatingSystem OS = System.getProperty("os.name").toUpperCase().contains("WIN") ? OperatingSystem.WINDOWS : OperatingSystem.UNIX;
|
||||
|
||||
/**
|
||||
* The administrators.
|
||||
*/
|
||||
public static final String[] ADMINISTRATORS = {
|
||||
"redsparr0w",
|
||||
};
|
||||
|
||||
public static final String[] DATABASE_NAMES = {
|
||||
"server",
|
||||
"global",
|
||||
};
|
||||
|
||||
/**
|
||||
* Stops from instantiating.
|
||||
*/
|
||||
private ServerConstants() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes a path to a specified operating system
|
||||
* @param operatingSystem The os type.
|
||||
* @param path The path.
|
||||
* @return The fixed path.
|
||||
*/
|
||||
public static String fixPath(OperatingSystem operatingSystem, String path) {
|
||||
if (operatingSystem == null)
|
||||
operatingSystem = OS;
|
||||
return operatingSystem == OperatingSystem.WINDOWS ? path.replace("/","\\") : path.replace("\\","/");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
package ms.classloader;
|
||||
|
||||
import ms.Management;
|
||||
import ms.ServerConstants;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* ClassLoadServer
|
||||
* @author Clayton Williams (Hope)
|
||||
*/
|
||||
public class ClassLoadServer extends Thread {
|
||||
|
||||
/**
|
||||
* Listening port
|
||||
*/
|
||||
private static final int PORT = 5050;
|
||||
|
||||
/**
|
||||
* serverSocket for incoming connections
|
||||
*/
|
||||
private ServerSocket serverSocket = null;
|
||||
|
||||
/**
|
||||
* Holds classes and resources already added in the server
|
||||
*/
|
||||
protected static HashMap<String, byte[]> resourceCache = new HashMap<String, byte[]>();
|
||||
|
||||
/**
|
||||
* New socket
|
||||
* @throws UnknownHostException
|
||||
* @throws IOException
|
||||
*/
|
||||
public ClassLoadServer() {
|
||||
try {
|
||||
serverSocket = new ServerSocket(PORT);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Listen for incoming connections
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
resetResourceCache();
|
||||
// System.out.println("Listening on port " + PORT + "...");
|
||||
while (Management.active) {
|
||||
Socket clientSocket = null;
|
||||
try {
|
||||
clientSocket = serverSocket.accept();
|
||||
//System.out.println("New Connection from : " + clientSocket.getInetAddress());
|
||||
WorkerThread wcs = new WorkerThread(clientSocket);
|
||||
wcs.start();
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads resources recursively from a starting root directory and adds the file bytes to our cache
|
||||
* @param path
|
||||
* @param pathRoot
|
||||
*/
|
||||
private static void loadResources(String path, String pathRoot) {
|
||||
try {
|
||||
path = ServerConstants.fixPath(null, path);
|
||||
pathRoot = ServerConstants.fixPath(null, pathRoot);
|
||||
File root = new File(path);
|
||||
File[] list = root.listFiles();
|
||||
if (list == null) return;
|
||||
for (File f : list) {
|
||||
if (f.isDirectory()) {
|
||||
loadResources(f.getAbsolutePath(), pathRoot);
|
||||
} else {
|
||||
if (f.exists()) {
|
||||
if (!f.getName().startsWith(".")) {
|
||||
byte[] bytes = Files.readAllBytes(f.toPath());
|
||||
String name = ServerConstants.fixPath(null, f.getAbsolutePath().substring(f.getAbsolutePath().lastIndexOf(pathRoot)));
|
||||
//System.out.println("[ClassLoadServer] Loaded resource '" + f.getName() +
|
||||
// "' Size: " + NumberFormat.getInstance().format(bytes.length) + " bytes");
|
||||
resourceCache.put(name, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Empties the class cache and loads resources
|
||||
*/
|
||||
public static void resetResourceCache() {
|
||||
resourceCache.clear();
|
||||
//loadResources("bin/org/keldagrim/launcher/", "org/arios/launcher/");
|
||||
//loadResources("resources/", "org/keldagrim/launcher/");
|
||||
//System.out.println("Loaded all resources!");
|
||||
}
|
||||
|
||||
}
|
||||
136
Management-Server/src/main/java/ms/classloader/WorkerThread.java
Normal file
136
Management-Server/src/main/java/ms/classloader/WorkerThread.java
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
package ms.classloader;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.Map;
|
||||
|
||||
import ms.ServerConstants;
|
||||
import ms.system.OperatingSystem;
|
||||
|
||||
/**
|
||||
* Worker thread for launcher connections
|
||||
* @author Clayton Williams (Hope)
|
||||
*
|
||||
*/
|
||||
public class WorkerThread extends Thread {
|
||||
|
||||
/**
|
||||
* Our launcher connection
|
||||
*/
|
||||
private Socket launcher = null;
|
||||
|
||||
/**
|
||||
* Input stream from launcher
|
||||
*/
|
||||
private ObjectInputStream is = null;
|
||||
|
||||
/**
|
||||
* Output stream to launcher
|
||||
*/
|
||||
private ObjectOutputStream os = null;
|
||||
|
||||
/**
|
||||
* The user's operating system type
|
||||
*/
|
||||
private OperatingSystem operatingSystem = OperatingSystem.WINDOWS;
|
||||
|
||||
/**
|
||||
* Creates a new worker thread to handle the launcher requests
|
||||
* @param socket
|
||||
* @param classesCache
|
||||
* @throws IOException
|
||||
*/
|
||||
public WorkerThread(Socket launcher) throws IOException {
|
||||
super();
|
||||
this.launcher = launcher;
|
||||
try {
|
||||
os = new ObjectOutputStream(new BufferedOutputStream(this.launcher.getOutputStream()));
|
||||
os.flush();
|
||||
is = new ObjectInputStream(new BufferedInputStream(launcher.getInputStream()));
|
||||
} catch (IOException ioe) {
|
||||
this.launcher.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Input Stream handler
|
||||
*/
|
||||
@SuppressWarnings("unused") //saving resource type for later
|
||||
public void run() {
|
||||
byte opcode = -1;
|
||||
try {
|
||||
while (true) {
|
||||
opcode = is.readByte();
|
||||
switch(opcode) {
|
||||
case 1: //requests revision
|
||||
operatingSystem = is.readUTF().contains("UNIX") ? OperatingSystem.UNIX : OperatingSystem.WINDOWS;
|
||||
os.reset();
|
||||
os.writeInt(ClassLoadServer.resourceCache.size());//#customresources
|
||||
for (Map.Entry<String, byte[]> hm : ClassLoadServer.resourceCache.entrySet()) {
|
||||
os.writeUTF(ServerConstants.fixPath(operatingSystem, (String) hm.getKey()));
|
||||
os.writeInt(hm.getValue().length);
|
||||
}
|
||||
os.writeByte(1); //number of custom resources
|
||||
//followed by 2 strings
|
||||
//System.err.println(operatingSystem.name());
|
||||
os.writeUTF(ServerConstants.fixPath(operatingSystem, "ms/launcher/arios-gamepack-530.jar"));
|
||||
os.writeUTF("BINARY");
|
||||
os.flush();
|
||||
break;
|
||||
case 2: //resource request
|
||||
String resourceName = ServerConstants.fixPath(null, is.readUTF());
|
||||
String resourceType = is.readUTF();
|
||||
if (ClassLoadServer.resourceCache.containsKey(resourceName)) {
|
||||
sendResource(ClassLoadServer.resourceCache.get(resourceName));
|
||||
//System.out.println("Sent Resource: " + resourceName);
|
||||
} else {
|
||||
sendOpcode(-1);
|
||||
//System.out.println("Could not send resource '" + resourceName + "'");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
System.out.println("Unhandled opcode=" + opcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
//System.out.println("Client force disconnect.");
|
||||
} finally {
|
||||
try {
|
||||
is.close();
|
||||
os.close();
|
||||
launcher.close();
|
||||
} catch (Exception e) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* send a byte array packet to the client
|
||||
* @exception IOException file read error.
|
||||
*/
|
||||
protected void sendResource(byte [] bytes) throws IOException {
|
||||
os.reset();
|
||||
os.writeByte(2);
|
||||
os.writeInt(bytes.length);
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
os.writeByte(bytes[i]);
|
||||
}
|
||||
os.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send no data opcodes
|
||||
* @param opcode
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void sendOpcode(int opcode) throws IOException {
|
||||
os.reset();
|
||||
os.writeByte(opcode);
|
||||
os.flush();
|
||||
}
|
||||
|
||||
}
|
||||
28
Management-Server/src/main/java/ms/net/EventProducer.java
Normal file
28
Management-Server/src/main/java/ms/net/EventProducer.java
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
package ms.net;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Used for producing I/O events.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public interface EventProducer {
|
||||
|
||||
/**
|
||||
* Produces a new read event.
|
||||
* @param session The session.
|
||||
* @param buffer The buffer to read.
|
||||
* @return The read event handler.
|
||||
*/
|
||||
IoReadEvent produceReader(IoSession session, ByteBuffer buffer);
|
||||
|
||||
/**
|
||||
* Produces a new writing event.
|
||||
* @param session The session.
|
||||
* @param context The context.
|
||||
* @return The write event handler.
|
||||
*/
|
||||
IoWriteEvent produceWriter(IoSession session, Object context);
|
||||
|
||||
}
|
||||
106
Management-Server/src/main/java/ms/net/IoEventHandler.java
Normal file
106
Management-Server/src/main/java/ms/net/IoEventHandler.java
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
package ms.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
/**
|
||||
* I/O event handling.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class IoEventHandler {
|
||||
|
||||
/**
|
||||
* The executor service.
|
||||
*/
|
||||
private final ExecutorService service;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoEventHandler}.
|
||||
* @param service The executor service used for handling events.
|
||||
*/
|
||||
public IoEventHandler(ExecutorService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when making a new connection.
|
||||
* @param key The selection key.
|
||||
*/
|
||||
public void connect(SelectionKey key) {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for accepting a new connection.
|
||||
* @param key The selection key.
|
||||
* @param selector The selector.
|
||||
* @throws IOException When an I/O exception occurs.
|
||||
*/
|
||||
public void accept(SelectionKey key, Selector selector) throws IOException {
|
||||
SocketChannel sc = ((ServerSocketChannel) key.channel()).accept();
|
||||
sc.configureBlocking(false);
|
||||
sc.socket().setTcpNoDelay(true);
|
||||
sc.register(selector, SelectionKey.OP_READ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the incoming packet data.
|
||||
* @param key The selection key.
|
||||
* @throws IOException When an I/O exception occurs.
|
||||
*/
|
||||
public void read(SelectionKey key) throws IOException {
|
||||
ReadableByteChannel channel = (ReadableByteChannel) key.channel();
|
||||
ByteBuffer buffer = ByteBuffer.allocate(100_000);
|
||||
IoSession session = (IoSession) key.attachment();
|
||||
if (channel.read(buffer) == -1) {
|
||||
System.out.println("Existing session disconnected - likely portscanner or server status checker.");
|
||||
key.cancel();
|
||||
return;
|
||||
}
|
||||
buffer.flip();
|
||||
if (session == null) {
|
||||
key.attach(session = new IoSession(key, service));
|
||||
}
|
||||
service.execute(session.getProducer().produceReader(session, buffer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the outgoing packet data.
|
||||
* @param key The selection key.
|
||||
*/
|
||||
public void write(SelectionKey key) {
|
||||
IoSession session = (IoSession) key.attachment();
|
||||
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
|
||||
session.write();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects a connection.
|
||||
* @param key The selection key.
|
||||
* @param t The occurred exception (if any).
|
||||
*/
|
||||
public void disconnect(SelectionKey key, Throwable t) {
|
||||
try {
|
||||
IoSession session = (IoSession) key.attachment();
|
||||
String cause = "" + t;
|
||||
if (t != null && !(t instanceof ClosedChannelException || cause.contains("De externe host") || cause.contains("De software op uw") || cause.contains("An established connection was aborted") || cause.contains("An existing connection") || cause.contains("AsynchronousClose"))) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
if (session != null) {
|
||||
session.disconnect();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
73
Management-Server/src/main/java/ms/net/IoReadEvent.java
Normal file
73
Management-Server/src/main/java/ms/net/IoReadEvent.java
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
package ms.net;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Handles a reading event.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public abstract class IoReadEvent implements Runnable {
|
||||
|
||||
/**
|
||||
* The I/O session.
|
||||
*/
|
||||
private final IoSession session;
|
||||
|
||||
/**
|
||||
* The buffer.
|
||||
*/
|
||||
private ByteBuffer buffer;
|
||||
|
||||
/**
|
||||
* If the queued reading buffer was used (debugging purposes).
|
||||
*/
|
||||
protected boolean usedQueuedBuffer;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoReadEvent}.
|
||||
* @param session The session.
|
||||
* @param buffer The buffer to read from.
|
||||
*/
|
||||
public IoReadEvent(IoSession session, ByteBuffer buffer) {
|
||||
this.session = session;
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (session.getReadingQueue() != null) {
|
||||
buffer = session.getReadingQueue().put(buffer);
|
||||
buffer.flip();
|
||||
session.setReadingQueue(null);
|
||||
usedQueuedBuffer = true;
|
||||
}
|
||||
read(session, buffer);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
session.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues the buffer until more data has been received.
|
||||
* @param data The data that has been read already.
|
||||
*/
|
||||
public void queueBuffer(int...data) {
|
||||
ByteBuffer queue = ByteBuffer.allocate(data.length + buffer.remaining() + 100_000);
|
||||
for (int value : data) {
|
||||
queue.put((byte) value);
|
||||
}
|
||||
queue.put(buffer);
|
||||
session.setReadingQueue(queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the data from the buffer.
|
||||
* @param session The session.
|
||||
* @param buffer The buffer to read from.
|
||||
*/
|
||||
public abstract void read(IoSession session, ByteBuffer buffer);
|
||||
|
||||
}
|
||||
351
Management-Server/src/main/java/ms/net/IoSession.java
Normal file
351
Management-Server/src/main/java/ms/net/IoSession.java
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
package ms.net;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import ms.ServerConstants;
|
||||
import ms.net.producer.HSEventProducer;
|
||||
import ms.world.GameServer;
|
||||
|
||||
/**
|
||||
* Represents a connected I/O session.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public class IoSession {
|
||||
|
||||
/**
|
||||
* The handshake event producer.
|
||||
*/
|
||||
private static final EventProducer HANDSHAKE_PRODUCER = new HSEventProducer();
|
||||
|
||||
/**
|
||||
* The selection key.
|
||||
*/
|
||||
private final SelectionKey key;
|
||||
|
||||
/**
|
||||
* The executor service.
|
||||
*/
|
||||
private final ExecutorService service;
|
||||
|
||||
/**
|
||||
* The event producer.
|
||||
*/
|
||||
private EventProducer producer = HANDSHAKE_PRODUCER;
|
||||
|
||||
/**
|
||||
* The currently queued writing data.
|
||||
*/
|
||||
private List<ByteBuffer> writingQueue = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The currently queued reading data.
|
||||
*/
|
||||
private ByteBuffer readingQueue;
|
||||
|
||||
/**
|
||||
* The writing lock.
|
||||
*/
|
||||
private Lock writingLock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* The name hash.
|
||||
*/
|
||||
private int nameHash;
|
||||
|
||||
/**
|
||||
* The server key.
|
||||
*/
|
||||
private long serverKey;
|
||||
|
||||
/**
|
||||
* The JS-5 encryption value.
|
||||
*/
|
||||
private int js5Encryption;
|
||||
|
||||
/**
|
||||
* If the session is active.
|
||||
*/
|
||||
private boolean active = true;
|
||||
|
||||
/**
|
||||
* The last ping time stamp.
|
||||
*/
|
||||
private long lastPing;
|
||||
|
||||
/**
|
||||
* The address.
|
||||
*/
|
||||
private final String address;
|
||||
|
||||
/**
|
||||
* The game server object for this session.
|
||||
*/
|
||||
private GameServer gameServer;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoSession}.
|
||||
* @param key The selection key.
|
||||
* @param service The executor service.
|
||||
*/
|
||||
public IoSession(SelectionKey key, ExecutorService service) {
|
||||
this.key = key;
|
||||
this.service = service;
|
||||
String address = getRemoteAddress().replaceAll("/", "").split(":")[0];
|
||||
if (address.equals("127.0.0.1")) {
|
||||
address = ServerConstants.HOST_ADDRESS;
|
||||
}
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires a write event created using the current event producer.
|
||||
* @param context The event context.
|
||||
*/
|
||||
public void write(Object context) {
|
||||
write(context, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires a write event created using the current event producer.
|
||||
* @param context The event context.
|
||||
* @param instant If the event should be instantly executed on this thread.
|
||||
*/
|
||||
public void write(Object context, boolean instant) {
|
||||
if (context == null) {
|
||||
throw new IllegalStateException("Invalid writing context!");
|
||||
}
|
||||
if (instant) {
|
||||
producer.produceWriter(this, context).run();
|
||||
return;
|
||||
}
|
||||
service.execute(producer.produceWriter(this, context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the packet data (without write event encoding).
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public void queue(ByteBuffer buffer) {
|
||||
try {
|
||||
writingLock.tryLock(1000L, TimeUnit.MILLISECONDS);
|
||||
} catch (Exception e){
|
||||
System.out.println(e);
|
||||
writingLock.unlock();
|
||||
return;
|
||||
}
|
||||
writingQueue.add(buffer);
|
||||
writingLock.unlock();
|
||||
write();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the writing of all buffers in the queue.
|
||||
*/
|
||||
public void write() {
|
||||
if (!key.isValid()) {
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
writingLock.lock();
|
||||
SocketChannel channel = (SocketChannel) key.channel();
|
||||
try {
|
||||
while (!writingQueue.isEmpty()) {
|
||||
ByteBuffer buffer = writingQueue.get(0);
|
||||
channel.write(buffer);
|
||||
if (buffer.hasRemaining()) {
|
||||
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
|
||||
break;
|
||||
}
|
||||
writingQueue.remove(0);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
disconnect();
|
||||
}
|
||||
writingLock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects the session.
|
||||
*/
|
||||
public void disconnect() {
|
||||
try {
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
active = false;
|
||||
key.cancel();
|
||||
SocketChannel channel = (SocketChannel) key.channel();
|
||||
channel.socket().close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the IP-address (without the port).
|
||||
* @return The address.
|
||||
*/
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the remote address of this session.
|
||||
* @return The remote address, as a String.
|
||||
*/
|
||||
public String getRemoteAddress() {
|
||||
try {
|
||||
return ((SocketChannel) key.channel()).getRemoteAddress().toString();
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current event producer.
|
||||
* @return The producer.
|
||||
*/
|
||||
public EventProducer getProducer() {
|
||||
return producer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event producer.
|
||||
* @param producer The producer to set.
|
||||
*/
|
||||
public void setProducer(EventProducer producer) {
|
||||
this.producer = producer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the queued reading data.
|
||||
* @return The readingQueue.
|
||||
*/
|
||||
public ByteBuffer getReadingQueue() {
|
||||
synchronized (this) {
|
||||
return readingQueue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Queues reading data.
|
||||
* @param readingQueue The readingQueue to set.
|
||||
*/
|
||||
public void setReadingQueue(ByteBuffer readingQueue) {
|
||||
synchronized (this) {
|
||||
this.readingQueue = readingQueue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the writing lock.
|
||||
* @return The writing lock.
|
||||
*/
|
||||
public Lock getWritingLock() {
|
||||
return writingLock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selection key.
|
||||
* @return The selection key.
|
||||
*/
|
||||
public SelectionKey getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The active.
|
||||
*/
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The js5Encryption.
|
||||
*/
|
||||
public int getJs5Encryption() {
|
||||
return js5Encryption;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param js5Encryption The js5Encryption to set.
|
||||
*/
|
||||
public void setJs5Encryption(int js5Encryption) {
|
||||
this.js5Encryption = js5Encryption;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lastPing.
|
||||
* @return The lastPing.
|
||||
*/
|
||||
public long getLastPing() {
|
||||
return lastPing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lastPing.
|
||||
* @param lastPing The lastPing to set.
|
||||
*/
|
||||
public void setLastPing(long lastPing) {
|
||||
this.lastPing = lastPing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the nameHash.
|
||||
* @return The nameHash.
|
||||
*/
|
||||
public int getNameHash() {
|
||||
return nameHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the nameHash.
|
||||
* @param nameHash The nameHash to set.
|
||||
*/
|
||||
public void setNameHash(int nameHash) {
|
||||
this.nameHash = nameHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the serverKey.
|
||||
* @return The serverKey.
|
||||
*/
|
||||
public long getServerKey() {
|
||||
return serverKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the serverKey.
|
||||
* @param serverKey The serverKey to set.
|
||||
*/
|
||||
public void setServerKey(long serverKey) {
|
||||
this.serverKey = serverKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the gameServer value.
|
||||
* @return The gameServer.
|
||||
*/
|
||||
public GameServer getGameServer() {
|
||||
return gameServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the gameServer value.
|
||||
* @param gameServer The gameServer to set.
|
||||
*/
|
||||
public void setGameServer(GameServer gameServer) {
|
||||
this.gameServer = gameServer;
|
||||
}
|
||||
|
||||
}
|
||||
50
Management-Server/src/main/java/ms/net/IoWriteEvent.java
Normal file
50
Management-Server/src/main/java/ms/net/IoWriteEvent.java
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package ms.net;
|
||||
|
||||
import java.nio.channels.CancelledKeyException;
|
||||
|
||||
/**
|
||||
* Handles a writing event.
|
||||
* @author Emperor
|
||||
*/
|
||||
public abstract class IoWriteEvent implements Runnable {
|
||||
|
||||
/**
|
||||
* The I/O session.
|
||||
*/
|
||||
private final IoSession session;
|
||||
|
||||
/**
|
||||
* The buffer.
|
||||
*/
|
||||
private final Object context;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoWriteEvent}.
|
||||
* @param session The session.
|
||||
* @param context The write event context.
|
||||
*/
|
||||
public IoWriteEvent(IoSession session, Object context) {
|
||||
this.session = session;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
write(session, context);
|
||||
} catch (Throwable t) {
|
||||
if (!(t instanceof CancelledKeyException)) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
session.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the data.
|
||||
* @param session The session.
|
||||
* @param context The write event context.
|
||||
*/
|
||||
public abstract void write(IoSession session, Object context);
|
||||
|
||||
}
|
||||
133
Management-Server/src/main/java/ms/net/NioReactor.java
Normal file
133
Management-Server/src/main/java/ms/net/NioReactor.java
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
package ms.net;
|
||||
|
||||
import ms.Management;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.Selector;
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* Handles (NIO-based) networking events using the reactor pattern.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class NioReactor implements Runnable {
|
||||
|
||||
/**
|
||||
* The executor service.
|
||||
*/
|
||||
private final ExecutorService service;
|
||||
|
||||
/**
|
||||
* The selector
|
||||
*/
|
||||
private Selector selector;
|
||||
|
||||
/**
|
||||
* The socket channel.
|
||||
*/
|
||||
private ServerSocketChannel channel;
|
||||
|
||||
/**
|
||||
* The I/O event handling instance.
|
||||
*/
|
||||
private final IoEventHandler eventHandler;
|
||||
|
||||
/**
|
||||
* If the reactor is running.
|
||||
*/
|
||||
private boolean running;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code NioReactor}.
|
||||
* @param poolSize The pool size.
|
||||
*/
|
||||
private NioReactor(int poolSize) {
|
||||
this.service = Executors.newSingleThreadScheduledExecutor();
|
||||
this.eventHandler = new IoEventHandler(Executors.newFixedThreadPool(poolSize));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and configures a new {@code NioReactor} with a pool size of 1.
|
||||
* @param port The port.
|
||||
* @return The {@code NioReactor} {@code Object}.
|
||||
* @throws IOException When an I/O exception occurs.
|
||||
*/
|
||||
public static NioReactor configure(int port) throws IOException {
|
||||
return configure(port, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and configures a new {@code NioReactor}.
|
||||
* @param port The port.
|
||||
* @param poolSize The amount of threads in the thread pool.
|
||||
* @return The {@code NioReactor} {@code Object}.
|
||||
* @throws IOException When an I/O exception occurs.
|
||||
*/
|
||||
public static NioReactor configure(int port, int poolSize) throws IOException {
|
||||
NioReactor reactor = new NioReactor(poolSize);
|
||||
reactor.channel = ServerSocketChannel.open();
|
||||
reactor.selector = Selector.open();
|
||||
reactor.channel.bind(new InetSocketAddress(port));
|
||||
reactor.channel.configureBlocking(false);
|
||||
reactor.channel.register(reactor.selector, SelectionKey.OP_ACCEPT);
|
||||
return reactor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the reactor.
|
||||
*/
|
||||
public void start() {
|
||||
running = true;
|
||||
service.execute(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (running && Management.active) {
|
||||
try {
|
||||
if(selector.select() > 0){
|
||||
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
|
||||
while (keys.hasNext()) {
|
||||
SelectionKey key = keys.next();
|
||||
keys.remove();
|
||||
try {
|
||||
if (!key.isValid() || !key.channel().isOpen()) {
|
||||
key.cancel();
|
||||
continue;
|
||||
}
|
||||
if (key.isAcceptable()) {
|
||||
eventHandler.accept(key, selector);
|
||||
}
|
||||
if (key.isReadable()) {
|
||||
eventHandler.read(key);
|
||||
}
|
||||
else if (key.isWritable()) {
|
||||
eventHandler.write(key);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
eventHandler.disconnect(key, t);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
System.out.println("SLEEPING");
|
||||
Thread.sleep(200);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates the reactor (once it's done processing current I/O events).
|
||||
*/
|
||||
public void terminate() {
|
||||
running = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package ms.net.event;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.IoReadEvent;
|
||||
import ms.net.IoSession;
|
||||
import ms.world.WorldDatabase;
|
||||
import ms.system.util.ByteBufferUtils;
|
||||
|
||||
/**
|
||||
* Handles handshake read events.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class HSReadEvent extends IoReadEvent {
|
||||
|
||||
/**
|
||||
* The password used to verify
|
||||
*/
|
||||
private static final String PASSWORD = "0x14ari0SSbh98989910";
|
||||
|
||||
/**
|
||||
* Constructs a new {@code HSReadEvent}.
|
||||
* @param session The session.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public HSReadEvent(IoSession session, ByteBuffer buffer) {
|
||||
super(session, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(IoSession session, ByteBuffer buffer) {
|
||||
int opcode = buffer.get() & 0xFF;
|
||||
switch (opcode) {
|
||||
case 88:
|
||||
String password = ByteBufferUtils.getString(buffer);
|
||||
if (!password.equals(PASSWORD)) {
|
||||
System.out.println("Password mismatch (attempt=" + password + ")!");
|
||||
session.disconnect();
|
||||
break;
|
||||
}
|
||||
session.write(opcode);
|
||||
break;
|
||||
case 255: // World list
|
||||
int updateStamp = buffer.getInt();
|
||||
WorldDatabase.sendUpdate(session, updateStamp);
|
||||
break;
|
||||
default:
|
||||
System.err.println("Unhandled handshake opcode: " + opcode + ".");
|
||||
session.disconnect();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package ms.net.event;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.IoSession;
|
||||
import ms.net.IoWriteEvent;
|
||||
import ms.net.producer.RegistryEventProducer;
|
||||
|
||||
/**
|
||||
* Handles Handshake write events.
|
||||
* @author Emperor
|
||||
*/
|
||||
public final class HSWriteEvent extends IoWriteEvent {
|
||||
|
||||
/**
|
||||
* The login event producer.
|
||||
*/
|
||||
private static final RegistryEventProducer REGISTRY_PRODUCER = new RegistryEventProducer();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code HSWriteEvent} {@code Object}.
|
||||
* @param session The session.
|
||||
* @param context The context.
|
||||
*/
|
||||
public HSWriteEvent(IoSession session, Object context) {
|
||||
super(session, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(IoSession session, Object context) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(9);
|
||||
buffer.put((byte) 14);
|
||||
session.setProducer( REGISTRY_PRODUCER);
|
||||
buffer.flip();
|
||||
session.queue(buffer);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
package ms.net.event;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.IoReadEvent;
|
||||
import ms.net.IoSession;
|
||||
import ms.net.packet.WorldPacketRepository;
|
||||
|
||||
/**
|
||||
* Handles world packet reading events.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class PacketReadEvent extends IoReadEvent {
|
||||
|
||||
/**
|
||||
* The packet sizes.
|
||||
*/
|
||||
private static final int[] PACKET_SIZE = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructs a new {@code PacketReadEvent} {@code Object}.
|
||||
* @param session The I/O session.
|
||||
* @param buffer The buffer to read from.
|
||||
*/
|
||||
public PacketReadEvent(IoSession session, ByteBuffer buffer) {
|
||||
super(session, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(IoSession session, ByteBuffer buffer) {
|
||||
int last = -1;
|
||||
while (buffer.hasRemaining()) {
|
||||
int opcode = buffer.get() & 0xFF;
|
||||
if (opcode >= PACKET_SIZE.length) {
|
||||
break;
|
||||
}
|
||||
int header = PACKET_SIZE[opcode];
|
||||
int size = header;
|
||||
if (header < 0) {
|
||||
size = getPacketSize(buffer, opcode, header, last);
|
||||
}
|
||||
if (size == -1) {
|
||||
break;
|
||||
}
|
||||
if (buffer.remaining() < size) {
|
||||
switch (header) {
|
||||
case -2:
|
||||
queueBuffer(opcode, size >> 8, size);
|
||||
break;
|
||||
case -1:
|
||||
queueBuffer(opcode, size);
|
||||
break;
|
||||
default:
|
||||
queueBuffer(opcode);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
byte[] data = new byte[size];
|
||||
buffer.get(data);
|
||||
last = opcode;
|
||||
try {
|
||||
WorldPacketRepository.handleIncoming(session, opcode, ByteBuffer.wrap(data));
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the packet size for the given opcode.
|
||||
* @param buffer The buffer.
|
||||
* @param opcode The opcode.
|
||||
* @param header The packet header.
|
||||
* @param last The last opcode.
|
||||
* @return The packet size.
|
||||
*/
|
||||
private int getPacketSize(ByteBuffer buffer, int opcode, int header, int last) {
|
||||
if (header == -1) {
|
||||
if (buffer.remaining() < 1) {
|
||||
queueBuffer(opcode);
|
||||
return -1;
|
||||
}
|
||||
return buffer.get() & 0xFF;
|
||||
}
|
||||
if (header == -2) {
|
||||
if (buffer.remaining() < 2) {
|
||||
queueBuffer(opcode);
|
||||
return -1;
|
||||
}
|
||||
return buffer.getShort() & 0xFFFF;
|
||||
}
|
||||
System.err.println("Invalid packet [opcode=" + opcode + ", last=" + last + ", queued=" + usedQueuedBuffer + "]!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package ms.net.event;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.IoSession;
|
||||
import ms.net.IoWriteEvent;
|
||||
import ms.net.packet.IoBuffer;
|
||||
|
||||
/**
|
||||
* Handles world packet writing events.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class PacketWriteEvent extends IoWriteEvent {
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a new {@code PacketWriteEvent} {@code Object}.
|
||||
* @param session The I/O session.
|
||||
* @param context The packet context.
|
||||
*/
|
||||
public PacketWriteEvent(IoSession session, Object context) {
|
||||
super(session, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(IoSession session, Object context) {
|
||||
IoBuffer b = (IoBuffer) context;
|
||||
int size = b.toByteBuffer().position();
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1 + size + b.getHeader().ordinal());
|
||||
buffer.put((byte) b.opcode());
|
||||
switch (b.getHeader()) {
|
||||
case NORMAL:
|
||||
break;
|
||||
case BYTE:
|
||||
buffer.put((byte) size);
|
||||
break;
|
||||
case SHORT:
|
||||
buffer.putShort((short) size);
|
||||
break;
|
||||
}
|
||||
buffer.put((ByteBuffer) b.toByteBuffer().flip());
|
||||
session.queue((ByteBuffer) buffer.flip());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package ms.net.event;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.ServerConstants;
|
||||
import ms.net.IoReadEvent;
|
||||
import ms.net.IoSession;
|
||||
import ms.world.WorldDatabase;
|
||||
import ms.system.util.ByteBufferUtils;
|
||||
import ms.world.info.CountryFlag;
|
||||
import ms.world.info.WorldInfo;
|
||||
|
||||
/**
|
||||
* Handles world registry read events.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class RegistryReadEvent extends IoReadEvent {
|
||||
|
||||
/**
|
||||
* The string check.
|
||||
*/
|
||||
private static final String CHECK = "12x4578f5g45hrdjiofed59898";
|
||||
//kratos = 666x14x88x28shhhwpwwb&h
|
||||
//12x4578f5g45hrdjiofed59898
|
||||
|
||||
/**
|
||||
* Constructs a new {@code RegistryReadEvent} {@code Object}.
|
||||
* @param session The session.
|
||||
* @param buffer The buffer to read.
|
||||
*/
|
||||
public RegistryReadEvent(IoSession session, ByteBuffer buffer) {
|
||||
super(session, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(IoSession session, ByteBuffer buffer) {
|
||||
int worldId = buffer.get() & 0xFF;
|
||||
if (buffer.remaining() < 2) {
|
||||
queueBuffer(worldId);
|
||||
return;
|
||||
}
|
||||
int revision = buffer.getInt();
|
||||
int country = buffer.get() & 0xFF;
|
||||
boolean members = buffer.get() == 1;
|
||||
boolean pvp = buffer.get() == 1;
|
||||
boolean quickChat = buffer.get() == 1;
|
||||
boolean lootshare = buffer.get() == 1;
|
||||
String activity = ByteBufferUtils.getString(buffer);
|
||||
System.out.println("["+ revision + "], country = " + country + ", members = " + members + ", pvp = " + pvp + ", quickChat = " + quickChat + ", lootShare = " + lootshare + ", activity = " + activity);
|
||||
for (int i = 0; i < CHECK.length(); i++) {
|
||||
if ((char) buffer.get() != CHECK.charAt(i)) {
|
||||
session.write(3);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (worldId >= ServerConstants.WORLD_LIMIT) {
|
||||
session.write(0);
|
||||
return;
|
||||
}
|
||||
if (WorldDatabase.isActive(worldId)) {
|
||||
session.write(2);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
WorldInfo info = new WorldInfo(worldId, session.getAddress(), revision, CountryFlag.values()[country], activity, members, pvp, quickChat, lootshare);
|
||||
WorldDatabase.register(info).configure(session);
|
||||
session.write(1);
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
session.write(3);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package ms.net.event;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.EventProducer;
|
||||
import ms.net.IoSession;
|
||||
import ms.net.IoWriteEvent;
|
||||
import ms.net.producer.PacketEventProducer;
|
||||
|
||||
/**
|
||||
* Handles game world registry writing events.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class RegistryWriteEvent extends IoWriteEvent {
|
||||
|
||||
/**
|
||||
* The event producer.
|
||||
*/
|
||||
public static final EventProducer PRODUCER = new PacketEventProducer();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code RegistryWriteEvent} {@code Object}.
|
||||
* @param session The I/O session.
|
||||
* @param context The writing context.
|
||||
*/
|
||||
public RegistryWriteEvent(IoSession session, Object context) {
|
||||
super(session, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(IoSession session, Object context) {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1);
|
||||
int opcode = (int) context;
|
||||
buffer.put((byte) opcode);
|
||||
buffer.flip();
|
||||
if (opcode == 1) {
|
||||
session.setProducer(PRODUCER);
|
||||
}
|
||||
session.queue(buffer);
|
||||
}
|
||||
|
||||
}
|
||||
677
Management-Server/src/main/java/ms/net/packet/IoBuffer.java
Normal file
677
Management-Server/src/main/java/ms/net/packet/IoBuffer.java
Normal file
|
|
@ -0,0 +1,677 @@
|
|||
package ms.net.packet;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.system.util.ByteBufferUtils;
|
||||
|
||||
/**
|
||||
* Represents the buffer used for reading/writing packets.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public class IoBuffer {
|
||||
|
||||
/**
|
||||
* The bit masks.
|
||||
*/
|
||||
private static final int[] BIT_MASK = new int[32];
|
||||
|
||||
/**
|
||||
* The packet size.
|
||||
*/
|
||||
private int packetSize;
|
||||
|
||||
/**
|
||||
* The opcode.
|
||||
*/
|
||||
private final int opcode;
|
||||
|
||||
/**
|
||||
* The packet header.
|
||||
*/
|
||||
private final PacketHeader header;
|
||||
|
||||
/**
|
||||
* The byte buffer.
|
||||
*/
|
||||
private ByteBuffer buf;
|
||||
|
||||
/**
|
||||
* The bit position.
|
||||
*/
|
||||
private int bitPosition = 0;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoBuffer} {@code Object}.
|
||||
*/
|
||||
public IoBuffer() {
|
||||
this(-1, PacketHeader.NORMAL, ByteBuffer.allocate(2048));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoBuffer} {@code Object}.
|
||||
* @param opcode The opcode.
|
||||
*/
|
||||
public IoBuffer(int opcode) {
|
||||
this(opcode, PacketHeader.NORMAL, ByteBuffer.allocate(2048));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoBuffer} {@code Object}.
|
||||
* @param opcode The opcode.
|
||||
* @param header The packet header.
|
||||
*/
|
||||
public IoBuffer(int opcode, PacketHeader header) {
|
||||
this(opcode, header, ByteBuffer.allocate((1 << 16) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code IoBuffer} {@code Object}.
|
||||
* @param opcode The opcode.
|
||||
* @param header The packet header.
|
||||
* @param buf The byte buffer.
|
||||
*/
|
||||
public IoBuffer(int opcode, PacketHeader header, ByteBuffer buf) {
|
||||
this.opcode = opcode;
|
||||
this.header = header;
|
||||
this.buf = buf;
|
||||
}
|
||||
|
||||
static {
|
||||
for (int i = 0; i < 32; i++) {
|
||||
BIT_MASK[i] = (1 << i) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer clear() {
|
||||
buf.clear();
|
||||
bitPosition = 0;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer put(int val) {
|
||||
buf.put((byte) val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param datas
|
||||
* @param offset
|
||||
* @param len
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putBytes(byte[] datas, int offset, int len) {
|
||||
for (int i = offset; i < len; i++) {
|
||||
put(datas[i]);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public final void getBytes(byte data[], int off, int len) {
|
||||
for (int k = off; k < len + off; k++) {
|
||||
data[k] = data[off++];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putA(int val) {
|
||||
buf.put((byte) (val + 128));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putC(int val) {
|
||||
buf.put((byte) -val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putS(int val) {
|
||||
buf.put((byte) (128 - val));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putTri(int val) {
|
||||
buf.put((byte) (val >> 16));
|
||||
buf.put((byte) (val >> 8));
|
||||
buf.put((byte) val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putShort(int val) {
|
||||
buf.putShort((short) val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putLEShort(int val) {
|
||||
buf.put((byte) val);
|
||||
buf.put((byte) (val >> 8));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putShortA(int val) {
|
||||
buf.put((byte) (val >> 8));
|
||||
buf.put((byte) (val + 128));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putLEShortA(int val) {
|
||||
buf.put((byte) (val + 128));
|
||||
buf.put((byte) (val >> 8));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putInt(int val) {
|
||||
buf.putInt(val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putLEInt(int val) {
|
||||
buf.put((byte) val);
|
||||
buf.put((byte) (val >> 8));
|
||||
buf.put((byte) (val >> 16));
|
||||
buf.put((byte) (val >> 24));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putIntA(int val) {
|
||||
buf.put((byte) (val >> 8));
|
||||
buf.put((byte) val);
|
||||
buf.put((byte) (val >> 24));
|
||||
buf.put((byte) (val >> 16));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putIntB(int val) {
|
||||
buf.put((byte) (val >> 16));
|
||||
buf.put((byte) (val >> 24));
|
||||
buf.put((byte) val);
|
||||
buf.put((byte) (val >> 8));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putLong(long val) {
|
||||
buf.putLong(val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putSmart(int val) {
|
||||
if (val > Byte.MAX_VALUE) {
|
||||
buf.putShort((short) (val + 32768));
|
||||
} else {
|
||||
buf.put((byte) val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putIntSmart(int val) {
|
||||
if (val > Short.MAX_VALUE) {
|
||||
buf.putInt(val + 32768);
|
||||
} else {
|
||||
buf.putShort((short) val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putString(String val) {
|
||||
buf.put(val.getBytes());
|
||||
buf.put((byte) 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putJagString(String val) {
|
||||
buf.put((byte) 0);
|
||||
buf.put(val.getBytes());
|
||||
buf.put((byte) 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putJagString2(String val) {
|
||||
byte[] packed = new byte[256];
|
||||
int length = ByteBufferUtils.packGJString2(0, packed, val);
|
||||
buf.put((byte) 0).put(packed, 0, length).put((byte) 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer put(byte[] val) {
|
||||
buf.put(val);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a byte array as byte A in reverse.
|
||||
* @param data The data to put.
|
||||
* @param start The start index.
|
||||
* @param offset The offset.
|
||||
*/
|
||||
public void putReverseA(byte[] data, int start, int offset) {
|
||||
for (int i = offset + start; i >= start; i--) {
|
||||
putA(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param numBits
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putBits(int numBits, int value) {
|
||||
int bytePos = getBitPosition() >> 3;
|
||||
int bitOffset = 8 - (getBitPosition() & 7);
|
||||
bitPosition += numBits;
|
||||
for (; numBits > bitOffset; bitOffset = 8) {
|
||||
byte b = buf.get(bytePos);
|
||||
buf.put(bytePos, b &= ~BIT_MASK[bitOffset]);
|
||||
buf.put(bytePos++, b |= value >> numBits - bitOffset & BIT_MASK[bitOffset]);
|
||||
numBits -= bitOffset;
|
||||
}
|
||||
byte b = buf.get(bytePos);
|
||||
if (numBits == bitOffset) {
|
||||
buf.put(bytePos, b &= ~BIT_MASK[bitOffset]);
|
||||
buf.put(bytePos, b |= value & BIT_MASK[bitOffset]);
|
||||
} else {
|
||||
buf.put(bytePos, b &= ~(BIT_MASK[numBits] << bitOffset - numBits));
|
||||
buf.put(bytePos, b |= (value & BIT_MASK[numBits]) << bitOffset - numBits);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param buffer
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer put(IoBuffer buffer) {
|
||||
buffer.toByteBuffer().flip();
|
||||
buf.put(buffer.toByteBuffer());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param buffer
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer putA(IoBuffer buffer) {
|
||||
buffer.toByteBuffer().flip();
|
||||
while (buffer.toByteBuffer().hasRemaining()) {
|
||||
putA(buffer.toByteBuffer().get());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param buffer
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer put(ByteBuffer buffer) {
|
||||
buf.put(buffer);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer setBitAccess() {
|
||||
bitPosition = buf.position() * 8;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer setByteAccess() {
|
||||
buf.position((getBitPosition() + 7) / 8);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int get() {
|
||||
return buf.get();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getA() {
|
||||
return (buf.get() & 0xFF) - 128;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getC() {
|
||||
return -buf.get();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getS() {
|
||||
return 128 - buf.get();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getTri() {
|
||||
return ((buf.get() << 16) & 0xFF) | ((buf.get() << 8) & 0xFF) | (buf.get() & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getShort() {
|
||||
return buf.getShort();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getLEShort() {
|
||||
return (buf.get() & 0xFF) | ((buf.get() & 0xFF) << 8);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getShortA() {
|
||||
return ((buf.get() & 0xFF) << 8) | (buf.get() - 128 & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getLEShortA() {
|
||||
return (buf.get() - 128 & 0xFF) | ((buf.get() & 0xFF) << 8);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getInt() {
|
||||
return buf.getInt();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getLEInt() {
|
||||
return (buf.get() & 0xFF) + ((buf.get() & 0xFF) << 8)
|
||||
+ ((buf.get() & 0xFF) << 16) + ((buf.get() & 0xFF) << 24);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getIntA() {
|
||||
return ((buf.get() & 0xFF) << 8) + (buf.get() & 0xFF)+ ((buf.get() & 0xFF) << 24) + ((buf.get() & 0xFF) << 16);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getIntB() {
|
||||
return ((buf.get() & 0xFF) << 16) + ((buf.get() & 0xFF) << 24)
|
||||
+ (buf.get() & 0xFF) + ((buf.get() & 0xFF) << 8);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getLongL() {
|
||||
long first = getIntB();
|
||||
long second = getIntB();
|
||||
if (second < 0)
|
||||
second = second & 0xffffffffL;
|
||||
return (first << -41780448) + second;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long getLong() {
|
||||
return buf.getLong();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getSmart() {
|
||||
int peek = buf.get(buf.position());
|
||||
if (peek <= Byte.MAX_VALUE) {
|
||||
return buf.get() & 0xFF;
|
||||
}
|
||||
return (buf.getShort() & 0xFFFF) - 32768;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getIntSmart() {
|
||||
int peek = buf.getShort(buf.position());
|
||||
if (peek <= Short.MAX_VALUE) {
|
||||
return buf.getShort() & 0xFFFF;
|
||||
}
|
||||
return (buf.getInt() & 0xFFFFFFFF) - 32768;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getString() {
|
||||
return ByteBufferUtils.getString(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getJagString() {
|
||||
buf.get();
|
||||
return ByteBufferUtils.getString(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param is
|
||||
* @param offset
|
||||
* @param length
|
||||
* @return
|
||||
*/
|
||||
public IoBuffer getReverseA(byte[] is, int offset, int length) {
|
||||
for (int i = (offset + length - 1); i >= offset; i--) {
|
||||
is[i] = (byte) (buf.get() - 128);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public ByteBuffer toByteBuffer() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int opcode() {
|
||||
return opcode;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int readableBytes() {
|
||||
return buf.capacity() - buf.remaining();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public PacketHeader getHeader() {
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public byte[] array() {
|
||||
return buf.array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the packetSize.
|
||||
*/
|
||||
public int getPacketSize() {
|
||||
return packetSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param packetSize the packetSize to set.
|
||||
*/
|
||||
public void setPacketSize(int packetSize) {
|
||||
this.packetSize = packetSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the bitPosition.
|
||||
* @return The bitPosition.
|
||||
*/
|
||||
public int getBitPosition() {
|
||||
return bitPosition;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package ms.net.packet;
|
||||
|
||||
/**
|
||||
* Represents the types of packet headers.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public enum PacketHeader {
|
||||
|
||||
/**
|
||||
* The normal packet header.
|
||||
*/
|
||||
NORMAL,
|
||||
|
||||
/**
|
||||
* The byte packet header.
|
||||
*/
|
||||
BYTE,
|
||||
|
||||
/**
|
||||
* The short packet header.
|
||||
*/
|
||||
SHORT;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,587 @@
|
|||
package ms.net.packet;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import ms.ServerConstants;
|
||||
import ms.net.IoSession;
|
||||
import ms.system.PunishmentStorage;
|
||||
import ms.world.GameServer;
|
||||
import ms.world.PlayerSession;
|
||||
import ms.world.WorldDatabase;
|
||||
import ms.system.communication.ClanRank;
|
||||
import ms.system.communication.ClanRepository;
|
||||
import ms.system.communication.CommunicationInfo;
|
||||
import ms.world.info.Response;
|
||||
import ms.world.info.UIDInfo;
|
||||
|
||||
/**
|
||||
* Repository class for world packets.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class WorldPacketRepository {
|
||||
|
||||
/**
|
||||
* Sends the player registry response.
|
||||
* @param server The game server.
|
||||
* @param player The player session.
|
||||
* @param response The registry response.
|
||||
*/
|
||||
public static void sendRegistryResponse(GameServer server, PlayerSession player, Response response) {
|
||||
IoBuffer buffer = new IoBuffer(0, PacketHeader.BYTE);
|
||||
buffer.putString(player.getUsername());
|
||||
buffer.put((byte) response.opcode());
|
||||
if (response == Response.MOVING_WORLD) {
|
||||
long delay = ServerConstants.WORLD_SWITCH_DELAY - (System.currentTimeMillis() - player.getDisconnectionTime());
|
||||
buffer.put((byte) (delay / 1000));
|
||||
}
|
||||
server.getSession().write(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the player.
|
||||
* @param player The player.
|
||||
* @param message The message to send.
|
||||
*/
|
||||
public static void sendPlayerMessage(PlayerSession player, String message) {
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
IoBuffer buffer = new IoBuffer(2, PacketHeader.BYTE);
|
||||
buffer.putString(player.getUsername());
|
||||
buffer.putString(message);
|
||||
player.getWorld().getSession().write(buffer);
|
||||
}
|
||||
|
||||
public static void sendPlayerMessage(PlayerSession player, String[] messages) {
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
for (String message : messages)
|
||||
sendPlayerMessage(player, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the contact information.
|
||||
* @param player The player.
|
||||
*/
|
||||
public static void sendContactInformation(PlayerSession player) {
|
||||
CommunicationInfo info = player.getCommunication();
|
||||
IoBuffer buffer = new IoBuffer(3, PacketHeader.SHORT);
|
||||
buffer.putString(player.getUsername());
|
||||
buffer.put(info.getContacts().size());
|
||||
for (String contact : info.getContacts().keySet()) {
|
||||
buffer.putString(contact);
|
||||
buffer.put(info.getRank(contact).ordinal());
|
||||
buffer.put(CommunicationInfo.getWorldId(player, contact));
|
||||
}
|
||||
buffer.put(info.getBlocked().size());
|
||||
for (String contact : info.getBlocked()) {
|
||||
buffer.putString(contact);
|
||||
}
|
||||
if (info.getCurrentClan() == null) {
|
||||
buffer.put(0);
|
||||
} else {
|
||||
buffer.put(1);
|
||||
buffer.putString(info.getCurrentClan());
|
||||
}
|
||||
player.getWorld().getSession().write(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a contact update.
|
||||
* @param player The player who's contacts we're changing.
|
||||
* @param contact The contact to update.
|
||||
* @param block If we're updating the blocked list.
|
||||
* @param remove If the contact should be removed.
|
||||
* @param worldId The world id of the contact.
|
||||
* @param rank The clan rank.
|
||||
*/
|
||||
public static void sendContactUpdate(PlayerSession player, String contact, boolean block, boolean remove, int worldId, ClanRank rank) {
|
||||
IoBuffer buffer = new IoBuffer(4, PacketHeader.BYTE);
|
||||
buffer.putString(player.getUsername());
|
||||
buffer.putString(contact);
|
||||
buffer.put((byte) (block ? 1 : 0));
|
||||
if (rank != null) {
|
||||
buffer.put((byte) (2 + rank.ordinal()));
|
||||
} else {
|
||||
buffer.put((byte) (remove ? 1 : 0));
|
||||
if (!block && !remove) {
|
||||
buffer.put((byte) worldId);
|
||||
}
|
||||
}
|
||||
player.getWorld().getSession().write(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a clan message.
|
||||
* @param player The player to send the message to.
|
||||
* @param p The player sending the message.
|
||||
* @param message The message to send.
|
||||
* @param type The message type.
|
||||
*/
|
||||
public static void sendMessage(PlayerSession player, PlayerSession p, int type, String message) {
|
||||
IoBuffer buffer = new IoBuffer(5, PacketHeader.BYTE);
|
||||
buffer.putString(player.getUsername());
|
||||
buffer.putString(p.getUsername());
|
||||
buffer.put((byte) type);
|
||||
buffer.put((byte) p.getChatIcon());
|
||||
buffer.putString(message);
|
||||
player.getWorld().getSession().write(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends clan information to the server.
|
||||
* @param server The server.
|
||||
* @param clan The clan.
|
||||
*/
|
||||
public static void sendClanInformation(GameServer server, ClanRepository clan) {
|
||||
IoBuffer buffer = new IoBuffer(6, PacketHeader.SHORT);
|
||||
buffer.putString(clan.getOwner().getUsername());
|
||||
buffer.putString(clan.getName());
|
||||
int length = clan.getPlayers().size();
|
||||
if (length > ClanRepository.MAX_MEMBERS) {
|
||||
length = ClanRepository.MAX_MEMBERS;
|
||||
}
|
||||
buffer.put((byte) length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
PlayerSession player = clan.getPlayers().get(i);
|
||||
buffer.putString(player.getUsername());
|
||||
buffer.put(player.getWorldId());
|
||||
buffer.put((byte) clan.getRank(player).ordinal());
|
||||
}
|
||||
buffer.put((byte) clan.getJoinRequirement().ordinal());
|
||||
buffer.put((byte) clan.getKickRequirement().ordinal());
|
||||
buffer.put((byte) clan.getMessageRequirement().ordinal());
|
||||
buffer.put((byte) clan.getLootRequirement().ordinal());
|
||||
server.getSession().write(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the leave clan packet.
|
||||
* @param player The player leaving the clan.
|
||||
*/
|
||||
public static void sendLeaveClan(PlayerSession player) {
|
||||
IoBuffer buffer = new IoBuffer(7, PacketHeader.BYTE);
|
||||
buffer.putString(player.getUsername());
|
||||
player.getWorld().getSession().write(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the player login notification.
|
||||
* @param server The server.
|
||||
* @param player The player logging in.
|
||||
* @param names The names.
|
||||
*/
|
||||
public static void notifyPlayers(GameServer server, PlayerSession player, List<String> names) {
|
||||
IoBuffer buffer = new IoBuffer(8, PacketHeader.SHORT);
|
||||
buffer.putString(player.getUsername());
|
||||
buffer.put((byte) player.getWorldId());
|
||||
buffer.put((byte) names.size());
|
||||
for (String name : names) {
|
||||
buffer.putString(name);
|
||||
}
|
||||
server.getSession().write(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the game server a player logged out.
|
||||
* @param server The game server to notify.
|
||||
* @param player The player logging out.
|
||||
*/
|
||||
public static void notifyLogout(GameServer server, PlayerSession player) {
|
||||
IoBuffer buffer = new IoBuffer(9, PacketHeader.BYTE);
|
||||
buffer.putString(player.getUsername());
|
||||
server.getSession().write(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the update countdown to the server.
|
||||
* @param server The server.
|
||||
* @param ticks The amount of ticks left.
|
||||
*/
|
||||
public static void sendUpdate(GameServer server, int ticks) {
|
||||
IoBuffer buffer = new IoBuffer(10);
|
||||
buffer.putInt(ticks);
|
||||
server.getSession().write(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the punishment update packet.
|
||||
* @param world The world to send the packet to.
|
||||
* @param key The punishment key.
|
||||
* @param type The punishment type.
|
||||
* @param duration The duration of the punishment.
|
||||
*/
|
||||
public static void sendPunishUpdate(GameServer world, String key, int type, long duration) {
|
||||
IoBuffer buffer = new IoBuffer(11, PacketHeader.BYTE);
|
||||
buffer.putString(key);
|
||||
buffer.put((byte) type);
|
||||
buffer.putLong(duration);
|
||||
world.getSession().write(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a configuration reload.
|
||||
* @param world the world.
|
||||
*/
|
||||
public static void sendConfigReload(GameServer world) {
|
||||
world.getSession().write(new IoBuffer(15, PacketHeader.BYTE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles incoming world packets.
|
||||
* @param session The I/O session.
|
||||
* @param opcode The opcode.
|
||||
* @param b The buffer to read from.
|
||||
*/
|
||||
public static void handleIncoming(IoSession session, int opcode, ByteBuffer b) {
|
||||
IoBuffer buffer = new IoBuffer(opcode, PacketHeader.NORMAL, b);
|
||||
GameServer server = session.getGameServer();
|
||||
switch (opcode) {
|
||||
case 0:
|
||||
handlePlayerRegistration(server, buffer);
|
||||
break;
|
||||
case 1:
|
||||
handlePlayerRemoval(server, buffer);
|
||||
break;
|
||||
case 2:
|
||||
handlePunishment(server, buffer);
|
||||
break;
|
||||
case 3:
|
||||
handleCommunicationRequest(server, buffer);
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
handleContactUpdate(server, buffer, opcode == 5);
|
||||
break;
|
||||
case 6:
|
||||
handleJoinClan(server, buffer);
|
||||
break;
|
||||
case 7:
|
||||
handleClanRename(server, buffer);
|
||||
break;
|
||||
case 8:
|
||||
handleClanSetting(server, buffer);
|
||||
break;
|
||||
case 9:
|
||||
handleClanKick(server, buffer);
|
||||
break;
|
||||
case 10:
|
||||
handleClanMessage(server, buffer);
|
||||
break;
|
||||
case 11:
|
||||
handlePrivateMessage(server, buffer);
|
||||
break;
|
||||
case 12:
|
||||
handleClanInfoRequest(server, buffer);
|
||||
break;
|
||||
case 13:
|
||||
handleChatSetting(server, buffer);
|
||||
break;
|
||||
case 14:
|
||||
handleInfoUpdate(server, buffer);
|
||||
break;
|
||||
default:
|
||||
System.err.println("Handling incoming packet [opcode=" + opcode + ", size=" + b.limit() + "].");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the info of a player update.
|
||||
* @param server the server.
|
||||
* @param buffer the buffer.
|
||||
*/
|
||||
private static void handleInfoUpdate(GameServer server, IoBuffer buffer) {
|
||||
String username = buffer.getString();
|
||||
PlayerSession player = server.getPlayers().get(username);
|
||||
if (player != null) {
|
||||
player.setChatIcon((int) buffer.get());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a player registration.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private static void handlePlayerRegistration(GameServer server, IoBuffer buffer) {
|
||||
String username = buffer.getString();
|
||||
String password = buffer.getString();
|
||||
String ipAddress = buffer.getString();
|
||||
String macAddress = buffer.getString();
|
||||
String compName = buffer.getString();
|
||||
String serial = buffer.getString();
|
||||
int rights = server.getInfo().getRevision() == 498 ? 0 : buffer.getInt();
|
||||
int chatIcon = server.getInfo().getRevision() == 498 ? 0 : buffer.get();
|
||||
UIDInfo uid = new UIDInfo(ipAddress, compName, macAddress, serial);
|
||||
PlayerSession player = new PlayerSession(username, password, new UIDInfo(ipAddress, compName, macAddress, serial));
|
||||
if (WorldDatabase.isActivePlayer(username)) {
|
||||
sendRegistryResponse(server, player, Response.ALREADY_ONLINE);
|
||||
return;
|
||||
}
|
||||
player.setUid(uid);
|
||||
player.setRights(rights);
|
||||
player.setChatIcon(chatIcon);
|
||||
if (PunishmentStorage.isSystemBanned(uid)) {
|
||||
sendRegistryResponse(server, player, Response.BANNED);
|
||||
return;
|
||||
}
|
||||
player.parse();
|
||||
if (player.isBanned()) {
|
||||
sendRegistryResponse(server, player, Response.ACCOUNT_DISABLED);
|
||||
return;
|
||||
}
|
||||
if (player.getLastWorld() != server.getInfo().getWorldId() && player.hasMovedWorld()) {
|
||||
sendRegistryResponse(server, player, Response.MOVING_WORLD);
|
||||
return;
|
||||
}
|
||||
server.register(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the removal of a player.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private static void handlePlayerRemoval(GameServer server, IoBuffer buffer) {
|
||||
String username = buffer.getString();
|
||||
PlayerSession session = server.getPlayers().get(username);
|
||||
if (session != null) {
|
||||
session.setActive(false);
|
||||
PlayerSession player = server.getPlayers().remove(username);
|
||||
if (player != null) {
|
||||
session.remove();
|
||||
}
|
||||
session.setWorldId(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a player registration.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private static void handlePunishment(GameServer server, IoBuffer buffer) {
|
||||
int type = buffer.get() & 0xFF;
|
||||
String target = buffer.getString();
|
||||
long duration = buffer.getLong();
|
||||
String staff = buffer.getString();
|
||||
PunishmentStorage.handlePunishment(staff, target, type, duration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the communication info request packet.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private static void handleCommunicationRequest(GameServer server, IoBuffer buffer) {
|
||||
String username = buffer.getString();
|
||||
PlayerSession player = server.getPlayers().get(username);
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
sendContactInformation(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a contact update packet.
|
||||
* @param server The server.
|
||||
* @param buffer The buffer to read from.
|
||||
* @param block If the list is for blocked players.
|
||||
*/
|
||||
private static void handleContactUpdate(GameServer server, IoBuffer buffer, boolean block) {
|
||||
String username = buffer.getString();
|
||||
PlayerSession player = server.getPlayers().get(username);
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
String contact = buffer.getString();
|
||||
switch (buffer.get()) {
|
||||
case 0:
|
||||
if (block) {
|
||||
player.getCommunication().block(contact);
|
||||
break;
|
||||
}
|
||||
player.getCommunication().add(contact);
|
||||
break;
|
||||
case 1:
|
||||
player.getCommunication().remove(contact, block);
|
||||
break;
|
||||
case 2:
|
||||
player.getCommunication().updateClanRank(contact, ClanRank.values()[buffer.get()]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a clan related packet.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private static void handleJoinClan(GameServer server, IoBuffer buffer) {
|
||||
String name = buffer.getString();
|
||||
String clanName = buffer.getString();
|
||||
PlayerSession player = server.getPlayers().get(name);
|
||||
if (player == null || !player.isActive()) {
|
||||
System.err.println("Invalid player specified in clan packet!");
|
||||
return;
|
||||
}
|
||||
if (player.getClan() != null) {
|
||||
player.getClan().leave(player, true);
|
||||
return;
|
||||
}
|
||||
if (clanName.length() < 1) {
|
||||
sendLeaveClan(player);
|
||||
return;
|
||||
}
|
||||
ClanRepository clan = ClanRepository.get(server, clanName);
|
||||
if (clan == null) {
|
||||
sendPlayerMessage(player, new String[]{ "The channel you tried to join does not exist.", "Try joining the main clan named '" + ServerConstants.SERVER_NAME + "'.:clan:" });
|
||||
return;
|
||||
}
|
||||
clan.enter(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles renaming a clan.
|
||||
* @param server The server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private static void handleClanRename(GameServer server, IoBuffer buffer) {
|
||||
String username = buffer.getString();
|
||||
String name = buffer.getString();
|
||||
PlayerSession player = server.getPlayers().get(username);
|
||||
if (player == null || !player.isActive()) {
|
||||
return;
|
||||
}
|
||||
ClanRepository clan = ClanRepository.getClans().get(username);
|
||||
player.getCommunication().setClanName(name);
|
||||
if (clan != null) {
|
||||
if (name.length() < 1) {
|
||||
clan.clean(true);
|
||||
} else {
|
||||
clan.rename(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changing clan settings packet.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private static void handleClanSetting(GameServer server, IoBuffer buffer) {
|
||||
String username = buffer.getString();
|
||||
int type = buffer.get();
|
||||
ClanRank rank = type < 4 ? ClanRank.values()[buffer.get() & 0xFF] : null;
|
||||
PlayerSession player = server.getPlayers().get(username);
|
||||
if (player == null || !player.isActive()) {
|
||||
return;
|
||||
}
|
||||
ClanRepository clan = ClanRepository.get(server,username);
|
||||
switch (type) {
|
||||
case 0:
|
||||
player.getCommunication().setJoinRequirement(rank);
|
||||
if (clan != null) {
|
||||
clan.clean(false);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
player.getCommunication().setMessageRequirement(rank);
|
||||
break;
|
||||
case 2:
|
||||
player.getCommunication().setKickRequirement(rank);
|
||||
if (clan != null) {
|
||||
clan.update();
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
player.getCommunication().setLootRequirement(rank);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles kicking a player from the clan.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private static void handleClanKick(GameServer server, IoBuffer buffer) {
|
||||
String username = buffer.getString();
|
||||
String playerName = buffer.getString();
|
||||
PlayerSession player = server.getPlayers().get(username);
|
||||
if (player == null || !player.isActive() || player.getClan() == null) {
|
||||
return;
|
||||
}
|
||||
PlayerSession target = WorldDatabase.getPlayer(playerName);
|
||||
if (target == null || !target.isActive()) {
|
||||
return;
|
||||
}
|
||||
player.getClan().kick(player, target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a clan message.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private static void handleClanMessage(GameServer server, IoBuffer buffer) {
|
||||
String username = buffer.getString();
|
||||
String message = buffer.getString();
|
||||
PlayerSession player = server.getPlayers().get(username);
|
||||
if (player == null || !player.isActive() || player.getClan() == null) {
|
||||
return;
|
||||
}
|
||||
player.getClan().message(player, message);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles a clan message.
|
||||
* @param server The game server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private static void handlePrivateMessage(GameServer server, IoBuffer buffer) {
|
||||
String username = buffer.getString();
|
||||
String receiver = buffer.getString();
|
||||
String message = buffer.getString();
|
||||
PlayerSession player = server.getPlayers().get(username);
|
||||
if (player == null || !player.isActive()) {
|
||||
return;
|
||||
}
|
||||
player.getCommunication().sendMessage(receiver, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a clan information request packet.
|
||||
* @param server The server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private static void handleClanInfoRequest(GameServer server, IoBuffer buffer) {
|
||||
String name = buffer.getString();
|
||||
ClanRepository clan = ClanRepository.get(server, name);
|
||||
if (clan == null) {
|
||||
return;
|
||||
}
|
||||
sendClanInformation(server, clan);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a chat setting update packet.
|
||||
* @param server The server.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
private static void handleChatSetting(GameServer server, IoBuffer buffer) {
|
||||
String name = buffer.getString();
|
||||
int publicSetting = buffer.get();
|
||||
int privateSetting = buffer.get();
|
||||
int tradeSetting = buffer.get();
|
||||
PlayerSession player = server.getPlayers().get(name);
|
||||
if (player == null || !player.isActive()) {
|
||||
return;
|
||||
}
|
||||
player.getCommunication().updateSettings(publicSetting, privateSetting, tradeSetting);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package ms.net.producer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.EventProducer;
|
||||
import ms.net.IoReadEvent;
|
||||
import ms.net.IoSession;
|
||||
import ms.net.IoWriteEvent;
|
||||
import ms.net.event.HSReadEvent;
|
||||
import ms.net.event.HSWriteEvent;
|
||||
|
||||
/**
|
||||
* Produces I/O events for the handshake protocol.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class HSEventProducer implements EventProducer {
|
||||
|
||||
@Override
|
||||
public IoReadEvent produceReader(IoSession session, ByteBuffer buffer) {
|
||||
return new HSReadEvent(session, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IoWriteEvent produceWriter(IoSession session, Object context) {
|
||||
return new HSWriteEvent(session, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package ms.net.producer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.EventProducer;
|
||||
import ms.net.IoReadEvent;
|
||||
import ms.net.IoSession;
|
||||
import ms.net.IoWriteEvent;
|
||||
import ms.net.event.PacketReadEvent;
|
||||
import ms.net.event.PacketWriteEvent;
|
||||
|
||||
/**
|
||||
* The packet event producer.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class PacketEventProducer implements EventProducer {
|
||||
|
||||
@Override
|
||||
public IoReadEvent produceReader(IoSession session, ByteBuffer buffer) {
|
||||
return new PacketReadEvent(session, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IoWriteEvent produceWriter(IoSession session, Object context) {
|
||||
return new PacketWriteEvent(session, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package ms.net.producer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import ms.net.EventProducer;
|
||||
import ms.net.IoReadEvent;
|
||||
import ms.net.IoSession;
|
||||
import ms.net.IoWriteEvent;
|
||||
import ms.net.event.RegistryReadEvent;
|
||||
import ms.net.event.RegistryWriteEvent;
|
||||
|
||||
/**
|
||||
* Handles world server registry.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class RegistryEventProducer implements EventProducer {
|
||||
|
||||
@Override
|
||||
public IoReadEvent produceReader(IoSession session, ByteBuffer buffer) {
|
||||
return new RegistryReadEvent(session, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IoWriteEvent produceWriter(IoSession session, Object context) {
|
||||
return new RegistryWriteEvent(session, context);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package ms.system;
|
||||
|
||||
/**
|
||||
* The operating systems
|
||||
* @author Clayton Williams
|
||||
*
|
||||
*/
|
||||
public enum OperatingSystem {
|
||||
|
||||
UNIX,
|
||||
WINDOWS
|
||||
|
||||
}
|
||||
263
Management-Server/src/main/java/ms/system/PunishmentStorage.java
Normal file
263
Management-Server/src/main/java/ms/system/PunishmentStorage.java
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
package ms.system;
|
||||
|
||||
import ms.net.packet.WorldPacketRepository;
|
||||
import ms.system.mysql.SQLManager;
|
||||
import ms.world.GameServer;
|
||||
import ms.world.PlayerSession;
|
||||
import ms.world.WorldDatabase;
|
||||
import ms.world.info.UIDInfo;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Used for storing and handling punishment data.
|
||||
* @author Emperor
|
||||
* @author Vexia
|
||||
*
|
||||
*/
|
||||
public final class PunishmentStorage {
|
||||
|
||||
/**
|
||||
* The type ids for IP, MAC and SERIAL bans.
|
||||
*/
|
||||
public static final int IP = 2, MAC = 3, SERIAL = 4;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code PunishmentStorage} {@code Object}.
|
||||
*/
|
||||
public PunishmentStorage() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a punishment.
|
||||
* @param staff The name of the staff member dealing the punishment.
|
||||
* @param target The target.
|
||||
* @param type The punishment type.
|
||||
* @param duration The duration of the punishment (in milliseconds).
|
||||
*/
|
||||
public static void handlePunishment(String name, String target, int type, long duration) {
|
||||
PlayerSession staff = WorldDatabase.getPlayer(name);
|
||||
PlayerSession player = WorldDatabase.getPlayer(target, true);
|
||||
if (player == null) {
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Player " + target + " is invalid!");
|
||||
return;
|
||||
}
|
||||
long end = Long.MAX_VALUE;
|
||||
if (duration != -1l && duration != 0L) {
|
||||
end = System.currentTimeMillis() + duration;
|
||||
} else if (duration == 0L) {
|
||||
end = 0L;
|
||||
}
|
||||
String key = "null";
|
||||
switch (type) {
|
||||
case 0: //Mute
|
||||
case 1: //Ban
|
||||
if (type == 1 && end == 0L) {
|
||||
unban(player.getIpAddress());
|
||||
unban(player.getMacAddress());
|
||||
unban(player.getSerialKey());
|
||||
}
|
||||
if (player.isActive()) {
|
||||
WorldPacketRepository.sendPunishUpdate(player.getWorld(), player.getUsername(), type, end);
|
||||
}
|
||||
notify(staff, type == 0 ? "mute" : "ban", target, end);
|
||||
Connection connection = SQLManager.getConnection();
|
||||
if (connection == null) {
|
||||
return;
|
||||
}
|
||||
PreparedStatement statement;
|
||||
try {
|
||||
statement = connection.prepareStatement("UPDATE members SET " + (type == 0 ? "muteTime" : "banTime") + "='" + end + "' WHERE username ='" + target + "'");
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
SQLManager.close(connection);
|
||||
return;
|
||||
}
|
||||
SQLManager.close(connection);
|
||||
return;
|
||||
case 2:
|
||||
ban(player.getIpAddress(), type);
|
||||
notify(staff, "IP-ban", target, end);
|
||||
notifyServers(key = player.getIpAddress(), type, end);
|
||||
break;
|
||||
case 3:
|
||||
ban(player.getMacAddress(), type);
|
||||
notify(staff, "MAC-ban", target, end);
|
||||
notifyServers(key = player.getMacAddress(), type, end);
|
||||
break;
|
||||
case 4:
|
||||
ban(player.getSerialKey(), type);
|
||||
notify(staff, "UID-ban", target, end);
|
||||
notifyServers(key = player.getSerialKey(), type, end);
|
||||
break;
|
||||
case 5:
|
||||
ban(player.getIpAddress(), 2);
|
||||
notifyServers(key = player.getIpAddress(), 2, end);
|
||||
ban(player.getMacAddress(), 3);
|
||||
notifyServers(key = player.getMacAddress(), 3, end);
|
||||
ban(player.getSerialKey(), 4);
|
||||
notifyServers(key = player.getSerialKey(), 4, end);
|
||||
notify(staff, "full ban", target, end);
|
||||
return;
|
||||
case 6: //Kick
|
||||
if (player.isActive()) {
|
||||
WorldPacketRepository.sendPunishUpdate(player.getWorld(), player.getUsername(), 6, end);
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Successfully kicked player " + target + " from world " + player.getWorldId() + ".");
|
||||
} else {
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Player " + target + " was already inactive.");
|
||||
}
|
||||
break;
|
||||
case 7: //Request info
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "[----------Player info----------]");
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Name: " + player.getUsername());
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "IP address: " + player.getIpAddress());
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "MAC address: " + player.getMacAddress());
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Serial key: " + player.getSerialKey());
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Computer name: " + player.getComputerName());
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "[-------------------------------]");
|
||||
return;
|
||||
}
|
||||
notifyServers(key, type, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bans an address.
|
||||
* @param address the address.
|
||||
* @return {@code True} if banned.
|
||||
*/
|
||||
public static boolean ban(String address, int type) {
|
||||
if (address == null || address.length() == 0 || address.equals("To be filled by O.E.M.") || address.equals("To be filled by O.E.M") || address.equals("Base Board Serial Number")) {
|
||||
System.out.println("Error! Can't ban address " + address + " type = " + type + "!");
|
||||
return false;
|
||||
}
|
||||
if (isBanned(address)) {
|
||||
return false;
|
||||
}
|
||||
Connection connection = SQLManager.getConnection();
|
||||
if (connection == null) {
|
||||
return false;
|
||||
}
|
||||
PreparedStatement statement;
|
||||
try {
|
||||
statement = connection.prepareStatement("INSERT INTO punishments VALUES('" + address + "','" + type + "')");
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
SQLManager.close(connection);
|
||||
return false;
|
||||
}
|
||||
SQLManager.close(connection);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unbans an address.
|
||||
* @param address the address.
|
||||
* @return {@code True} if unbanned.
|
||||
*/
|
||||
public static boolean unban(String address) {
|
||||
Connection connection = SQLManager.getConnection();
|
||||
if (connection == null) {
|
||||
return false;
|
||||
}
|
||||
PreparedStatement statement;
|
||||
try {
|
||||
statement = connection.prepareStatement("DELETE from punishments WHERE address ='" + address + "'");
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
SQLManager.close(connection);
|
||||
return false;
|
||||
}
|
||||
SQLManager.close(connection);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the punishing player of success.
|
||||
* @param staff The punishing player.
|
||||
* @param type The punishment type.
|
||||
* @param target The target name.
|
||||
* @param end The end time stamp of the punishment.
|
||||
*/
|
||||
private static void notify(PlayerSession staff, String type, String target, long end) {
|
||||
if (end <= System.currentTimeMillis()) {
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Successfully removed punishment [type=" + type + ", player=" + target + "].");
|
||||
return;
|
||||
}
|
||||
WorldPacketRepository.sendPlayerMessage(staff, "Successfully punished player " + target + " [type=" + type + ", duration=" + getDuration(end) + "].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the game servers of a punishment update.
|
||||
* @param key The punishment key.
|
||||
* @param type The type.
|
||||
* @param duration The duration.
|
||||
*/
|
||||
public static void notifyServers(String key, int type, long duration) {
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null && server.isActive()) {
|
||||
WorldPacketRepository.sendPunishUpdate(server, key, type, duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the UID Info is banned.
|
||||
* @param info the info.
|
||||
* @return {@code True} if banned.
|
||||
*/
|
||||
public static boolean isSystemBanned(UIDInfo info) {
|
||||
return isBanned(info.getIp()) || isBanned(info.getMac()) || isBanned(info.getSerial());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checked if an address is banned.
|
||||
* @param address the address.
|
||||
* @param type the type.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
public static boolean isBanned(String address) {
|
||||
Connection connection = SQLManager.getConnection();
|
||||
if (connection == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
ResultSet set = connection.createStatement().executeQuery("SELECT * FROM punishments WHERE address ='" + address +"'");
|
||||
if (set == null || !set.next()) {
|
||||
SQLManager.close(connection);
|
||||
return false;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
SQLManager.close(connection);
|
||||
return false;
|
||||
}
|
||||
SQLManager.close(connection);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the duration string representation.
|
||||
* @param end The end time.
|
||||
* @return The string.
|
||||
*/
|
||||
private static String getDuration(long end) {
|
||||
String time = "indefinite time";
|
||||
if (end != Long.MAX_VALUE) {
|
||||
int days = (int) ((end -= System.currentTimeMillis()) / (24 * 60 * 60_000));
|
||||
int hours = (int) ((end -= (days * 24 * 60 * 60_000)) / (60 * 60_000));
|
||||
int minutes = (int) ((end -= (hours * (60 * 60_000))) / 60_000);
|
||||
time = days + "d, " + hours + "h, " + minutes + "m";
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package ms.system;
|
||||
|
||||
|
||||
import ms.Management;
|
||||
|
||||
/**
|
||||
* The shutdown sequence used for safely turning off the Management server.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class ShutdownSequence extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (Management.active) {
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely shuts down the Management server.
|
||||
*/
|
||||
public static void shutdown() {
|
||||
System.out.println("Management server successfully shut down!");
|
||||
Management.active = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
package ms.system.communication;
|
||||
|
||||
/**
|
||||
* Represents the rank of a clan member.
|
||||
* @author Emperor
|
||||
*/
|
||||
public enum ClanRank {
|
||||
NONE(-1, "Anyone"),
|
||||
FRIEND(0, "Any friends"),
|
||||
RECRUIT(1, "Recruit+"),
|
||||
CORPORAL(2, "Corporal+"),
|
||||
SERGEANT(3, "Sergeant+"),
|
||||
LIEUTENANT(4, "Lieutenant+"),
|
||||
CAPTAIN(5, "Captain+"),
|
||||
GENERAL(6, "General+"),
|
||||
OWNER(7, "Only me"),
|
||||
ADMINISTRATOR(127, "No-one");
|
||||
|
||||
/**
|
||||
* The value of the rank.
|
||||
*/
|
||||
private final int value;
|
||||
|
||||
/**
|
||||
* The requirement info.
|
||||
*/
|
||||
private final String info;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ClanRank} {@code Object}.
|
||||
* @param value The rank value.
|
||||
* @param info The requirement info.
|
||||
*/
|
||||
private ClanRank(int value, String info) {
|
||||
this.value = value;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value.
|
||||
* @return The value.
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the info.
|
||||
* @return The info.
|
||||
*/
|
||||
public String getInfo() {
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,337 @@
|
|||
package ms.system.communication;
|
||||
|
||||
import ms.net.packet.WorldPacketRepository;
|
||||
import ms.system.util.StringUtils;
|
||||
import ms.world.GameServer;
|
||||
import ms.world.PlayerSession;
|
||||
import ms.world.WorldDatabase;
|
||||
import ms.world.info.UIDInfo;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Holds clan related information.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class ClanRepository {
|
||||
|
||||
/**
|
||||
* The mapping of active clans.
|
||||
*/
|
||||
private static final Map<String, ClanRepository> CLANS = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The maximum amount of members to be in a clan chat.
|
||||
*/
|
||||
public static final int MAX_MEMBERS = 100;
|
||||
|
||||
/**
|
||||
* The owner's details.
|
||||
*/
|
||||
private PlayerSession owner;
|
||||
|
||||
/**
|
||||
* The list of players currently in the chat.
|
||||
*/
|
||||
private final List<PlayerSession> players = new ArrayList<>(MAX_MEMBERS);
|
||||
|
||||
/**
|
||||
* The banned players.
|
||||
*/
|
||||
private final Map<String, Long> banned = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ClanRepository} {@code Object}.
|
||||
*/
|
||||
private ClanRepository() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clan repository for the given username.
|
||||
* @param ownerName The clan owner's name.
|
||||
* @return The clan repository.
|
||||
*/
|
||||
public static ClanRepository get(GameServer server, String ownerName) {
|
||||
ClanRepository clan = CLANS.get(ownerName);
|
||||
if (clan != null) {
|
||||
return clan;
|
||||
}
|
||||
PlayerSession owner = WorldDatabase.getPlayer(ownerName);
|
||||
if (owner == null) {
|
||||
owner = new PlayerSession(ownerName, ownerName, new UIDInfo());
|
||||
owner.parse();
|
||||
}
|
||||
if (owner.getCommunication().getClanName().equals("")) {
|
||||
return null;
|
||||
}
|
||||
clan = new ClanRepository();
|
||||
clan.owner = owner;
|
||||
CLANS.put(ownerName, clan);
|
||||
return clan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enters the clan chat.
|
||||
* @param player The player.
|
||||
*/
|
||||
public void enter(PlayerSession player) {
|
||||
if (players.size() >= MAX_MEMBERS && !owner.getUsername().equals("2009scape")) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "The channel you tried to join is full.:clan:");
|
||||
return;
|
||||
}
|
||||
if (player != owner && player.getRights() != 2) {
|
||||
if (isBanned(player.getUsername()) || owner.getCommunication().getBlocked().contains(player.getUsername())) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You are temporarily banned from this clan channel.:clan:");
|
||||
return;
|
||||
}
|
||||
ClanRank rank = getRank(player);
|
||||
if (rank.ordinal() < getJoinRequirement().ordinal()) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You do not have a high enough rank to join this clan channel.:clan:");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!players.contains(player)) {
|
||||
players.add(player);
|
||||
}
|
||||
WorldPacketRepository.sendPlayerMessage(player, "Now talking in clan channel " + owner.getCommunication().getClanName() + ".:clan:");
|
||||
WorldPacketRepository.sendPlayerMessage(player, "To talk, start each line of chat with the / symbol.:clan:");
|
||||
player.getCommunication().setCurrentClan(owner.getUsername());
|
||||
player.setClan(this);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves the clan chat.
|
||||
* @param player The player to leave.
|
||||
* @param remove If the player should be removed from the list.
|
||||
*/
|
||||
public void leave(PlayerSession player, boolean remove) {
|
||||
if (remove) {
|
||||
players.remove(player);
|
||||
update();
|
||||
if (players.size() < 1) {
|
||||
banned.clear();
|
||||
}
|
||||
}
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You have left the channel.:clan:");
|
||||
player.setClan(null);
|
||||
player.getCommunication().setCurrentClan(null);
|
||||
if (player.isActive()) {
|
||||
WorldPacketRepository.sendLeaveClan(player);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to all players in the chat.
|
||||
* @param player The player sending the message.
|
||||
* @param message The message to send.
|
||||
*/
|
||||
public void message(PlayerSession player, String message) {
|
||||
if (player != owner && player.getRights() != 2) {
|
||||
ClanRank rank = getRank(player);
|
||||
if (rank.ordinal() < getMessageRequirement().ordinal()) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You do not have a high enough rank to talk in this clan channel.:clan:");
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (Iterator<PlayerSession> it = players.iterator(); it.hasNext();) {
|
||||
PlayerSession p = it.next();
|
||||
if (p != null) {
|
||||
WorldPacketRepository.sendMessage(p, player, 2, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the clan chat.
|
||||
*/
|
||||
public void update() {
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null && server.isActive()) {
|
||||
WorldPacketRepository.sendClanInformation(server, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicks a player from the clan chat.
|
||||
* @param player The player.
|
||||
*/
|
||||
public void kick(PlayerSession player, PlayerSession target) {
|
||||
ClanRank rank = getRank(target);
|
||||
if (target.getRights() == 2) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You can't kick an administrator.:clan:");
|
||||
return;
|
||||
}
|
||||
System.out.println(rank + ", " + player.getUsername());
|
||||
if (player.getRights() < 1/*!= 2 && rank.ordinal() < getKickRequirement().ordinal()*/) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You do not have a high enough rank to kick in this clan channel.:clan:");
|
||||
return;
|
||||
}
|
||||
if (target == owner) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You can't kick the owner of this clan channel.:clan:");
|
||||
return;
|
||||
}
|
||||
if (target == player) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "You can't kick yourself.:clan:");
|
||||
return;
|
||||
}
|
||||
for (PlayerSession p : players) {
|
||||
WorldPacketRepository.sendMessage(p, player, 2, "[Attempting to kick/ban " + StringUtils.formatDisplayName(target.getUsername()) + " from this Clan Chat.]");
|
||||
}
|
||||
leave(target, true);
|
||||
banned.put(target.getUsername(), System.currentTimeMillis() + (3_600_000));
|
||||
WorldPacketRepository.sendPlayerMessage(target, "You have been kicked from the channel.:clan:");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rank for the given player.
|
||||
* @param player The player.
|
||||
* @return The rank.
|
||||
*/
|
||||
public ClanRank getRank(PlayerSession player) {
|
||||
ClanRank rank = owner.getCommunication().getContacts().get(player.getUsername());
|
||||
if (player.getRights() == 2 && player != owner) {
|
||||
return ClanRank.ADMINISTRATOR;
|
||||
}
|
||||
if (rank == null) {
|
||||
if (player == owner) {
|
||||
return ClanRank.OWNER;
|
||||
}
|
||||
return ClanRank.NONE;
|
||||
}
|
||||
return rank;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the player is banned.
|
||||
* @param username The username of the player.
|
||||
* @return {@code True} if so.
|
||||
*/
|
||||
private boolean isBanned(String username) {
|
||||
Long time = banned.get(username);
|
||||
if (time == null) {
|
||||
return false;
|
||||
}
|
||||
if (time < System.currentTimeMillis()) {
|
||||
banned.remove(username);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the clan chat.
|
||||
* @param disable If the clan chat is getting disabled.
|
||||
*/
|
||||
public void clean(boolean disable) {
|
||||
for (Iterator<PlayerSession> it = players.iterator(); it.hasNext();) {
|
||||
PlayerSession player = it.next();
|
||||
boolean remove = disable;
|
||||
if (!remove) {
|
||||
remove = getRank(player).ordinal() < getJoinRequirement().getValue();
|
||||
}
|
||||
if (remove) {
|
||||
leave(player, false);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
if (players.isEmpty()) {
|
||||
banned.clear();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the clan chat.
|
||||
* @param name The new clan name.
|
||||
*/
|
||||
public void rename(String name) {
|
||||
owner.getCommunication().setClanName(name);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clan name.
|
||||
* @return The clan name.
|
||||
*/
|
||||
public String getName() {
|
||||
return owner.getCommunication().getClanName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the owner value.
|
||||
* @return The owner.
|
||||
*/
|
||||
public PlayerSession getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the owner value.
|
||||
* @param owner The owner to set.
|
||||
*/
|
||||
public void setOwner(PlayerSession owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the players value.
|
||||
* @return The players.
|
||||
*/
|
||||
public List<PlayerSession> getPlayers() {
|
||||
return players;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clans value.
|
||||
* @return The clans.
|
||||
*/
|
||||
public static Map<String, ClanRepository> getClans() {
|
||||
return CLANS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the joinRequirement value.
|
||||
* @return The joinRequirement.
|
||||
*/
|
||||
public ClanRank getJoinRequirement() {
|
||||
return owner.getCommunication().getJoinRequirement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the messageRequirement value.
|
||||
* @return The messageRequirement.
|
||||
*/
|
||||
public ClanRank getMessageRequirement() {
|
||||
return owner.getCommunication().getMessageRequirement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kickRequirement value.
|
||||
* @return The kickRequirement.
|
||||
*/
|
||||
public ClanRank getKickRequirement() {
|
||||
return owner.getCommunication().getKickRequirement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lootRequirement value.
|
||||
* @return The lootRequirement.
|
||||
*/
|
||||
public ClanRank getLootRequirement() {
|
||||
return owner.getCommunication().getLootRequirement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the banned value.
|
||||
* @return The banned.
|
||||
*/
|
||||
public Map<String, Long> getBanned() {
|
||||
return banned;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,655 @@
|
|||
package ms.system.communication;
|
||||
|
||||
import ms.ServerConstants;
|
||||
import ms.net.packet.WorldPacketRepository;
|
||||
import ms.system.util.ByteBufferUtils;
|
||||
import ms.system.util.StringUtils;
|
||||
import ms.world.GameServer;
|
||||
import ms.world.PlayerSession;
|
||||
import ms.world.WorldDatabase;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Holds communication information.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class CommunicationInfo {
|
||||
|
||||
/**
|
||||
* The maximum list size.
|
||||
*/
|
||||
public static final int MAX_LIST_SIZE = 200;
|
||||
|
||||
/**
|
||||
* The clan ranks.
|
||||
*/
|
||||
private final Map<String, ClanRank> contacts = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The list of blocked players.
|
||||
*/
|
||||
private final List<String> blocked = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The player's clan name.
|
||||
*/
|
||||
private String clanName = "";
|
||||
|
||||
/**
|
||||
* The current clan this player is in.
|
||||
*/
|
||||
private String currentClan = "2009scape";
|
||||
|
||||
/**
|
||||
* The rank required for joining.
|
||||
*/
|
||||
private ClanRank joinRequirement = ClanRank.FRIEND;
|
||||
|
||||
/**
|
||||
* The rank required for messaging.
|
||||
*/
|
||||
private ClanRank messageRequirement = ClanRank.NONE;
|
||||
|
||||
/**
|
||||
* The rank required for kicking members.
|
||||
*/
|
||||
private ClanRank kickRequirement = ClanRank.OWNER;
|
||||
|
||||
/**
|
||||
* The rank required for loot-share.
|
||||
*/
|
||||
private ClanRank lootRequirement = ClanRank.ADMINISTRATOR;
|
||||
|
||||
/**
|
||||
* The public chat setting.
|
||||
*/
|
||||
private int publicChatSetting = 0;
|
||||
|
||||
/**
|
||||
* The private chat setting.
|
||||
*/
|
||||
private int privateChatSetting = 0;
|
||||
|
||||
/**
|
||||
* The trade setting.
|
||||
*/
|
||||
private int tradeSetting = 0;
|
||||
|
||||
/**
|
||||
* The player session.
|
||||
*/
|
||||
private PlayerSession player;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code CommunicationInfo} {@code Object}.
|
||||
* @param player The player.
|
||||
*/
|
||||
public CommunicationInfo(PlayerSession player) {
|
||||
this.setPlayer(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the player logs in.
|
||||
*/
|
||||
public void sync() {
|
||||
if (privateChatSetting != 2) {
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null && server.isActive()) {
|
||||
List<String> names = new ArrayList<>();
|
||||
for (PlayerSession p : server.getPlayers().values()) {
|
||||
if (p.isActive() && p.getCommunication().contacts.containsKey(player.getUsername())) {
|
||||
if (privateChatSetting == 0 || contacts.containsKey(p.getUsername())) {
|
||||
names.add(p.getUsername());
|
||||
}
|
||||
}
|
||||
}
|
||||
WorldPacketRepository.notifyPlayers(server, player, names);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the player logs out.
|
||||
*/
|
||||
public void clear() {
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null && server.isActive()) {
|
||||
WorldPacketRepository.notifyLogout(server, player);
|
||||
}
|
||||
}
|
||||
if (player.getClan() != null) {
|
||||
player.getClan().leave(player, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the communication info.
|
||||
* @param statement The buffer.
|
||||
* @throws SQLException The exception if thrown.
|
||||
*/
|
||||
public void save(PreparedStatement statement) throws SQLException {
|
||||
String contacts = "";
|
||||
String blocked = "";
|
||||
for (int i = 0; i < this.blocked.size(); i++) {
|
||||
blocked += (i == 0 ? "" : ",") + this.blocked.get(i);
|
||||
}
|
||||
int count = 0;
|
||||
for (Entry<String, ClanRank> entry : this.contacts.entrySet()) {
|
||||
contacts += "{" + entry.getKey() + "," + entry.getValue().ordinal() + "}" + (count == this.contacts.size() - 1 ? "" : "~");
|
||||
count++;
|
||||
}
|
||||
statement.setString(3, contacts);
|
||||
statement.setString(4, blocked);
|
||||
statement.setString(5, clanName);
|
||||
statement.setString(6, currentClan);
|
||||
statement.setString(7, joinRequirement.ordinal() + "," + messageRequirement.ordinal() + "," + kickRequirement.ordinal() + "," + lootRequirement.ordinal());
|
||||
statement.setString(8, publicChatSetting + "," + privateChatSetting + "," + tradeSetting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the communication info from the database.
|
||||
* @param set The result set.
|
||||
* @throws SQLException The exception if thrown.
|
||||
*/
|
||||
public void parse(ResultSet set) throws SQLException {
|
||||
String contacts = set.getString("contacts");
|
||||
String[] tokens;
|
||||
if (contacts != null && !contacts.isEmpty()) {
|
||||
String[] datas = contacts.split("~");
|
||||
for (String d : datas) {
|
||||
tokens = d.replace("{", "").replace("}", "").split(",");
|
||||
if (tokens.length < 2) {
|
||||
continue;
|
||||
}
|
||||
this.contacts.put(tokens[0], ClanRank.values()[Integer.parseInt(tokens[1])]);
|
||||
}
|
||||
}
|
||||
String bl = set.getString("blocked");
|
||||
if (bl != null && !bl.isEmpty()) {
|
||||
tokens = bl.split(",");
|
||||
for (String name : tokens) {
|
||||
blocked.add(name);
|
||||
}
|
||||
}
|
||||
clanName = set.getString("clanName");
|
||||
currentClan = set.getString("currentClan");
|
||||
String clanReqs = set.getString("clanReqs");
|
||||
if (!clanReqs.isEmpty()) {
|
||||
tokens = clanReqs.split(",");
|
||||
ClanRank rank = null;
|
||||
int ordinal = 0;
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
ordinal = Integer.parseInt(tokens[i]);
|
||||
if (ordinal < 0 || ordinal > ClanRank.values().length -1) {
|
||||
continue;
|
||||
}
|
||||
rank = ClanRank.values()[ordinal];
|
||||
switch (i) {
|
||||
case 0:
|
||||
joinRequirement = rank;
|
||||
break;
|
||||
case 1:
|
||||
messageRequirement = rank;
|
||||
break;
|
||||
case 2:
|
||||
if (ordinal < 3 || ordinal > 8) {
|
||||
break;
|
||||
}
|
||||
kickRequirement = rank;
|
||||
break;
|
||||
case 3:
|
||||
lootRequirement = rank;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
String chatSettings = set.getString("chatSettings");
|
||||
if (!chatSettings.isEmpty()) {
|
||||
tokens = chatSettings.split(",");
|
||||
for (int i = 0; i < tokens.length; i++) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
publicChatSetting = Integer.parseInt(tokens[0]);
|
||||
break;
|
||||
case 1:
|
||||
privateChatSetting = Integer.parseInt(tokens[1]);
|
||||
break;
|
||||
case 2:
|
||||
tradeSetting = Integer.parseInt(tokens[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the communication info.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public void save(ByteBuffer buffer) {
|
||||
buffer.put((byte) contacts.size());
|
||||
for (String name : contacts.keySet()) {
|
||||
ByteBufferUtils.putString(name, buffer);
|
||||
buffer.put((byte) contacts.get(name).ordinal());
|
||||
}
|
||||
buffer.put((byte) blocked.size());
|
||||
for (String name : blocked) {
|
||||
ByteBufferUtils.putString(name, buffer);
|
||||
}
|
||||
ByteBufferUtils.putString(clanName, buffer);
|
||||
if (currentClan != null) {
|
||||
ByteBufferUtils.putString(currentClan, buffer.put((byte) 1));
|
||||
} else {
|
||||
buffer.put((byte) 0);
|
||||
}
|
||||
buffer.put((byte) joinRequirement.ordinal());
|
||||
buffer.put((byte) messageRequirement.ordinal());
|
||||
buffer.put((byte) kickRequirement.ordinal());
|
||||
buffer.put((byte) lootRequirement.ordinal());
|
||||
buffer.put((byte) publicChatSetting);
|
||||
buffer.put((byte) privateChatSetting);
|
||||
buffer.put((byte) tradeSetting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the communication info from the buffer.
|
||||
* @param buffer The buffer.
|
||||
*/
|
||||
public void parse(ByteBuffer buffer) {
|
||||
int length = buffer.get() & 0xFF;
|
||||
for (int i = 0; i < length; i++) {
|
||||
contacts.put(ByteBufferUtils.getString(buffer), ClanRank.values()[buffer.get() & 0xFF]);
|
||||
}
|
||||
length = buffer.get() & 0xFF;
|
||||
for (int i = 0; i < length; i++) {
|
||||
blocked.add(ByteBufferUtils.getString(buffer));
|
||||
}
|
||||
clanName = ByteBufferUtils.getString(buffer);
|
||||
if (buffer.get() == 1) {
|
||||
currentClan = ByteBufferUtils.getString(buffer);
|
||||
}
|
||||
joinRequirement = ClanRank.values()[buffer.get()];
|
||||
messageRequirement = ClanRank.values()[buffer.get()];
|
||||
kickRequirement = ClanRank.values()[buffer.get()];
|
||||
lootRequirement = ClanRank.values()[buffer.get()];
|
||||
publicChatSetting = buffer.get();
|
||||
privateChatSetting = buffer.get();
|
||||
tradeSetting = buffer.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the target.
|
||||
* @param target The target.
|
||||
* @param message The message to send.
|
||||
*/
|
||||
public void sendMessage(String target, String message) {
|
||||
PlayerSession receiver = WorldDatabase.getPlayer(target);
|
||||
if (receiver == null || !receiver.isActive()) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "That player is currently offline.");
|
||||
return;
|
||||
}
|
||||
WorldPacketRepository.sendMessage(player, receiver, 0, message);
|
||||
WorldPacketRepository.sendMessage(receiver, player, 1, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a contact.
|
||||
* @param contact The contact to add.
|
||||
*/
|
||||
public void add(String contact) {
|
||||
if (contacts.size() >= MAX_LIST_SIZE) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "Your friend list is full.");
|
||||
return;
|
||||
}
|
||||
if (blocked.contains(contact)) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "Please remove " + StringUtils.formatDisplayName(contact) + " from your ignored list first.");
|
||||
return;
|
||||
}
|
||||
if (contacts.containsKey(contact)) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, StringUtils.formatDisplayName(contact) + " is already on your friend list.");
|
||||
return;
|
||||
}
|
||||
contacts.put(contact, ClanRank.FRIEND);
|
||||
WorldPacketRepository.sendContactUpdate(player, contact, false, false, getWorldId(player, contact), null);
|
||||
ClanRepository clan = ClanRepository.getClans().get(player.getUsername());
|
||||
if (clan != null) {
|
||||
clan.update();
|
||||
}
|
||||
if (privateChatSetting == 1) {
|
||||
PlayerSession other = WorldDatabase.getPlayer(contact);
|
||||
if (other != null && other.isActive() && other.getCommunication().getContacts().containsKey(player.getUsername())) {
|
||||
WorldPacketRepository.sendContactUpdate(other, player.getUsername(), false, false, getWorldId(other, player.getUsername()), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the world id for the given contact.
|
||||
* @param player The player.
|
||||
* @param contact The contact.
|
||||
* @return The world id to display.
|
||||
*/
|
||||
public static int getWorldId(PlayerSession player, String contact) {
|
||||
PlayerSession p = WorldDatabase.getPlayer(contact);
|
||||
if (p == null || !p.isActive() || p.getCommunication().getPrivateChatSetting() == 2) {
|
||||
return 0;
|
||||
}
|
||||
if (p.getCommunication().getBlocked().contains(player.getUsername())) {
|
||||
return 0;
|
||||
}
|
||||
if (p.getCommunication().getPrivateChatSetting() == 1) {
|
||||
if (p.getCommunication().getContacts().containsKey(player.getUsername())) {
|
||||
return p.getWorldId();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return p.getWorldId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a contact.
|
||||
* @param contact The contact to remove.
|
||||
* @param block If the contact should be removed from the block list.
|
||||
*/
|
||||
public void remove(String contact, boolean block) {
|
||||
PlayerSession other = WorldDatabase.getPlayer(contact);
|
||||
if (block) {
|
||||
blocked.remove(contact);
|
||||
if (other != null && other.isActive() && other.getCommunication().getContacts().containsKey(player.getUsername())) {
|
||||
WorldPacketRepository.sendContactUpdate(other, player.getUsername(), false, false, getWorldId(other, player.getUsername()), null);
|
||||
}
|
||||
} else {
|
||||
contacts.remove(contact);
|
||||
ClanRepository clan = ClanRepository.getClans().get(player.getUsername());
|
||||
if (clan != null) {
|
||||
clan.update();
|
||||
}
|
||||
if (privateChatSetting == 1 && other != null && other.isActive() && other.getCommunication().getContacts().containsKey(player.getUsername())) {
|
||||
WorldPacketRepository.sendContactUpdate(other, player.getUsername(), false, false, getWorldId(other, player.getUsername()), null);
|
||||
}
|
||||
}
|
||||
WorldPacketRepository.sendContactUpdate(player, contact, block, true, 0, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a blocked contact.
|
||||
* @param contact The contact to block.
|
||||
*/
|
||||
public void block(String contact) {
|
||||
if (blocked.size() >= MAX_LIST_SIZE) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "Your ignore list is full.");
|
||||
return;
|
||||
}
|
||||
if (contacts.containsKey(contact)) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, "Please remove " + StringUtils.formatDisplayName(contact) + " from your friends list first.");
|
||||
return;
|
||||
}
|
||||
if (blocked.contains(contact)) {
|
||||
WorldPacketRepository.sendPlayerMessage(player, StringUtils.formatDisplayName(contact) + " is already on your friend list.");
|
||||
return;
|
||||
}
|
||||
blocked.add(contact);
|
||||
WorldPacketRepository.sendContactUpdate(player, contact, true, false, 0, null);
|
||||
PlayerSession other = WorldDatabase.getPlayer(contact);
|
||||
if (other != null && other.isActive() && other.getCommunication().getContacts().containsKey(player.getUsername())) {
|
||||
WorldPacketRepository.sendContactUpdate(other, player.getUsername(), false, false, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the clan rank of a certain contact.
|
||||
* @param contact The contact.
|
||||
* @param clanRank The clan rank to set.
|
||||
*/
|
||||
public void updateClanRank(String contact, ClanRank clanRank) {
|
||||
if (!contacts.containsKey(contact)) {
|
||||
System.err.println("Could not find contact " + contact + " to update clan rank!");
|
||||
return;
|
||||
}
|
||||
contacts.put(contact, clanRank);
|
||||
ClanRepository clan = ClanRepository.getClans().get(player.getUsername());
|
||||
if (clan != null) {
|
||||
clan.update();
|
||||
}
|
||||
|
||||
WorldPacketRepository.sendContactUpdate(player, contact, false, false, 0, clanRank);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the settings.
|
||||
* @param publicSetting The public chat setting.
|
||||
* @param privateSetting The private chat setting.
|
||||
* @param tradeSetting The trade setting.
|
||||
*/
|
||||
public void updateSettings(int publicSetting, int privateSetting, int tradeSetting) {
|
||||
this.publicChatSetting = publicSetting;
|
||||
this.tradeSetting = tradeSetting;
|
||||
if (this.privateChatSetting != privateSetting) {
|
||||
updatePrivateSetting(privateSetting);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the private chat setting.
|
||||
* @param privateSetting The private chat setting.
|
||||
*/
|
||||
private void updatePrivateSetting(int privateSetting) {
|
||||
this.privateChatSetting = privateSetting;
|
||||
for (GameServer server : WorldDatabase.getWorlds()) {
|
||||
if (server != null && server.isActive()) {
|
||||
if (privateSetting == 2) {
|
||||
WorldPacketRepository.notifyLogout(server, player);
|
||||
continue;
|
||||
}
|
||||
for (PlayerSession p : server.getPlayers().values()) {
|
||||
if (p.isActive() && p.getCommunication().contacts.containsKey(player.getUsername())) {
|
||||
WorldPacketRepository.sendContactUpdate(p, player.getUsername(), false, false, getWorldId(p, player.getUsername()), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the contacts value.
|
||||
* @return The contacts.
|
||||
*/
|
||||
public Map<String, ClanRank> getContacts() {
|
||||
return contacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clan rank for the given contact.
|
||||
* @param contact The contact.
|
||||
* @return The rank.
|
||||
*/
|
||||
public ClanRank getRank(String contact) {
|
||||
for (String name : ServerConstants.ADMINISTRATORS) {
|
||||
if (contact.equals(name)) {
|
||||
return ClanRank.ADMINISTRATOR;
|
||||
}
|
||||
}
|
||||
return contacts.get(contact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the blocked value.
|
||||
* @return The blocked.
|
||||
*/
|
||||
public List<String> getBlocked() {
|
||||
return blocked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clanName value.
|
||||
* @return The clanName.
|
||||
*/
|
||||
public String getClanName() {
|
||||
return clanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the clanName value.
|
||||
* @param clanName The clanName to set.
|
||||
*/
|
||||
public void setClanName(String clanName) {
|
||||
this.clanName = clanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currentClan value.
|
||||
* @return The currentClan.
|
||||
*/
|
||||
public String getCurrentClan() {
|
||||
return currentClan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the currentClan value.
|
||||
* @param currentClan The currentClan to set.
|
||||
*/
|
||||
public void setCurrentClan(String currentClan) {
|
||||
this.currentClan = currentClan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the player value.
|
||||
* @return The player.
|
||||
*/
|
||||
public PlayerSession getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the player value.
|
||||
* @param player The player to set.
|
||||
*/
|
||||
public void setPlayer(PlayerSession player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the joinRequirement value.
|
||||
* @return The joinRequirement.
|
||||
*/
|
||||
public ClanRank getJoinRequirement() {
|
||||
return joinRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the joinRequirement value.
|
||||
* @param joinRequirement The joinRequirement to set.
|
||||
*/
|
||||
public void setJoinRequirement(ClanRank joinRequirement) {
|
||||
this.joinRequirement = joinRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the messageRequirement value.
|
||||
* @return The messageRequirement.
|
||||
*/
|
||||
public ClanRank getMessageRequirement() {
|
||||
return messageRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the messageRequirement value.
|
||||
* @param messageRequirement The messageRequirement to set.
|
||||
*/
|
||||
public void setMessageRequirement(ClanRank messageRequirement) {
|
||||
this.messageRequirement = messageRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kickRequirement value.
|
||||
* @return The kickRequirement.
|
||||
*/
|
||||
public ClanRank getKickRequirement() {
|
||||
return kickRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the kickRequirement value.
|
||||
* @param kickRequirement The kickRequirement to set.
|
||||
*/
|
||||
public void setKickRequirement(ClanRank kickRequirement) {
|
||||
this.kickRequirement = kickRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the lootRequirement value.
|
||||
* @return The lootRequirement.
|
||||
*/
|
||||
public ClanRank getLootRequirement() {
|
||||
return lootRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the lootRequirement value.
|
||||
* @param lootRequirement The lootRequirement to set.
|
||||
*/
|
||||
public void setLootRequirement(ClanRank lootRequirement) {
|
||||
this.lootRequirement = lootRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the publicChatSetting value.
|
||||
* @return The publicChatSetting.
|
||||
*/
|
||||
public int getPublicChatSetting() {
|
||||
return publicChatSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the publicChatSetting value.
|
||||
* @param publicChatSetting The publicChatSetting to set.
|
||||
*/
|
||||
public void setPublicChatSetting(int publicChatSetting) {
|
||||
this.publicChatSetting = publicChatSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the privateChatSetting value.
|
||||
* @return The privateChatSetting.
|
||||
*/
|
||||
public int getPrivateChatSetting() {
|
||||
return privateChatSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the privateChatSetting value.
|
||||
* @param privateChatSetting The privateChatSetting to set.
|
||||
*/
|
||||
public void setPrivateChatSetting(int privateChatSetting) {
|
||||
this.privateChatSetting = privateChatSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the tradeSetting value.
|
||||
* @return The tradeSetting.
|
||||
*/
|
||||
public int getTradeSetting() {
|
||||
return tradeSetting;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tradeSetting value.
|
||||
* @param tradeSetting The tradeSetting to set.
|
||||
*/
|
||||
public void setTradeSetting(int tradeSetting) {
|
||||
this.tradeSetting = tradeSetting;
|
||||
}
|
||||
|
||||
}
|
||||
121
Management-Server/src/main/java/ms/system/mysql/SQLColumn.java
Normal file
121
Management-Server/src/main/java/ms/system/mysql/SQLColumn.java
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
package ms.system.mysql;
|
||||
|
||||
/**
|
||||
* Represents a column used in an SQL table.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class SQLColumn {
|
||||
|
||||
/**
|
||||
* The name.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The data type.
|
||||
*/
|
||||
private final Class<?> type;
|
||||
|
||||
/**
|
||||
* If this column should never be updated in the database.
|
||||
*/
|
||||
private final boolean neverUpdate;
|
||||
|
||||
/**
|
||||
* The value.
|
||||
*/
|
||||
private Object value;
|
||||
|
||||
/**
|
||||
* If the column value changed.
|
||||
*/
|
||||
private boolean changed;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code SQLColumn} {@code Object}.
|
||||
* @param name The column name.
|
||||
* @param type The data type.
|
||||
*/
|
||||
public SQLColumn(String name, Class<?> type) {
|
||||
this(name, type, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code SQLColumn} {@code Object}.
|
||||
* @param name The column name.
|
||||
* @param type The data type.
|
||||
* @param neverUpdate If this column should never be updated in the database.
|
||||
*/
|
||||
public SQLColumn(String name, Class<?> type, boolean neverUpdate) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.neverUpdate = neverUpdate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name.
|
||||
* @return The name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the value.
|
||||
* @param value The value.
|
||||
*/
|
||||
public void updateValue(Object value) {
|
||||
this.changed = value != this.value;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value.
|
||||
* @return The value.
|
||||
*/
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value.
|
||||
* @param value The value to set.
|
||||
*/
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
this.changed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the changed.
|
||||
* @return The changed.
|
||||
*/
|
||||
public boolean isChanged() {
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the changed.
|
||||
* @param changed The changed to set.
|
||||
*/
|
||||
public void setChanged(boolean changed) {
|
||||
this.changed = changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type.
|
||||
* @return The type.
|
||||
*/
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the neverUpdate.
|
||||
* @return The neverUpdate.
|
||||
*/
|
||||
public boolean isNeverUpdate() {
|
||||
return neverUpdate;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,202 @@
|
|||
package ms.system.mysql;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Handles an SQL entry.
|
||||
* @author Emperor
|
||||
* @param <T> The entry type.
|
||||
*/
|
||||
public abstract class SQLEntryHandler<T> {
|
||||
|
||||
/**
|
||||
* The connection.
|
||||
*/
|
||||
protected Connection connection;
|
||||
|
||||
/**
|
||||
* The entry.
|
||||
*/
|
||||
protected T entry;
|
||||
|
||||
/**
|
||||
* The result set.
|
||||
*/
|
||||
protected ResultSet result;
|
||||
|
||||
/**
|
||||
* The table name.
|
||||
*/
|
||||
protected String table;
|
||||
|
||||
/**
|
||||
* The column name.
|
||||
*/
|
||||
private String column;
|
||||
|
||||
/**
|
||||
* The value to use.
|
||||
*/
|
||||
protected String value;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code SQLEntryHandler} {@code Object}.
|
||||
* @param entry The entry.
|
||||
* @param table The table name.
|
||||
* @param column column name.
|
||||
* @param value The column value.
|
||||
*/
|
||||
public SQLEntryHandler(T entry, String table, String column, String value) {
|
||||
this.entry = entry;
|
||||
this.table = table;
|
||||
this.column = column;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the SQL entry.
|
||||
* @param entry The entry.
|
||||
*/
|
||||
public static void read(SQLEntryHandler<?> entry) {
|
||||
entry.connection = entry.getConnection();
|
||||
if (entry.connection == null) {
|
||||
//System.err.println("Could not read SQL data: connection is null!");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
entry.read();
|
||||
if (entry.result == null || !entry.result.next()) {
|
||||
entry.create();
|
||||
} else {
|
||||
entry.parse();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
SQLManager.close(entry.connection);
|
||||
entry.connection = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the entry data on the SQL database.
|
||||
* @param entry The entry.
|
||||
*/
|
||||
public static void write(SQLEntryHandler<?> entry) {
|
||||
write(entry, entry.getConnection(), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the SQL entry.
|
||||
* @param entry The entry.
|
||||
*/
|
||||
public static void write(SQLEntryHandler<?> entry, Connection connection, boolean commit) {
|
||||
if (connection == null) {
|
||||
//System.err.println("Could not write SQL data: connection is null!");
|
||||
return;
|
||||
}
|
||||
entry.connection = connection;
|
||||
try {
|
||||
if (!commit) {
|
||||
entry.connection.setAutoCommit(false);
|
||||
}
|
||||
entry.save();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (commit) {
|
||||
SQLManager.close(entry.connection);
|
||||
}
|
||||
entry.connection = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the table from the SQL database.
|
||||
* @throws SQLException When an SQL exception occurs.
|
||||
*/
|
||||
public void read() throws SQLException {
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT " + getReadSelection() + " FROM " + table + " WHERE " + column + " = ?");
|
||||
statement.setString(1, value);
|
||||
result = statement.executeQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result.
|
||||
* @return the result.
|
||||
*/
|
||||
public ResultSet getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selection.
|
||||
* @return The selection.
|
||||
*/
|
||||
public String getReadSelection() {
|
||||
return "*";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the writing statement.
|
||||
* @param create If we are creating a new row.
|
||||
* @param columns The columns to update.
|
||||
*/
|
||||
public PreparedStatement getWritingStatement(boolean create, String...columns) {
|
||||
PreparedStatement statement = null;
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (create) {
|
||||
sb.append("INSERT INTO ").append(table).append(" (").append(column);
|
||||
for (String name : columns) {
|
||||
sb.append(",").append(name);
|
||||
}
|
||||
sb.append(") VALUES (?");
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
sb.append(",?");
|
||||
}
|
||||
sb.append(")");
|
||||
} else {
|
||||
sb.append("UPDATE ").append(table).append(" SET ");
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
sb.append(columns[i]).append("=?");
|
||||
if (i < columns.length - 1) {
|
||||
sb.append(",");
|
||||
}
|
||||
}
|
||||
sb.append(" WHERE ").append(column).append("=?");
|
||||
}
|
||||
statement = connection.prepareStatement(sb.toString());
|
||||
statement.setString(create ? 1 : columns.length + 1, value);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the entry.
|
||||
* @throws SQLException When an SQL exception occurs.
|
||||
*/
|
||||
public abstract void parse() throws SQLException;
|
||||
|
||||
/**
|
||||
* Creates a new row in the database.
|
||||
* @throws SQLException When an SQL exception occurs.
|
||||
*/
|
||||
public abstract void create() throws SQLException;
|
||||
|
||||
/**
|
||||
* Saves the entry.
|
||||
* @throws SQLException When an SQL exception occurs.
|
||||
*/
|
||||
public abstract void save() throws SQLException;
|
||||
|
||||
/**
|
||||
* Gets the connection.
|
||||
* @return The connection.
|
||||
*/
|
||||
public abstract Connection getConnection();
|
||||
|
||||
}
|
||||
100
Management-Server/src/main/java/ms/system/mysql/SQLManager.java
Normal file
100
Management-Server/src/main/java/ms/system/mysql/SQLManager.java
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
package ms.system.mysql;
|
||||
|
||||
import ms.ServerConstants;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Manages the sql connections.
|
||||
* @author Vexia
|
||||
*
|
||||
*/
|
||||
public final class SQLManager {
|
||||
|
||||
/**
|
||||
* If the sql manager is locally hosted.
|
||||
*/
|
||||
public static final boolean LOCAL = true;
|
||||
|
||||
/**
|
||||
* The database URL.
|
||||
*/
|
||||
public static final String DATABASE_URL = (LOCAL ? "127.0.0.1" : "keldagrim.org") + ":3306/" + (SQLManager.LOCAL ? "global" : ServerConstants.DATABASE_NAMES[1]);
|
||||
|
||||
/**
|
||||
* The username of the user.
|
||||
*/
|
||||
private static final String USERNAME = (LOCAL ? "root" : "keldagr1_user");
|
||||
|
||||
/**
|
||||
* The password of the user.
|
||||
*/
|
||||
private static final String PASSWORD = (LOCAL ? "" : "2jf4wkz$");
|
||||
|
||||
|
||||
/**
|
||||
* IF the sql manager is initialized.
|
||||
*/
|
||||
private static boolean initialized;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code SQLManager} {@code Object}
|
||||
*/
|
||||
public SQLManager() {
|
||||
/**
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the sql manager.
|
||||
*/
|
||||
public static void init() {
|
||||
initialized = true;
|
||||
WorldListSQLHandler.clearWorldList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a connection from the pool.
|
||||
* @return The connection.
|
||||
*/
|
||||
public static Connection getConnection() {
|
||||
try {
|
||||
return DriverManager.getConnection("jdbc:mysql://" + DATABASE_URL + "?useTimezone=true&serverTimezone=UTC", USERNAME, PASSWORD);
|
||||
} catch (SQLException e) {
|
||||
System.out.println("Error: Mysql error message=" + e.getMessage() + ".");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the connection so it's available for usage.
|
||||
* @param connection The connection.
|
||||
*/
|
||||
public static void close(Connection connection) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the initialized.
|
||||
* @return the initialized
|
||||
*/
|
||||
public static boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the bainitialized.
|
||||
* @param initialized the initialized to set.
|
||||
*/
|
||||
public static void setInitialized(boolean initialized) {
|
||||
SQLManager.initialized = initialized;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package ms.system.mysql;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents an SQL table.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class SQLTable {
|
||||
|
||||
/**
|
||||
* The columns.
|
||||
*/
|
||||
private final SQLColumn[] columns;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code SQLTable} {@code Object}.
|
||||
* @param columns The columns.
|
||||
*/
|
||||
public SQLTable(SQLColumn...columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column for the given name.
|
||||
* @param name The column name.
|
||||
* @return The column.
|
||||
*/
|
||||
public SQLColumn getColumn(String name) {
|
||||
for (SQLColumn column : columns) {
|
||||
if (column.getName().equals(name)) {
|
||||
return column;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the changed columns.
|
||||
* @return The columns.
|
||||
*/
|
||||
public List<SQLColumn> getChanged() {
|
||||
List<SQLColumn> updated = new ArrayList<>();
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
SQLColumn column = columns[i];
|
||||
if (column.isChanged()) {
|
||||
updated.add(column);
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the columns.
|
||||
* @return The columns.
|
||||
*/
|
||||
public SQLColumn[] getColumns() {
|
||||
return columns;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package ms.system.mysql;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import ms.world.GameServer;
|
||||
import ms.world.info.WorldInfo;
|
||||
|
||||
/**
|
||||
* Handles the world list SQL database.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class WorldListSQLHandler extends SQLEntryHandler<GameServer> {
|
||||
|
||||
/**
|
||||
* The table for this sql entry.
|
||||
*/
|
||||
private static final String TABLE = "worlds";
|
||||
|
||||
/**
|
||||
* Constructs a new {@code WorldListSQLHandler} {@code Object}.
|
||||
* @param entry The game server entry.
|
||||
*/
|
||||
public WorldListSQLHandler(GameServer entry) {
|
||||
super(entry, TABLE, "world", "" + entry.getInfo().getWorldId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the world list.
|
||||
*/
|
||||
public static void clearWorldList() {
|
||||
try {
|
||||
Connection connection = SQLManager.getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("DELETE FROM " + TABLE);
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void parse() throws SQLException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create() throws SQLException {
|
||||
PreparedStatement statement = connection.prepareStatement("INSERT "+ table + "(world, ip, players, country, member, revision) VALUES('" + value + "', '" + entry.getInfo().getAddress() + "', '" + entry.getPlayerAmount() + "', '" + entry.getInfo().getCountry().getId() + "', '" + (entry.getInfo().isMembers() ? 1 : 0) + "', '" + entry.getInfo().getRevision() + "')");
|
||||
statement.executeUpdate();
|
||||
SQLManager.close(statement.getConnection());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() throws SQLException {
|
||||
super.read();
|
||||
if (result == null || !result.next()) {
|
||||
create();
|
||||
return;
|
||||
}
|
||||
int players = entry.getPlayerAmount();
|
||||
WorldInfo info = entry.getInfo();
|
||||
if (!entry.isActive()) {
|
||||
players = -1;
|
||||
}
|
||||
if (players <= 0) {
|
||||
PreparedStatement statement = connection.prepareStatement("UPDATE members SET online='0' WHERE lastWorld='" + value + "'");
|
||||
statement.executeUpdate();
|
||||
}
|
||||
PreparedStatement statement = connection.prepareStatement("UPDATE " + table + " SET players='" + players + "', ip='" + info.getAddress() + "', country='" + info.getCountry().getId() + "', member='" + (info.isMembers() ? 1 : 0) + "', revision='" + info.getRevision() + "' WHERE world='" + value + "'");
|
||||
statement.executeUpdate();
|
||||
SQLManager.close(statement.getConnection());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return SQLManager.getConnection();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,153 @@
|
|||
package ms.system.util;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
|
||||
/**
|
||||
* Holds utility methods for reading/writing a byte buffer.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class ByteBufferUtils {
|
||||
|
||||
/**
|
||||
* Gets a string from the byte buffer.
|
||||
* @param buffer The byte buffer.
|
||||
* @return The string.
|
||||
*/
|
||||
public static String getString(ByteBuffer buffer) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
byte b;
|
||||
while ((b = buffer.get()) != 0) {
|
||||
sb.append((char) b);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a string on the byte buffer.
|
||||
* @param s The string to put.
|
||||
* @param buffer The byte buffer.
|
||||
*/
|
||||
public static void putString(String s, ByteBuffer buffer) {
|
||||
buffer.put(s.getBytes()).put((byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a string from the byte buffer.
|
||||
* @param s The string.
|
||||
* @param buffer The byte buffer.
|
||||
* @return The string.
|
||||
*/
|
||||
public static ByteBuffer putGJ2String(String s, ByteBuffer buffer) {
|
||||
byte[] packed = new byte[256];
|
||||
int length = packGJString2(0, packed, s);
|
||||
return buffer.put((byte) 0).put(packed, 0, length).put((byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes the XTEA encryption.
|
||||
* @param keys The keys.
|
||||
* @param start The start index.
|
||||
* @param end The end index.
|
||||
* @param buffer The byte buffer.
|
||||
*/
|
||||
public static void decodeXTEA(int[] keys, int start, int end, ByteBuffer buffer) {
|
||||
int l = buffer.position();
|
||||
buffer.position(start);
|
||||
int length = (end - start) / 8;
|
||||
for (int i = 0; i < length; i++) {
|
||||
int firstInt = buffer.getInt();
|
||||
int secondInt = buffer.getInt();
|
||||
int sum = 0xc6ef3720;
|
||||
int delta = 0x9e3779b9;
|
||||
for (int j = 32; j-- > 0;) {
|
||||
secondInt -= keys[(sum & 0x1c84) >>> 11] + sum ^ (firstInt >>> 5 ^ firstInt << 4) + firstInt;
|
||||
sum -= delta;
|
||||
firstInt -= (secondInt >>> 5 ^ secondInt << 4) + secondInt ^ keys[sum & 3] + sum;
|
||||
}
|
||||
buffer.position(buffer.position() - 8);
|
||||
buffer.putInt(firstInt);
|
||||
buffer.putInt(secondInt);
|
||||
}
|
||||
buffer.position(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String to an Integer?
|
||||
*
|
||||
* @param position
|
||||
* The position.
|
||||
* @param buffer
|
||||
* The buffer used.
|
||||
* @param string
|
||||
* The String to convert.
|
||||
* @return The Integer.
|
||||
*/
|
||||
public static int packGJString2(int position, byte[] buffer, String string) {
|
||||
int length = string.length();
|
||||
int offset = position;
|
||||
for (int i = 0; length > i; i++) {
|
||||
int character = string.charAt(i);
|
||||
if (character > 127) {
|
||||
if (character > 2047) {
|
||||
buffer[offset++] = (byte) ((character | 919275) >> 12);
|
||||
buffer[offset++] = (byte) (128 | ((character >> 6) & 63));
|
||||
buffer[offset++] = (byte) (128 | (character & 63));
|
||||
} else {
|
||||
buffer[offset++] = (byte) ((character | 12309) >> 6);
|
||||
buffer[offset++] = (byte) (128 | (character & 63));
|
||||
}
|
||||
} else
|
||||
buffer[offset++] = (byte) character;
|
||||
}
|
||||
return offset - position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a tri-byte from the buffer.
|
||||
* @param buffer The buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
public static int getTriByte(ByteBuffer buffer) {
|
||||
return ((buffer.get() & 0xFF) << 16) + ((buffer.get() & 0xFF) << 8) + (buffer.get() & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a smart from the buffer.
|
||||
* @param buffer The buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
public static int getSmart(ByteBuffer buffer) {
|
||||
int peek = buffer.get() & 0xFF;
|
||||
if (peek <= Byte.MAX_VALUE) {
|
||||
return peek;
|
||||
}
|
||||
return ((peek << 8) | (buffer.get() & 0xFF)) - 32768;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a smart from the buffer.
|
||||
* @param buffer The buffer.
|
||||
* @return The value.
|
||||
*/
|
||||
public static int getBigSmart(ByteBuffer buffer) {
|
||||
int value = 0;
|
||||
int current = getSmart(buffer);
|
||||
while (current == 32767) {
|
||||
current = getSmart(buffer);
|
||||
value += 32767;
|
||||
}
|
||||
value += current;
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code ByteBufferUtils} {@code Object}.
|
||||
*/
|
||||
private ByteBufferUtils() {
|
||||
/*
|
||||
* empty.
|
||||
*/
|
||||
}
|
||||
}
|
||||
52
Management-Server/src/main/java/ms/system/util/Command.java
Normal file
52
Management-Server/src/main/java/ms/system/util/Command.java
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package ms.system.util;
|
||||
|
||||
/**
|
||||
* Represents a command.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public abstract class Command {
|
||||
|
||||
/**
|
||||
* The command name.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The command info.
|
||||
*/
|
||||
private final String info;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code Command} {@code Object}.
|
||||
* @param name The command name.
|
||||
* @param info The command info.
|
||||
*/
|
||||
public Command(String name, String info) {
|
||||
this.name = name;
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the command.
|
||||
* @param args The arguments.
|
||||
*/
|
||||
public abstract void run(String...args);
|
||||
|
||||
/**
|
||||
* Gets the name value.
|
||||
* @return The name.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the info value.
|
||||
* @return The info.
|
||||
*/
|
||||
public String getInfo() {
|
||||
return info;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,815 @@
|
|||
package ms.system.util;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* Represents the class of simple encryption functions.
|
||||
* @author Unknown
|
||||
*/
|
||||
public class EncryptionManager {
|
||||
|
||||
// Define the BCrypt workload to use when generating password hashes. 10-31 is a valid value.
|
||||
private static int workload = 12;
|
||||
|
||||
/**
|
||||
* Singleton instance.
|
||||
*/
|
||||
private static final EncryptionManager INSTANCE = new EncryptionManager();
|
||||
|
||||
/**
|
||||
* Constructs a new {@code EncryptionManager} {@code Object}.
|
||||
*/
|
||||
private EncryptionManager() {
|
||||
//empty.
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be used to generate a string representing an account password
|
||||
* suitable for storing in a database. It will be an OpenBSD-style crypt(3) formatted
|
||||
* hash string of length=60
|
||||
* The bcrypt workload is specified in the above static variable, a value from 10 to 31.
|
||||
* A workload of 12 is a very reasonable safe default as of 2013.
|
||||
* This automatically handles secure 128-bit salt generation and storage within the hash.
|
||||
* @param password_plaintext The account's plaintext password as provided during account creation,
|
||||
* or when changing an account's password.
|
||||
* @return String - a string of length 60 that is the bcrypt hashed password in crypt(3) format.
|
||||
*/
|
||||
public String hashPassword(String password_plaintext) {
|
||||
String salt = BCrypt.gensalt(workload);
|
||||
String hashed_password = BCrypt.hashpw(password_plaintext, salt);
|
||||
return(hashed_password);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method can be used to verify a computed hash from a plaintext (e.g. during a login
|
||||
* request) with that of a stored hash from a database. The password hash from the database
|
||||
* must be passed as the second variable.
|
||||
* @param password_plaintext The account's plaintext password, as provided during a login request
|
||||
* @param stored_hash The account's stored password hash, retrieved from the authorization database
|
||||
* @return boolean - true if the password matches the password of the stored hash, false otherwise
|
||||
*/
|
||||
public boolean checkPassword(String password_plaintext, String stored_hash) {
|
||||
boolean password_verified = false;
|
||||
if(null == stored_hash || !stored_hash.startsWith("$2a$"))
|
||||
throw new java.lang.IllegalArgumentException("Invalid hash provided for comparison");
|
||||
password_verified = BCrypt.checkpw(password_plaintext, stored_hash);
|
||||
return(password_verified);
|
||||
}
|
||||
|
||||
// Copyright (c) 2006 Damien Miller <djm@mindrot.org>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
/**
|
||||
* Gets the instance value.
|
||||
* @return The instance.
|
||||
*/
|
||||
public static EncryptionManager getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* BCrypt implements OpenBSD-style Blowfish password hashing using
|
||||
* the scheme described in "A Future-Adaptable Password Scheme" by
|
||||
* Niels Provos and David Mazieres.
|
||||
* <p>
|
||||
* This password hashing system tries to thwart off-line password
|
||||
* cracking using a computationally-intensive hashing algorithm,
|
||||
* based on Bruce Schneier's Blowfish cipher. The work factor of
|
||||
* the algorithm is parameterised, so it can be increased as
|
||||
* computers get faster.
|
||||
* <p>
|
||||
* Usage is really simple. To hash a password for the first time,
|
||||
* call the hashpw method with a random salt, like this:
|
||||
* <p>
|
||||
* <code>
|
||||
* String pw_hash = BCrypt.hashpw(plain_password, BCrypt.gensalt()); <br />
|
||||
* </code>
|
||||
* <p>
|
||||
* To check whether a plaintext password matches one that has been
|
||||
* hashed previously, use the checkpw method:
|
||||
* <p>
|
||||
* <code>
|
||||
* if (BCrypt.checkpw(candidate_password, stored_hash))<br />
|
||||
* System.out.println("It matches");<br />
|
||||
* else<br />
|
||||
* System.out.println("It does not match");<br />
|
||||
* </code>
|
||||
* <p>
|
||||
* The gensalt() method takes an optional parameter (log_rounds)
|
||||
* that determines the computational complexity of the hashing:
|
||||
* <p>
|
||||
* <code>
|
||||
* String strong_salt = BCrypt.gensalt(10)<br />
|
||||
* String stronger_salt = BCrypt.gensalt(12)<br />
|
||||
* </code>
|
||||
* <p>
|
||||
* The amount of work increases exponentially (2**log_rounds), so
|
||||
* each increment is twice as much work. The default log_rounds is
|
||||
* 10, and the valid range is 4 to 31.
|
||||
*
|
||||
* @author Damien Miller
|
||||
* @version 0.2
|
||||
*/
|
||||
public static class BCrypt {
|
||||
// BCrypt parameters
|
||||
private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10;
|
||||
private static final int BCRYPT_SALT_LEN = 16;
|
||||
|
||||
// Blowfish parameters
|
||||
private static final int BLOWFISH_NUM_ROUNDS = 16;
|
||||
|
||||
// Initial contents of key schedule
|
||||
private static final int P_orig[] = {
|
||||
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
|
||||
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
|
||||
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||||
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
|
||||
0x9216d5d9, 0x8979fb1b
|
||||
};
|
||||
private static final int S_orig[] = {
|
||||
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
|
||||
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
|
||||
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
|
||||
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
|
||||
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
|
||||
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
||||
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
|
||||
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
|
||||
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
|
||||
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
|
||||
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
|
||||
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
||||
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
|
||||
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
|
||||
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
|
||||
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
|
||||
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
|
||||
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
||||
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
|
||||
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
|
||||
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
|
||||
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
|
||||
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
|
||||
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
||||
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
|
||||
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
|
||||
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
|
||||
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
|
||||
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
|
||||
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
||||
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
|
||||
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
|
||||
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
|
||||
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
|
||||
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
|
||||
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
||||
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
|
||||
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
|
||||
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
||||
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
|
||||
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
|
||||
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
||||
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
|
||||
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
|
||||
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
|
||||
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
|
||||
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
|
||||
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
||||
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
|
||||
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
|
||||
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
|
||||
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
|
||||
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
|
||||
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
||||
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
|
||||
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
|
||||
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
|
||||
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
|
||||
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
|
||||
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
||||
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
|
||||
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
|
||||
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
|
||||
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
|
||||
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
|
||||
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
|
||||
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
|
||||
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
|
||||
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
|
||||
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
||||
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
|
||||
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
|
||||
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
|
||||
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
|
||||
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
|
||||
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
||||
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
|
||||
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
|
||||
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
|
||||
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
|
||||
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
|
||||
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
||||
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
|
||||
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
|
||||
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
|
||||
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
|
||||
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
|
||||
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
||||
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
|
||||
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
|
||||
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
|
||||
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
|
||||
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
|
||||
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
||||
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
|
||||
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
|
||||
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
|
||||
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
|
||||
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
|
||||
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
||||
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
|
||||
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
|
||||
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
||||
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
|
||||
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
|
||||
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
||||
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
|
||||
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
|
||||
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
|
||||
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
|
||||
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
|
||||
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
||||
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
|
||||
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
|
||||
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
|
||||
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
|
||||
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
|
||||
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
||||
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
|
||||
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
|
||||
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
|
||||
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
|
||||
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
|
||||
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
||||
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
|
||||
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
|
||||
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
|
||||
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
|
||||
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
|
||||
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
|
||||
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
|
||||
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
|
||||
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
|
||||
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
||||
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
|
||||
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
|
||||
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
|
||||
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
|
||||
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
|
||||
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
||||
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
|
||||
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
|
||||
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
|
||||
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
|
||||
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
|
||||
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
||||
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
|
||||
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
|
||||
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
|
||||
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
|
||||
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
|
||||
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
||||
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
|
||||
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
|
||||
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
|
||||
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
|
||||
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
|
||||
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
||||
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
|
||||
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
|
||||
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
|
||||
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
|
||||
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
|
||||
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
||||
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
|
||||
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
|
||||
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
||||
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
|
||||
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
|
||||
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
||||
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
|
||||
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
|
||||
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
|
||||
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
|
||||
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
|
||||
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
||||
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
|
||||
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
|
||||
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
|
||||
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
|
||||
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
|
||||
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
||||
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
|
||||
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
|
||||
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
|
||||
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
|
||||
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
|
||||
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
||||
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
|
||||
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
|
||||
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
|
||||
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
|
||||
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
|
||||
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
|
||||
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
|
||||
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
|
||||
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
|
||||
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
||||
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
|
||||
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
|
||||
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
|
||||
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
|
||||
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
|
||||
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
||||
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
|
||||
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
|
||||
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
|
||||
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
|
||||
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
|
||||
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
||||
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
|
||||
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
|
||||
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
|
||||
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
|
||||
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
|
||||
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
||||
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
|
||||
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
|
||||
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
|
||||
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
|
||||
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
|
||||
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
||||
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
|
||||
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
|
||||
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
|
||||
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
|
||||
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
|
||||
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
||||
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
|
||||
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
|
||||
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
||||
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
|
||||
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
|
||||
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
||||
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
|
||||
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
|
||||
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
|
||||
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
|
||||
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
|
||||
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
||||
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
|
||||
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
|
||||
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
|
||||
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
|
||||
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
|
||||
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
||||
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
|
||||
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
|
||||
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
|
||||
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
|
||||
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
|
||||
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
||||
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
|
||||
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
|
||||
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
|
||||
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
|
||||
};
|
||||
|
||||
// bcrypt IV: "OrpheanBeholderScryDoubt"
|
||||
static private final int bf_crypt_ciphertext[] = {
|
||||
0x4f727068, 0x65616e42, 0x65686f6c,
|
||||
0x64657253, 0x63727944, 0x6f756274
|
||||
};
|
||||
|
||||
// Table for Base64 encoding
|
||||
static private final char base64_code[] = {
|
||||
'.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
|
||||
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
|
||||
'6', '7', '8', '9'
|
||||
};
|
||||
|
||||
// Table for Base64 decoding
|
||||
static private final byte index_64[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, 0, 1, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63, -1, -1,
|
||||
-1, -1, -1, -1, -1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
||||
-1, -1, -1, -1, -1, -1, 28, 29, 30,
|
||||
31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
||||
51, 52, 53, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
// Expanded Blowfish key
|
||||
private int P[];
|
||||
private int S[];
|
||||
|
||||
/**
|
||||
* Encode a byte array using bcrypt's slightly-modified base64
|
||||
* encoding scheme. Note that this is *not* compatible with
|
||||
* the standard MIME-base64 encoding.
|
||||
*
|
||||
* @param d the byte array to encode
|
||||
* @param len the number of bytes to encode
|
||||
* @return base64-encoded string
|
||||
* @exception IllegalArgumentException if the length is invalid
|
||||
*/
|
||||
private static String encode_base64(byte d[], int len)
|
||||
throws IllegalArgumentException {
|
||||
int off = 0;
|
||||
StringBuffer rs = new StringBuffer();
|
||||
int c1, c2;
|
||||
|
||||
if (len <= 0 || len > d.length)
|
||||
throw new IllegalArgumentException ("Invalid len");
|
||||
|
||||
while (off < len) {
|
||||
c1 = d[off++] & 0xff;
|
||||
rs.append(base64_code[(c1 >> 2) & 0x3f]);
|
||||
c1 = (c1 & 0x03) << 4;
|
||||
if (off >= len) {
|
||||
rs.append(base64_code[c1 & 0x3f]);
|
||||
break;
|
||||
}
|
||||
c2 = d[off++] & 0xff;
|
||||
c1 |= (c2 >> 4) & 0x0f;
|
||||
rs.append(base64_code[c1 & 0x3f]);
|
||||
c1 = (c2 & 0x0f) << 2;
|
||||
if (off >= len) {
|
||||
rs.append(base64_code[c1 & 0x3f]);
|
||||
break;
|
||||
}
|
||||
c2 = d[off++] & 0xff;
|
||||
c1 |= (c2 >> 6) & 0x03;
|
||||
rs.append(base64_code[c1 & 0x3f]);
|
||||
rs.append(base64_code[c2 & 0x3f]);
|
||||
}
|
||||
return rs.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the 3 bits base64-encoded by the specified character,
|
||||
* range-checking againt conversion table
|
||||
* @param x the base64-encoded value
|
||||
* @return the decoded value of x
|
||||
*/
|
||||
private static byte char64(char x) {
|
||||
if ((int)x < 0 || (int)x > index_64.length)
|
||||
return -1;
|
||||
return index_64[(int)x];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a string encoded using bcrypt's base64 scheme to a
|
||||
* byte array. Note that this is *not* compatible with
|
||||
* the standard MIME-base64 encoding.
|
||||
* @param s the string to decode
|
||||
* @param maxolen the maximum number of bytes to decode
|
||||
* @return an array containing the decoded bytes
|
||||
* @throws IllegalArgumentException if maxolen is invalid
|
||||
*/
|
||||
private static byte[] decode_base64(String s, int maxolen)
|
||||
throws IllegalArgumentException {
|
||||
StringBuffer rs = new StringBuffer();
|
||||
int off = 0, slen = s.length(), olen = 0;
|
||||
byte ret[];
|
||||
byte c1, c2, c3, c4, o;
|
||||
|
||||
if (maxolen <= 0)
|
||||
throw new IllegalArgumentException ("Invalid maxolen");
|
||||
|
||||
while (off < slen - 1 && olen < maxolen) {
|
||||
c1 = char64(s.charAt(off++));
|
||||
c2 = char64(s.charAt(off++));
|
||||
if (c1 == -1 || c2 == -1)
|
||||
break;
|
||||
o = (byte)(c1 << 2);
|
||||
o |= (c2 & 0x30) >> 4;
|
||||
rs.append((char)o);
|
||||
if (++olen >= maxolen || off >= slen)
|
||||
break;
|
||||
c3 = char64(s.charAt(off++));
|
||||
if (c3 == -1)
|
||||
break;
|
||||
o = (byte)((c2 & 0x0f) << 4);
|
||||
o |= (c3 & 0x3c) >> 2;
|
||||
rs.append((char)o);
|
||||
if (++olen >= maxolen || off >= slen)
|
||||
break;
|
||||
c4 = char64(s.charAt(off++));
|
||||
o = (byte)((c3 & 0x03) << 6);
|
||||
o |= c4;
|
||||
rs.append((char)o);
|
||||
++olen;
|
||||
}
|
||||
|
||||
ret = new byte[olen];
|
||||
for (off = 0; off < olen; off++)
|
||||
ret[off] = (byte)rs.charAt(off);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blowfish encipher a single 64-bit block encoded as
|
||||
* two 32-bit halves
|
||||
* @param lr an array containing the two 32-bit half blocks
|
||||
* @param off the position in the array of the blocks
|
||||
*/
|
||||
private final void encipher(int lr[], int off) {
|
||||
int i, n, l = lr[off], r = lr[off + 1];
|
||||
|
||||
l ^= P[0];
|
||||
for (i = 0; i <= BLOWFISH_NUM_ROUNDS - 2;) {
|
||||
// Feistel substitution on left word
|
||||
n = S[(l >> 24) & 0xff];
|
||||
n += S[0x100 | ((l >> 16) & 0xff)];
|
||||
n ^= S[0x200 | ((l >> 8) & 0xff)];
|
||||
n += S[0x300 | (l & 0xff)];
|
||||
r ^= n ^ P[++i];
|
||||
|
||||
// Feistel substitution on right word
|
||||
n = S[(r >> 24) & 0xff];
|
||||
n += S[0x100 | ((r >> 16) & 0xff)];
|
||||
n ^= S[0x200 | ((r >> 8) & 0xff)];
|
||||
n += S[0x300 | (r & 0xff)];
|
||||
l ^= n ^ P[++i];
|
||||
}
|
||||
lr[off] = r ^ P[BLOWFISH_NUM_ROUNDS + 1];
|
||||
lr[off + 1] = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycically extract a word of key material
|
||||
* @param data the string to extract the data from
|
||||
* @param offp a "pointer" (as a one-entry array) to the
|
||||
* current offset into data
|
||||
* @return the next word of material from data
|
||||
*/
|
||||
private static int streamtoword(byte data[], int offp[]) {
|
||||
int i;
|
||||
int word = 0;
|
||||
int off = offp[0];
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
word = (word << 8) | (data[off] & 0xff);
|
||||
off = (off + 1) % data.length;
|
||||
}
|
||||
|
||||
offp[0] = off;
|
||||
return word;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the Blowfish key schedule
|
||||
*/
|
||||
private void init_key() {
|
||||
P = (int[])P_orig.clone();
|
||||
S = (int[])S_orig.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Key the Blowfish cipher
|
||||
* @param key an array containing the key
|
||||
*/
|
||||
private void key(byte key[]) {
|
||||
int i;
|
||||
int koffp[] = { 0 };
|
||||
int lr[] = { 0, 0 };
|
||||
int plen = P.length, slen = S.length;
|
||||
|
||||
for (i = 0; i < plen; i++)
|
||||
P[i] = P[i] ^ streamtoword(key, koffp);
|
||||
|
||||
for (i = 0; i < plen; i += 2) {
|
||||
encipher(lr, 0);
|
||||
P[i] = lr[0];
|
||||
P[i + 1] = lr[1];
|
||||
}
|
||||
|
||||
for (i = 0; i < slen; i += 2) {
|
||||
encipher(lr, 0);
|
||||
S[i] = lr[0];
|
||||
S[i + 1] = lr[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the "enhanced key schedule" step described by
|
||||
* Provos and Mazieres in "A Future-Adaptable Password Scheme"
|
||||
* http://www.openbsd.org/papers/bcrypt-paper.ps
|
||||
* @param data salt information
|
||||
* @param key password information
|
||||
*/
|
||||
private void ekskey(byte data[], byte key[]) {
|
||||
int i;
|
||||
int koffp[] = { 0 }, doffp[] = { 0 };
|
||||
int lr[] = { 0, 0 };
|
||||
int plen = P.length, slen = S.length;
|
||||
|
||||
for (i = 0; i < plen; i++)
|
||||
P[i] = P[i] ^ streamtoword(key, koffp);
|
||||
|
||||
for (i = 0; i < plen; i += 2) {
|
||||
lr[0] ^= streamtoword(data, doffp);
|
||||
lr[1] ^= streamtoword(data, doffp);
|
||||
encipher(lr, 0);
|
||||
P[i] = lr[0];
|
||||
P[i + 1] = lr[1];
|
||||
}
|
||||
|
||||
for (i = 0; i < slen; i += 2) {
|
||||
lr[0] ^= streamtoword(data, doffp);
|
||||
lr[1] ^= streamtoword(data, doffp);
|
||||
encipher(lr, 0);
|
||||
S[i] = lr[0];
|
||||
S[i + 1] = lr[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the central password hashing step in the
|
||||
* bcrypt scheme
|
||||
* @param password the password to hash
|
||||
* @param salt the binary salt to hash with the password
|
||||
* @param log_rounds the binary logarithm of the number
|
||||
* of rounds of hashing to apply
|
||||
* @return an array containing the binary hashed password
|
||||
*/
|
||||
private byte[] crypt_raw(byte password[], byte salt[], int log_rounds) {
|
||||
int rounds, i, j;
|
||||
int cdata[] = (int[])bf_crypt_ciphertext.clone();
|
||||
int clen = cdata.length;
|
||||
byte ret[];
|
||||
|
||||
if (log_rounds < 4 || log_rounds > 31)
|
||||
throw new IllegalArgumentException ("Bad number of rounds");
|
||||
rounds = 1 << log_rounds;
|
||||
if (salt.length != BCRYPT_SALT_LEN)
|
||||
throw new IllegalArgumentException ("Bad salt length");
|
||||
|
||||
init_key();
|
||||
ekskey(salt, password);
|
||||
for (i = 0; i < rounds; i++) {
|
||||
key(password);
|
||||
key(salt);
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
for (j = 0; j < (clen >> 1); j++)
|
||||
encipher(cdata, j << 1);
|
||||
}
|
||||
|
||||
ret = new byte[clen * 4];
|
||||
for (i = 0, j = 0; i < clen; i++) {
|
||||
ret[j++] = (byte)((cdata[i] >> 24) & 0xff);
|
||||
ret[j++] = (byte)((cdata[i] >> 16) & 0xff);
|
||||
ret[j++] = (byte)((cdata[i] >> 8) & 0xff);
|
||||
ret[j++] = (byte)(cdata[i] & 0xff);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash a password using the OpenBSD bcrypt scheme
|
||||
* @param password the password to hash
|
||||
* @param salt the salt to hash with (perhaps generated
|
||||
* using BCrypt.gensalt)
|
||||
* @return the hashed password
|
||||
*/
|
||||
public static String hashpw(String password, String salt) {
|
||||
BCrypt B;
|
||||
String real_salt;
|
||||
byte passwordb[], saltb[], hashed[];
|
||||
char minor = (char)0;
|
||||
int rounds, off = 0;
|
||||
StringBuffer rs = new StringBuffer();
|
||||
|
||||
if (salt.charAt(0) != '$' || salt.charAt(1) != '2')
|
||||
throw new IllegalArgumentException ("Invalid salt version");
|
||||
if (salt.charAt(2) == '$')
|
||||
off = 3;
|
||||
else {
|
||||
minor = salt.charAt(2);
|
||||
if (minor != 'a' || salt.charAt(3) != '$')
|
||||
throw new IllegalArgumentException ("Invalid salt revision");
|
||||
off = 4;
|
||||
}
|
||||
|
||||
// Extract number of rounds
|
||||
if (salt.charAt(off + 2) > '$')
|
||||
throw new IllegalArgumentException ("Missing salt rounds");
|
||||
rounds = Integer.parseInt(salt.substring(off, off + 2));
|
||||
|
||||
real_salt = salt.substring(off + 3, off + 25);
|
||||
try {
|
||||
passwordb = (password + (minor >= 'a' ? "\000" : "")).getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
throw new AssertionError("UTF-8 is not supported");
|
||||
}
|
||||
|
||||
saltb = decode_base64(real_salt, BCRYPT_SALT_LEN);
|
||||
|
||||
B = new BCrypt();
|
||||
hashed = B.crypt_raw(passwordb, saltb, rounds);
|
||||
|
||||
rs.append("$2");
|
||||
if (minor >= 'a')
|
||||
rs.append(minor);
|
||||
rs.append("$");
|
||||
if (rounds < 10)
|
||||
rs.append("0");
|
||||
rs.append(Integer.toString(rounds));
|
||||
rs.append("$");
|
||||
rs.append(encode_base64(saltb, saltb.length));
|
||||
rs.append(encode_base64(hashed,
|
||||
bf_crypt_ciphertext.length * 4 - 1));
|
||||
return rs.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a salt for use with the BCrypt.hashpw() method
|
||||
* @param log_rounds the log2 of the number of rounds of
|
||||
* hashing to apply - the work factor therefore increases as
|
||||
* 2**log_rounds.
|
||||
* @param random an instance of SecureRandom to use
|
||||
* @return an encoded salt value
|
||||
*/
|
||||
public static String gensalt(int log_rounds, SecureRandom random) {
|
||||
StringBuffer rs = new StringBuffer();
|
||||
byte rnd[] = new byte[BCRYPT_SALT_LEN];
|
||||
|
||||
random.nextBytes(rnd);
|
||||
|
||||
rs.append("$2a$");
|
||||
if (log_rounds < 10)
|
||||
rs.append("0");
|
||||
rs.append(Integer.toString(log_rounds));
|
||||
rs.append("$");
|
||||
rs.append(encode_base64(rnd, rnd.length));
|
||||
return rs.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a salt for use with the BCrypt.hashpw() method
|
||||
* @param log_rounds the log2 of the number of rounds of
|
||||
* hashing to apply - the work factor therefore increases as
|
||||
* 2**log_rounds.
|
||||
* @return an encoded salt value
|
||||
*/
|
||||
public static String gensalt(int log_rounds) {
|
||||
return gensalt(log_rounds, new SecureRandom());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a salt for use with the BCrypt.hashpw() method,
|
||||
* selecting a reasonable default for the number of hashing
|
||||
* rounds to apply
|
||||
* @return an encoded salt value
|
||||
*/
|
||||
public static String gensalt() {
|
||||
return gensalt(GENSALT_DEFAULT_LOG2_ROUNDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a plaintext password matches a previously hashed
|
||||
* one
|
||||
* @param plaintext the plaintext password to verify
|
||||
* @param hashed the previously-hashed password
|
||||
* @return true if the passwords match, false otherwise
|
||||
*/
|
||||
public static boolean checkpw(String plaintext, String hashed) {
|
||||
return (hashed.compareTo(hashpw(plaintext, hashed)) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package ms.system.util;
|
||||
|
||||
/**
|
||||
* Handles generating a player database.
|
||||
* @author Emperor
|
||||
*
|
||||
*/
|
||||
public final class PlayerDatabaseGen {
|
||||
|
||||
/**
|
||||
* The main method.
|
||||
* @param args The arguments.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue