Experimental AutoJCE & Reactor's incorrect parameter
[EXPERIMENTAL] Added the AutoJCE feature to the server source. This is expected to solve the encryption size issue without resorting to overwrite the JCE files on the system. LMPQ now sends players to random starting rooms, GMS-like. Added a server flag for the free market item sold announcement. Tweaked the reactor-hitting system, expecting to solve the incorrect parameter issue on the "multiple players hitting" scenario.
This commit is contained in:
@@ -73,9 +73,9 @@ public class ServerConstants {
|
||||
public static final boolean USE_QUEST_RATE = false; //Exp/Meso gained by quests uses fixed server exp/meso rate times quest rate as multiplier, instead of player rates.
|
||||
public static final boolean USE_MULTIPLE_SAME_EQUIP_DROP = true;//Enables multiple drops by mobs of the same equipment, number of possible drops based on the quantities provided at the drop data.
|
||||
|
||||
|
||||
//Announcement Configuration
|
||||
public static final boolean USE_ANNOUNCE_CHANGEJOB = true; //Automatic message sent to acquantainces when changing jobs.
|
||||
public static final boolean USE_ANNOUNCE_SHOPITEMSOLD = false; //Automatic message sent to owner when an item from the Player Shop or Hired Merchant is sold.
|
||||
public static final boolean USE_ANNOUNCE_CHANGEJOB = false; //Automatic message sent to acquantainces when changing jobs.
|
||||
|
||||
//Server Rates And Experience
|
||||
public static final int EXP_RATE = 10;
|
||||
|
||||
@@ -112,13 +112,12 @@ public class MapleServerHandler extends IoHandlerAdapter {
|
||||
FilePrinter.print(FilePrinter.SESSION, "IoSession with " + session.getRemoteAddress() + " opened on " + sdf.format(Calendar.getInstance().getTime()), false);
|
||||
}
|
||||
|
||||
byte key[] = {0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, (byte) 0xB4, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00};
|
||||
byte ivRecv[] = {70, 114, 122, 82};
|
||||
byte ivSend[] = {82, 48, 120, 115};
|
||||
ivRecv[3] = (byte) (Math.random() * 255);
|
||||
ivSend[3] = (byte) (Math.random() * 255);
|
||||
MapleAESOFB sendCypher = new MapleAESOFB(key, ivSend, (short) (0xFFFF - ServerConstants.VERSION));
|
||||
MapleAESOFB recvCypher = new MapleAESOFB(key, ivRecv, (short) ServerConstants.VERSION);
|
||||
MapleAESOFB sendCypher = new MapleAESOFB(ivSend, (short) (0xFFFF - ServerConstants.VERSION));
|
||||
MapleAESOFB recvCypher = new MapleAESOFB(ivRecv, (short) ServerConstants.VERSION);
|
||||
MapleClient client = new MapleClient(sendCypher, recvCypher, session);
|
||||
client.setWorld(world);
|
||||
client.setChannel(channel);
|
||||
|
||||
@@ -71,10 +71,12 @@ import client.SkillFactory;
|
||||
import client.newyear.NewYearCardRecord;
|
||||
import constants.ItemConstants;
|
||||
import constants.ServerConstants;
|
||||
import java.security.Security;
|
||||
import java.util.Calendar;
|
||||
import net.server.audit.ThreadTracker;
|
||||
import server.quest.MapleQuest;
|
||||
import tools.locks.MonitoredLockType;
|
||||
import tools.AutoJCE;
|
||||
|
||||
public class Server implements Runnable {
|
||||
private static final Set<Integer> activeFly = new HashSet<>();
|
||||
@@ -382,6 +384,8 @@ public class Server implements Runnable {
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.setProperty("wzpath", "wz");
|
||||
Security.setProperty("crypto.policy", "unlimited");
|
||||
AutoJCE.removeCryptographyRestrictions();
|
||||
Server.getInstance().run();
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ public final class ReactorHitHandler extends AbstractMaplePacketHandler {
|
||||
slea.skip(4);
|
||||
int skillid = slea.readInt();
|
||||
MapleReactor reactor = c.getPlayer().getMap().getReactorByOid(oid);
|
||||
if (reactor != null && reactor.isAlive()) {
|
||||
if (reactor != null) {
|
||||
reactor.hitReactor(true, charPos, stance, skillid, c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ public final class CharSelectedHandler extends AbstractMaplePacketHandler {
|
||||
|
||||
Server.getInstance().unregisterLoginState(c);
|
||||
c.updateLoginState(MapleClient.LOGIN_SERVER_TRANSITION);
|
||||
|
||||
String[] socket = Server.getInstance().getIP(c.getWorld(), c.getChannel()).split(":");
|
||||
try {
|
||||
c.announce(MaplePacketCreator.getServerIP(InetAddress.getByName(socket[0]), Integer.parseInt(socket[1]), charId));
|
||||
|
||||
@@ -17,9 +17,9 @@ public class CharSelectedWithPicHandler extends AbstractMaplePacketHandler {
|
||||
String pic = slea.readMapleAsciiString();
|
||||
int charId = slea.readInt();
|
||||
String macs = slea.readMapleAsciiString();
|
||||
String hwid = slea.readMapleAsciiString();
|
||||
String hwid = slea.readMapleAsciiString();
|
||||
c.updateMacs(macs);
|
||||
c.updateHWID(hwid);
|
||||
c.updateHWID(hwid);
|
||||
|
||||
if (c.hasBannedMac() || c.hasBannedHWID()) {
|
||||
c.getSession().close(true);
|
||||
|
||||
@@ -45,7 +45,7 @@ public class NPCScriptManager extends AbstractScriptManager {
|
||||
private Map<MapleClient, Invocable> scripts = new HashMap<>();
|
||||
private static NPCScriptManager instance = new NPCScriptManager();
|
||||
|
||||
public synchronized static NPCScriptManager getInstance() {
|
||||
public static NPCScriptManager getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -140,8 +140,9 @@ public class NPCScriptManager extends AbstractScriptManager {
|
||||
}
|
||||
|
||||
public void dispose(MapleClient c) {
|
||||
if (cms.get(c) != null) {
|
||||
dispose(cms.get(c));
|
||||
NPCConversationManager cm = cms.get(c);
|
||||
if (cm != null) {
|
||||
dispose(cm);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import client.inventory.MapleInventory;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import com.mysql.jdbc.Statement;
|
||||
import constants.ItemConstants;
|
||||
import constants.ServerConstants;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
@@ -192,7 +193,7 @@ public class MapleHiredMerchant extends AbstractMapleMapObject {
|
||||
if (c.getPlayer().getMeso() >= price) {
|
||||
if (canBuy(c, newItem)) {
|
||||
c.getPlayer().gainMeso(-price, false);
|
||||
announceItemSold(newItem, price); // idea thanks to vcoc
|
||||
if(ServerConstants.USE_ANNOUNCE_SHOPITEMSOLD) announceItemSold(newItem, price); // idea thanks to vcoc
|
||||
|
||||
synchronized (sold) {
|
||||
sold.add(new SoldItem(c.getPlayer().getName(), pItem.getItem().getItemId(), quantity, price));
|
||||
|
||||
@@ -25,6 +25,7 @@ import client.MapleCharacter;
|
||||
import client.MapleClient;
|
||||
import client.inventory.Item;
|
||||
import client.inventory.MapleInventoryType;
|
||||
import constants.ServerConstants;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
@@ -35,7 +36,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import tools.locks.MonitoredReentrantLock;
|
||||
import net.SendOpcode;
|
||||
import net.server.Server;
|
||||
import server.MapleInventoryManipulator;
|
||||
import server.MapleItemInformationProvider;
|
||||
import tools.MaplePacketCreator;
|
||||
@@ -216,7 +216,7 @@ public class MaplePlayerShop extends AbstractMapleMapObject {
|
||||
if (canBuy(c, newItem)) {
|
||||
c.getPlayer().gainMeso(-price, false);
|
||||
|
||||
announceItemSold(newItem, price); // idea thanks to vcoc
|
||||
if(ServerConstants.USE_ANNOUNCE_SHOPITEMSOLD) announceItemSold(newItem, price); // idea thanks to vcoc
|
||||
owner.gainMeso(price, true);
|
||||
|
||||
pItem.setBundles((short) (pItem.getBundles() - quantity));
|
||||
|
||||
@@ -55,6 +55,7 @@ public class MapleReactor extends AbstractMapleMapObject {
|
||||
private boolean attackHit;
|
||||
private ScheduledFuture<?> timeoutTask = null;
|
||||
private Lock reactorLock = new MonitoredReentrantLock(MonitoredLockType.REACTOR, true);
|
||||
private Lock hitLock = new MonitoredReentrantLock(MonitoredLockType.REACTOR, true);
|
||||
|
||||
public MapleReactor(MapleReactorStats stats, int rid) {
|
||||
this.evstate = (byte)0;
|
||||
@@ -139,6 +140,10 @@ public class MapleReactor extends AbstractMapleMapObject {
|
||||
public boolean isAlive() {
|
||||
return alive;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return alive && stats.getType(state) != -1;
|
||||
}
|
||||
|
||||
public void setAlive(boolean alive) {
|
||||
this.alive = alive;
|
||||
@@ -227,69 +232,73 @@ public class MapleReactor extends AbstractMapleMapObject {
|
||||
hitReactor(false, 0, (short) 0, 0, c);
|
||||
}
|
||||
|
||||
public synchronized void hitReactor(boolean wHit, int charPos, short stance, int skillid, MapleClient c) {
|
||||
public void hitReactor(boolean wHit, int charPos, short stance, int skillid, MapleClient c) {
|
||||
try {
|
||||
if(!this.isAlive()) {
|
||||
if(!this.isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lockReactor();
|
||||
try {
|
||||
cancelReactorTimeout();
|
||||
attackHit = wHit;
|
||||
if(hitLock.tryLock()) {
|
||||
this.lockReactor();
|
||||
try {
|
||||
cancelReactorTimeout();
|
||||
attackHit = wHit;
|
||||
|
||||
if(ServerConstants.USE_DEBUG == true) c.getPlayer().dropMessage(5, "Hitted REACTOR " + this.getId() + " with POS " + charPos + " , STANCE " + stance + " , SkillID " + skillid + " , STATE " + stats.getType(state) + " STATESIZE " + stats.getStateSize(state));
|
||||
ReactorScriptManager.getInstance().onHit(c, this);
|
||||
if(ServerConstants.USE_DEBUG == true) c.getPlayer().dropMessage(5, "Hitted REACTOR " + this.getId() + " with POS " + charPos + " , STANCE " + stance + " , SkillID " + skillid + " , STATE " + stats.getType(state) + " STATESIZE " + stats.getStateSize(state));
|
||||
ReactorScriptManager.getInstance().onHit(c, this);
|
||||
|
||||
int reactorType = stats.getType(state);
|
||||
if (reactorType < 999 && reactorType != -1) {//type 2 = only hit from right (kerning swamp plants), 00 is air left 02 is ground left
|
||||
if (!(reactorType == 2 && (stance == 0 || stance == 2))) { //get next state
|
||||
for (byte b = 0; b < stats.getStateSize(state); b++) {//YAY?
|
||||
List<Integer> activeSkills = stats.getActiveSkills(state, b);
|
||||
if (activeSkills != null) {
|
||||
if (!activeSkills.contains(skillid)) continue;
|
||||
}
|
||||
state = stats.getNextState(state, b);
|
||||
if (stats.getNextState(state, b) == -1) {//end of reactor
|
||||
if (reactorType < 100) {//reactor broken
|
||||
if (delay > 0) {
|
||||
map.destroyReactor(getObjectId());
|
||||
} else {//trigger as normal
|
||||
int reactorType = stats.getType(state);
|
||||
if (reactorType < 999 && reactorType != -1) {//type 2 = only hit from right (kerning swamp plants), 00 is air left 02 is ground left
|
||||
if (!(reactorType == 2 && (stance == 0 || stance == 2))) { //get next state
|
||||
for (byte b = 0; b < stats.getStateSize(state); b++) {//YAY?
|
||||
List<Integer> activeSkills = stats.getActiveSkills(state, b);
|
||||
if (activeSkills != null) {
|
||||
if (!activeSkills.contains(skillid)) continue;
|
||||
}
|
||||
state = stats.getNextState(state, b);
|
||||
if (stats.getNextState(state, b) == -1) {//end of reactor
|
||||
if (reactorType < 100) {//reactor broken
|
||||
if (delay > 0) {
|
||||
map.destroyReactor(getObjectId());
|
||||
} else {//trigger as normal
|
||||
map.broadcastMessage(MaplePacketCreator.triggerReactor(this, stance));
|
||||
}
|
||||
} else {//item-triggered on final step
|
||||
map.broadcastMessage(MaplePacketCreator.triggerReactor(this, stance));
|
||||
}
|
||||
} else {//item-triggered on final step
|
||||
map.broadcastMessage(MaplePacketCreator.triggerReactor(this, stance));
|
||||
}
|
||||
|
||||
ReactorScriptManager.getInstance().act(c, this);
|
||||
} else { //reactor not broken yet
|
||||
map.broadcastMessage(MaplePacketCreator.triggerReactor(this, stance));
|
||||
if (state == stats.getNextState(state, b)) {//current state = next state, looping reactor
|
||||
ReactorScriptManager.getInstance().act(c, this);
|
||||
}
|
||||
} else { //reactor not broken yet
|
||||
map.broadcastMessage(MaplePacketCreator.triggerReactor(this, stance));
|
||||
if (state == stats.getNextState(state, b)) {//current state = next state, looping reactor
|
||||
ReactorScriptManager.getInstance().act(c, this);
|
||||
}
|
||||
|
||||
setShouldCollect(true); // refresh collectability on item drop-based reactors
|
||||
refreshReactorTimeout();
|
||||
if(stats.getType(state) == 100) {
|
||||
map.searchItemReactors(this);
|
||||
setShouldCollect(true); // refresh collectability on item drop-based reactors
|
||||
refreshReactorTimeout();
|
||||
if(stats.getType(state) == 100) {
|
||||
map.searchItemReactors(this);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
state++;
|
||||
map.broadcastMessage(MaplePacketCreator.triggerReactor(this, stance));
|
||||
ReactorScriptManager.getInstance().act(c, this);
|
||||
|
||||
setShouldCollect(true);
|
||||
refreshReactorTimeout();
|
||||
if(stats.getType(state) == 100) {
|
||||
map.searchItemReactors(this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
state++;
|
||||
map.broadcastMessage(MaplePacketCreator.triggerReactor(this, stance));
|
||||
ReactorScriptManager.getInstance().act(c, this);
|
||||
|
||||
setShouldCollect(true);
|
||||
refreshReactorTimeout();
|
||||
if(stats.getType(state) == 100) {
|
||||
map.searchItemReactors(this);
|
||||
}
|
||||
} finally {
|
||||
this.unlockReactor();
|
||||
}
|
||||
} finally {
|
||||
this.unlockReactor();
|
||||
|
||||
hitLock.unlock();
|
||||
}
|
||||
} catch(Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
61
src/tools/AutoJCE.java
Normal file
61
src/tools/AutoJCE.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package tools;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.Permission;
|
||||
import java.security.PermissionCollection;
|
||||
import java.util.Map;
|
||||
|
||||
public class AutoJCE{ // AutoJCE into server source thanks to Kradi-a
|
||||
|
||||
/**
|
||||
* Credits: ntoskrnl of StackOverflow
|
||||
* http://stackoverflow.com/questions/1179672/
|
||||
*/
|
||||
public static byte removeCryptographyRestrictions(){
|
||||
if(!isRestrictedCryptography()){
|
||||
//System.out.println("Cryptography restrictions removal not needed");
|
||||
return 0;
|
||||
}
|
||||
try{
|
||||
/*
|
||||
* Do the following, but with reflection to bypass access checks:
|
||||
*
|
||||
* JceSecurity.isRestricted = false;
|
||||
* JceSecurity.defaultPolicy.perms.clear();
|
||||
* JceSecurity.defaultPolicy.add(CryptoAllPermission.INSTANCE);
|
||||
*/
|
||||
final Class<?> jceSecurity = Class.forName("javax.crypto.JceSecurity");
|
||||
final Class<?> cryptoPermissions = Class.forName("javax.crypto.CryptoPermissions");
|
||||
final Class<?> cryptoAllPermission = Class.forName("javax.crypto.CryptoAllPermission");
|
||||
final Field isRestrictedField = jceSecurity.getDeclaredField("isRestricted");// was set to final in Java 8 Update 112. Requires you to remove the final modifier.
|
||||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||
modifiersField.setAccessible(true);
|
||||
modifiersField.setInt(isRestrictedField, isRestrictedField.getModifiers() & ~Modifier.FINAL);
|
||||
isRestrictedField.setAccessible(true);
|
||||
isRestrictedField.set(null, false);
|
||||
final Field defaultPolicyField = jceSecurity.getDeclaredField("defaultPolicy");
|
||||
defaultPolicyField.setAccessible(true);
|
||||
final PermissionCollection defaultPolicy = (PermissionCollection) defaultPolicyField.get(null);
|
||||
final Field perms = cryptoPermissions.getDeclaredField("perms");
|
||||
perms.setAccessible(true);
|
||||
((Map<?, ?>) perms.get(defaultPolicy)).clear();
|
||||
final Field instance = cryptoAllPermission.getDeclaredField("INSTANCE");
|
||||
instance.setAccessible(true);
|
||||
defaultPolicy.add((Permission) instance.get(null));
|
||||
|
||||
//System.out.println("Successfully removed cryptography restrictions");
|
||||
return 1;
|
||||
}catch(final Exception e){
|
||||
e.printStackTrace();
|
||||
|
||||
System.err.println("Failed to remove cryptography restrictions");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isRestrictedCryptography(){
|
||||
// This simply matches the Oracle JRE, but not OpenJDK.
|
||||
return "Java(TM) SE Runtime Environment".equals(System.getProperty("java.runtime.name"));
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,9 @@ public class MapleAESOFB {
|
||||
private byte iv[];
|
||||
private Cipher cipher;
|
||||
private short mapleVersion;
|
||||
private final static SecretKeySpec skey = new SecretKeySpec(
|
||||
new byte[]{0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, (byte) 0xB4, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00}, "AES");
|
||||
|
||||
private static final byte[] funnyBytes = new byte[]{(byte) 0xEC, (byte) 0x3F, (byte) 0x77, (byte) 0xA4, (byte) 0x45, (byte) 0xD0, (byte) 0x71, (byte) 0xBF, (byte) 0xB7, (byte) 0x98, (byte) 0x20, (byte) 0xFC,
|
||||
(byte) 0x4B, (byte) 0xE9, (byte) 0xB3, (byte) 0xE1, (byte) 0x5C, (byte) 0x22, (byte) 0xF7, (byte) 0x0C, (byte) 0x44, (byte) 0x1B, (byte) 0x81, (byte) 0xBD, (byte) 0x63, (byte) 0x8D, (byte) 0xD4, (byte) 0xC3,
|
||||
(byte) 0xF2, (byte) 0x10, (byte) 0x19, (byte) 0xE0, (byte) 0xFB, (byte) 0xA1, (byte) 0x6E, (byte) 0x66, (byte) 0xEA, (byte) 0xAE, (byte) 0xD6, (byte) 0xCE, (byte) 0x06, (byte) 0x18, (byte) 0x4E, (byte) 0xEB,
|
||||
@@ -51,19 +54,16 @@ public class MapleAESOFB {
|
||||
(byte) 0xD3, (byte) 0xAB, (byte) 0x91, (byte) 0xB9, (byte) 0x84, (byte) 0x7F, (byte) 0x61, (byte) 0x1E, (byte) 0xCF, (byte) 0xC5, (byte) 0xD1, (byte) 0x56, (byte) 0x3D, (byte) 0xCA, (byte) 0xF4, (byte) 0x05,
|
||||
(byte) 0xC6, (byte) 0xE5, (byte) 0x08, (byte) 0x49};
|
||||
|
||||
public MapleAESOFB(byte key[], byte iv[], short mapleVersion) {
|
||||
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
|
||||
public MapleAESOFB(byte iv[], short mapleVersion) {
|
||||
try {
|
||||
cipher = Cipher.getInstance("AES");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, skey);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
System.out.println("ERROR " + e);
|
||||
} catch (NoSuchPaddingException e) {
|
||||
System.out.println("ERROR " + e);
|
||||
}
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
|
||||
} catch (InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("Error initalizing the encryption cipher. Make sure you're using the Unlimited Strength cryptography jar files.");
|
||||
}
|
||||
this.setIv(iv);
|
||||
this.mapleVersion = (short) (((mapleVersion >> 8) & 0xFF) | ((mapleVersion << 8) & 0xFF00));
|
||||
|
||||
Reference in New Issue
Block a user