From c1dc90a6e0f4c3e252140b78fd01b6b7dd8aa7ae Mon Sep 17 00:00:00 2001 From: mobius <8391001+MobiusDevelopment@users.noreply.github.com> Date: Mon, 26 Jan 2015 00:20:05 +0000 Subject: [PATCH] L2J_GeoDriver, java-engine-1.8 and mmocore libraries are dropped and directly integrated to project under "com.l2jserver.commons". --- trunk/.classpath | 3 - trunk/build.xml | 4 +- .../admincommandhandlers/AdminPForge.java | 3 +- trunk/dist/libs/L2J_GeoDriver.jar | Bin 22376 -> 0 bytes trunk/dist/libs/java-engine-1.8.jar | Bin 19106 -> 0 bytes trunk/dist/libs/mmocore.jar | Bin 19607 -> 0 bytes .../com/l2jserver/commons/geodriver/Cell.java | 50 ++ .../commons/geodriver/GeoDriver.java | 184 +++++ .../l2jserver/commons/geodriver/IBlock.java | 52 ++ .../l2jserver/commons/geodriver/IRegion.java | 57 ++ .../geodriver/blocks/AbstractBlock.java | 54 ++ .../geodriver/blocks/ComplexBlock.java | 89 +++ .../commons/geodriver/blocks/FlatBlock.java | 64 ++ .../geodriver/blocks/MultilayerBlock.java | 196 +++++ .../commons/geodriver/regions/NullRegion.java | 83 +++ .../commons/geodriver/regions/Region.java | 116 +++ .../javaengine/CompilationException.java | 11 + .../commons/javaengine/JavaCompiler.java | 125 ++++ .../commons/javaengine/JavaScriptEngine.java | 500 +++++++++++++ .../javaengine/JavaScriptEngineFactory.java | 216 ++++++ .../commons/javaengine/MemoryClassLoader.java | 123 +++ .../javaengine/MemoryJavaFileManager.java | 163 ++++ .../commons/mmocore/AbstractPacket.java | 36 + .../commons/mmocore/IAcceptFilter.java | 28 + .../commons/mmocore/IClientFactory.java | 27 + .../commons/mmocore/IMMOExecutor.java | 27 + .../commons/mmocore/IPacketHandler.java | 29 + .../l2jserver/commons/mmocore/MMOClient.java | 47 ++ .../commons/mmocore/MMOConnection.java | 288 +++++++ .../commons/mmocore/NioNetStackList.java | 102 +++ .../commons/mmocore/NioNetStringBuffer.java | 62 ++ .../commons/mmocore/ReceivablePacket.java | 141 ++++ .../commons/mmocore/SelectorConfig.java | 64 ++ .../commons/mmocore/SelectorThread.java | 703 ++++++++++++++++++ .../commons/mmocore/SendablePacket.java | 120 +++ .../com/l2jserver/gameserver/GameServer.java | 5 +- .../com/l2jserver/gameserver/GeoData.java | 4 +- .../gameserver/network/L2GameClient.java | 7 +- .../network/L2GamePacketHandler.java | 11 +- .../clientpackets/L2GameClientPacket.java | 3 +- .../serverpackets/L2GameServerPacket.java | 3 +- .../pathfinding/cellnodes/NodeLoc.java | 2 +- .../gameserver/script/Expression.java | 28 - .../scripting/L2ScriptEngineManager.java | 97 +-- .../l2jserver/gameserver/util/GeoUtils.java | 2 +- .../l2jserver/loginserver/L2LoginServer.java | 5 +- .../l2jserver/loginserver/SelectorHelper.java | 11 +- .../loginserver/network/L2LoginClient.java | 7 +- .../network/L2LoginPacketHandler.java | 5 +- .../clientpackets/L2LoginClientPacket.java | 3 +- .../serverpackets/L2LoginServerPacket.java | 3 +- trunk/java/com/l2jserver/util/IPv4Filter.java | 2 +- trunk/launcher/Gameserver.launch | 2 +- trunk/launcher/Loginserver.launch | 2 +- 54 files changed, 3801 insertions(+), 168 deletions(-) delete mode 100644 trunk/dist/libs/L2J_GeoDriver.jar delete mode 100644 trunk/dist/libs/java-engine-1.8.jar delete mode 100644 trunk/dist/libs/mmocore.jar create mode 100644 trunk/java/com/l2jserver/commons/geodriver/Cell.java create mode 100644 trunk/java/com/l2jserver/commons/geodriver/GeoDriver.java create mode 100644 trunk/java/com/l2jserver/commons/geodriver/IBlock.java create mode 100644 trunk/java/com/l2jserver/commons/geodriver/IRegion.java create mode 100644 trunk/java/com/l2jserver/commons/geodriver/blocks/AbstractBlock.java create mode 100644 trunk/java/com/l2jserver/commons/geodriver/blocks/ComplexBlock.java create mode 100644 trunk/java/com/l2jserver/commons/geodriver/blocks/FlatBlock.java create mode 100644 trunk/java/com/l2jserver/commons/geodriver/blocks/MultilayerBlock.java create mode 100644 trunk/java/com/l2jserver/commons/geodriver/regions/NullRegion.java create mode 100644 trunk/java/com/l2jserver/commons/geodriver/regions/Region.java create mode 100644 trunk/java/com/l2jserver/commons/javaengine/CompilationException.java create mode 100644 trunk/java/com/l2jserver/commons/javaengine/JavaCompiler.java create mode 100644 trunk/java/com/l2jserver/commons/javaengine/JavaScriptEngine.java create mode 100644 trunk/java/com/l2jserver/commons/javaengine/JavaScriptEngineFactory.java create mode 100644 trunk/java/com/l2jserver/commons/javaengine/MemoryClassLoader.java create mode 100644 trunk/java/com/l2jserver/commons/javaengine/MemoryJavaFileManager.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/AbstractPacket.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/IAcceptFilter.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/IClientFactory.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/IMMOExecutor.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/IPacketHandler.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/MMOClient.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/MMOConnection.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/NioNetStackList.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/NioNetStringBuffer.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/ReceivablePacket.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/SelectorConfig.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/SelectorThread.java create mode 100644 trunk/java/com/l2jserver/commons/mmocore/SendablePacket.java diff --git a/trunk/.classpath b/trunk/.classpath index 3870301d52..7b1b1831ad 100644 --- a/trunk/.classpath +++ b/trunk/.classpath @@ -3,11 +3,8 @@ - - - diff --git a/trunk/build.xml b/trunk/build.xml index 4474474005..6695fe3d5b 100644 --- a/trunk/build.xml +++ b/trunk/build.xml @@ -83,12 +83,14 @@ + + - + diff --git a/trunk/dist/game/data/scripts/handlers/admincommandhandlers/AdminPForge.java b/trunk/dist/game/data/scripts/handlers/admincommandhandlers/AdminPForge.java index ec8f67e9bc..37d82e759d 100644 --- a/trunk/dist/game/data/scripts/handlers/admincommandhandlers/AdminPForge.java +++ b/trunk/dist/game/data/scripts/handlers/admincommandhandlers/AdminPForge.java @@ -24,8 +24,7 @@ import java.util.Collection; import java.util.LinkedList; import java.util.StringTokenizer; -import org.mmocore.network.NioNetStringBuffer; - +import com.l2jserver.commons.mmocore.NioNetStringBuffer; import com.l2jserver.gameserver.GameServer; import com.l2jserver.gameserver.ThreadPoolManager; import com.l2jserver.gameserver.cache.HtmCache; diff --git a/trunk/dist/libs/L2J_GeoDriver.jar b/trunk/dist/libs/L2J_GeoDriver.jar deleted file mode 100644 index 7869d6aad90a6f30619cde2b9a05f46059e7ea15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22376 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 V;{x?>EG#Smd>tE%|XNv#; diff --git a/trunk/dist/libs/java-engine-1.8.jar b/trunk/dist/libs/java-engine-1.8.jar deleted file mode 100644 index 1facd14b95bb5ae3a1dfa60a943469eac2d5ffc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19106 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 diff --git a/trunk/dist/libs/mmocore.jar b/trunk/dist/libs/mmocore.jar deleted file mode 100644 index f6a1f89f2933fa324a05524868c486b953add2dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19607 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 W;LQrmuMEI5#6%b(fGkZn5Dx%Hs*R!m diff --git a/trunk/java/com/l2jserver/commons/geodriver/Cell.java b/trunk/java/com/l2jserver/commons/geodriver/Cell.java new file mode 100644 index 0000000000..3a5f16d7c8 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/geodriver/Cell.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2004-2015 L2J Server + * + * This file is part of L2J Server. + * + * L2J Server is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * L2J Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jserver.commons.geodriver; + +/** + * @author HorridoJoho + */ +public final class Cell +{ + /** East NSWE flag */ + public static final byte NSWE_EAST = 1 << 0; + /** West NSWE flag */ + public static final byte NSWE_WEST = 1 << 1; + /** South NSWE flag */ + public static final byte NSWE_SOUTH = 1 << 2; + /** North NSWE flag */ + public static final byte NSWE_NORTH = 1 << 3; + + /** North-East NSWE flags */ + public static final byte NSWE_NORTH_EAST = NSWE_NORTH | NSWE_EAST; + /** North-West NSWE flags */ + public static final byte NSWE_NORTH_WEST = NSWE_NORTH | NSWE_WEST; + /** South-East NSWE flags */ + public static final byte NSWE_SOUTH_EAST = NSWE_SOUTH | NSWE_EAST; + /** South-West NSWE flags */ + public static final byte NSWE_SOUTH_WEST = NSWE_SOUTH | NSWE_WEST; + + /** All directions NSWE flags */ + public static final byte NSWE_ALL = NSWE_EAST | NSWE_WEST | NSWE_SOUTH | NSWE_NORTH; + + private Cell() + { + } +} diff --git a/trunk/java/com/l2jserver/commons/geodriver/GeoDriver.java b/trunk/java/com/l2jserver/commons/geodriver/GeoDriver.java new file mode 100644 index 0000000000..174d683bc0 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/geodriver/GeoDriver.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2004-2015 L2J Server + * + * This file is part of L2J Server. + * + * L2J Server is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * L2J Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jserver.commons.geodriver; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel.MapMode; +import java.nio.file.Path; +import java.util.concurrent.atomic.AtomicReferenceArray; + +import com.l2jserver.commons.geodriver.regions.NullRegion; +import com.l2jserver.commons.geodriver.regions.Region; + +/** + * @author HorridoJoho + */ +public final class GeoDriver +{ + // world dimensions: 1048576 * 1048576 = 1099511627776 + private static final int WORLD_MIN_X = -655360; + private static final int WORLD_MAX_X = 393215; + private static final int WORLD_MIN_Y = -589824; + private static final int WORLD_MAX_Y = 458751; + + /** Regions in the world on the x axis */ + public static final int GEO_REGIONS_X = 32; + /** Regions in the world on the y axis */ + public static final int GEO_REGIONS_Y = 32; + /** Region in the world */ + public static final int GEO_REGIONS = GEO_REGIONS_X * GEO_REGIONS_Y; + + /** Blocks in the world on the x axis */ + public static final int GEO_BLOCKS_X = GEO_REGIONS_X * IRegion.REGION_BLOCKS_X; + /** Blocks in the world on the y axis */ + public static final int GEO_BLOCKS_Y = GEO_REGIONS_Y * IRegion.REGION_BLOCKS_Y; + /** Blocks in the world */ + public static final int GEO_BLOCKS = GEO_REGIONS * IRegion.REGION_BLOCKS; + + /** Cells in the world on the x axis */ + public static final int GEO_CELLS_X = GEO_BLOCKS_X * IBlock.BLOCK_CELLS_X; + /** Cells in the world in the y axis */ + public static final int GEO_CELLS_Y = GEO_BLOCKS_Y * IBlock.BLOCK_CELLS_Y; + + /** The regions array */ + private final AtomicReferenceArray _regions = new AtomicReferenceArray<>(GEO_REGIONS); + + public GeoDriver() + { + for (int i = 0; i < _regions.length(); i++) + { + _regions.set(i, NullRegion.INSTANCE); + } + } + + private void checkGeoX(int geoX) + { + if ((geoX < 0) || (geoX >= GEO_CELLS_X)) + { + throw new IllegalArgumentException(); + } + } + + private void checkGeoY(int geoY) + { + if ((geoY < 0) || (geoY >= GEO_CELLS_Y)) + { + throw new IllegalArgumentException(); + } + } + + private IRegion getRegion(int geoX, int geoY) + { + checkGeoX(geoX); + checkGeoY(geoY); + return _regions.get(((geoX / IRegion.REGION_CELLS_X) * GEO_REGIONS_Y) + (geoY / IRegion.REGION_CELLS_Y)); + } + + public void loadRegion(Path filePath, int regionX, int regionY) throws IOException + { + final int regionOffset = (regionX * GEO_REGIONS_Y) + regionY; + + try (RandomAccessFile raf = new RandomAccessFile(filePath.toFile(), "r")) + { + _regions.set(regionOffset, new Region(raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length()).order(ByteOrder.LITTLE_ENDIAN))); + } + } + + public void unloadRegion(int regionX, int regionY) + { + _regions.set((regionX * GEO_REGIONS_Y) + regionY, NullRegion.INSTANCE); + } + + public boolean hasGeoPos(int geoX, int geoY) + { + return getRegion(geoX, geoY).hasGeo(); + } + + public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe) + { + return getRegion(geoX, geoY).checkNearestNswe(geoX, geoY, worldZ, nswe); + } + + public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe, int zDeltaLimit) + { + return getRegion(geoX, geoY).checkNearestNswe(geoX, geoY, worldZ, nswe, zDeltaLimit); + } + + public int getNearestZ(int geoX, int geoY, int worldZ) + { + return getRegion(geoX, geoY).getNearestZ(geoX, geoY, worldZ); + } + + public int getNearestZ(int geoX, int geoY, int worldZ, int zDeltaLimit) + { + return getRegion(geoX, geoY).getNearestZ(geoX, geoY, worldZ, zDeltaLimit); + } + + public int getNextLowerZ(int geoX, int geoY, int worldZ) + { + return getRegion(geoX, geoY).getNextLowerZ(geoX, geoY, worldZ); + } + + public int getNextLowerZ(int geoX, int geoY, int worldZ, int zDeltaLimit) + { + return getRegion(geoX, geoY).getNextLowerZ(geoX, geoY, worldZ, zDeltaLimit); + } + + public int getNextHigherZ(int geoX, int geoY, int worldZ) + { + return getRegion(geoX, geoY).getNextHigherZ(geoX, geoY, worldZ); + } + + public int getNextHigherZ(int geoX, int geoY, int worldZ, int zDeltaLimit) + { + return getRegion(geoX, geoY).getNextHigherZ(geoX, geoY, worldZ, zDeltaLimit); + } + + public int getGeoX(int worldX) + { + if ((worldX < WORLD_MIN_X) || (worldX > WORLD_MAX_X)) + { + throw new IllegalArgumentException(); + } + return (worldX - WORLD_MIN_X) / 16; + } + + public int getGeoY(int worldY) + { + if ((worldY < WORLD_MIN_Y) || (worldY > WORLD_MAX_Y)) + { + throw new IllegalArgumentException(); + } + return (worldY - WORLD_MIN_Y) / 16; + } + + public int getWorldX(int geoX) + { + checkGeoX(geoX); + return (geoX * 16) + WORLD_MIN_X + 8; + } + + public int getWorldY(int geoY) + { + checkGeoY(geoY); + return (geoY * 16) + WORLD_MIN_Y + 8; + } +} diff --git a/trunk/java/com/l2jserver/commons/geodriver/IBlock.java b/trunk/java/com/l2jserver/commons/geodriver/IBlock.java new file mode 100644 index 0000000000..8b873872c9 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/geodriver/IBlock.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2004-2015 L2J Server + * + * This file is part of L2J Server. + * + * L2J Server is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * L2J Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jserver.commons.geodriver; + +/** + * @author HorridoJoho + */ +public interface IBlock +{ + public static final int TYPE_FLAT = 0; + public static final int TYPE_COMPLEX = 1; + public static final int TYPE_MULTILAYER = 2; + + /** Cells in a block on the x axis */ + public static final int BLOCK_CELLS_X = 8; + /** Cells in a block on the y axis */ + public static final int BLOCK_CELLS_Y = 8; + /** Cells in a block */ + public static final int BLOCK_CELLS = BLOCK_CELLS_X * BLOCK_CELLS_Y; + + boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe); + + boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe, int zDeltaLimit); + + int getNearestZ(int geoX, int geoY, int worldZ); + + int getNearestZ(int geoX, int geoY, int worldZ, int zDeltaLimit); + + int getNextLowerZ(int geoX, int geoY, int worldZ); + + int getNextLowerZ(int geoX, int geoY, int worldZ, int zDeltaLimit); + + int getNextHigherZ(int geoX, int geoY, int worldZ); + + int getNextHigherZ(int geoX, int geoY, int worldZ, int zDeltaLimit); +} diff --git a/trunk/java/com/l2jserver/commons/geodriver/IRegion.java b/trunk/java/com/l2jserver/commons/geodriver/IRegion.java new file mode 100644 index 0000000000..a80b9fe765 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/geodriver/IRegion.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2004-2015 L2J Server + * + * This file is part of L2J Server. + * + * L2J Server is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * L2J Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jserver.commons.geodriver; + +/** + * @author HorridoJoho + */ +public interface IRegion +{ + /** Blocks in a region on the x axis */ + public static final int REGION_BLOCKS_X = 256; + /** Blocks in a region on the y axis */ + public static final int REGION_BLOCKS_Y = 256; + /** Blocks in a region */ + public static final int REGION_BLOCKS = REGION_BLOCKS_X * REGION_BLOCKS_Y; + + /** Cells in a region on the x axis */ + public static final int REGION_CELLS_X = REGION_BLOCKS_X * IBlock.BLOCK_CELLS_X; + /** Cells in a regioin on the y axis */ + public static final int REGION_CELLS_Y = REGION_BLOCKS_Y * IBlock.BLOCK_CELLS_Y; + /** Cells in a region */ + public static final int REGION_CELLS = REGION_CELLS_X * REGION_CELLS_Y; + + boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe); + + boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe, int zDeltaLimit); + + int getNearestZ(int geoX, int geoY, int worldZ); + + int getNearestZ(int geoX, int geoY, int worldZ, int zDeltaLimit); + + int getNextLowerZ(int geoX, int geoY, int worldZ); + + int getNextLowerZ(int geoX, int geoY, int worldZ, int zDeltaLimit); + + int getNextHigherZ(int geoX, int geoY, int worldZ); + + int getNextHigherZ(int geoX, int geoY, int worldZ, int zDeltaLimit); + + boolean hasGeo(); +} diff --git a/trunk/java/com/l2jserver/commons/geodriver/blocks/AbstractBlock.java b/trunk/java/com/l2jserver/commons/geodriver/blocks/AbstractBlock.java new file mode 100644 index 0000000000..322dd515aa --- /dev/null +++ b/trunk/java/com/l2jserver/commons/geodriver/blocks/AbstractBlock.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2004-2015 L2J Server + * + * This file is part of L2J Server. + * + * L2J Server is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * L2J Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jserver.commons.geodriver.blocks; + +import com.l2jserver.commons.geodriver.IBlock; + +/** + * @author HorridoJoho + */ +public abstract class AbstractBlock implements IBlock +{ + private int limitZ(int z, int newZ, int deltaLimit) + { + if (Math.abs(z - newZ) > deltaLimit) + { + return z; + } + return newZ; + } + + @Override + public int getNearestZ(int geoX, int geoY, int worldZ, int zDeltaLimit) + { + return limitZ(worldZ, getNearestZ(geoX, geoY, worldZ), zDeltaLimit); + } + + @Override + public int getNextLowerZ(int geoX, int geoY, int worldZ, int zDeltaLimit) + { + return limitZ(worldZ, getNextLowerZ(geoX, geoY, worldZ), zDeltaLimit); + } + + @Override + public int getNextHigherZ(int geoX, int geoY, int worldZ, int zDeltaLimit) + { + return limitZ(worldZ, getNextHigherZ(geoX, geoY, worldZ), zDeltaLimit); + } +} diff --git a/trunk/java/com/l2jserver/commons/geodriver/blocks/ComplexBlock.java b/trunk/java/com/l2jserver/commons/geodriver/blocks/ComplexBlock.java new file mode 100644 index 0000000000..99dcd188d2 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/geodriver/blocks/ComplexBlock.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2004-2015 L2J Server + * + * This file is part of L2J Server. + * + * L2J Server is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * L2J Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jserver.commons.geodriver.blocks; + +import java.nio.ByteBuffer; + +import com.l2jserver.commons.geodriver.IBlock; + +/** + * @author HorridoJoho + */ +public final class ComplexBlock extends AbstractBlock +{ + private final short[] _data; + + public ComplexBlock(ByteBuffer bb) + { + _data = new short[IBlock.BLOCK_CELLS]; + for (int cellOffset = 0; cellOffset < IBlock.BLOCK_CELLS; cellOffset++) + { + _data[cellOffset] = bb.getShort(); + } + } + + private short _getCellData(int geoX, int geoY) + { + return _data[((geoX % IBlock.BLOCK_CELLS_X) * IBlock.BLOCK_CELLS_Y) + (geoY % IBlock.BLOCK_CELLS_Y)]; + } + + private byte _getCellNSWE(int geoX, int geoY) + { + return (byte) (_getCellData(geoX, geoY) & 0x000F); + } + + private int _getCellHeight(int geoX, int geoY) + { + short height = (short) (_getCellData(geoX, geoY) & 0x0FFF0); + return height >> 1; + } + + @Override + public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe) + { + return (_getCellNSWE(geoX, geoY) & nswe) == nswe; + } + + @Override + public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe, int zDeltaLimit) + { + int height = _getCellHeight(geoX, geoY); + return Math.abs(worldZ - height) > zDeltaLimit ? true : (_getCellNSWE(geoX, geoY) & nswe) == nswe; + } + + @Override + public int getNearestZ(int geoX, int geoY, int worldZ) + { + return _getCellHeight(geoX, geoY); + } + + @Override + public int getNextLowerZ(int geoX, int geoY, int worldZ) + { + int cellHeight = _getCellHeight(geoX, geoY); + return cellHeight <= worldZ ? cellHeight : worldZ; + } + + @Override + public int getNextHigherZ(int geoX, int geoY, int worldZ) + { + int cellHeight = _getCellHeight(geoX, geoY); + return cellHeight >= worldZ ? cellHeight : worldZ; + } +} diff --git a/trunk/java/com/l2jserver/commons/geodriver/blocks/FlatBlock.java b/trunk/java/com/l2jserver/commons/geodriver/blocks/FlatBlock.java new file mode 100644 index 0000000000..aabc43a20b --- /dev/null +++ b/trunk/java/com/l2jserver/commons/geodriver/blocks/FlatBlock.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2004-2015 L2J Server + * + * This file is part of L2J Server. + * + * L2J Server is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * L2J Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jserver.commons.geodriver.blocks; + +import java.nio.ByteBuffer; + +/** + * @author HorridoJoho + */ +public class FlatBlock extends AbstractBlock +{ + private final short _height; + + public FlatBlock(ByteBuffer bb) + { + _height = bb.getShort(); + } + + @Override + public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe) + { + return true; + } + + @Override + public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe, int zDeltaLimit) + { + return true; + } + + @Override + public int getNearestZ(int geoX, int geoY, int worldZ) + { + return _height; + } + + @Override + public int getNextLowerZ(int geoX, int geoY, int worldZ) + { + return _height <= worldZ ? _height : worldZ; + } + + @Override + public int getNextHigherZ(int geoX, int geoY, int worldZ) + { + return _height >= worldZ ? _height : worldZ; + } +} diff --git a/trunk/java/com/l2jserver/commons/geodriver/blocks/MultilayerBlock.java b/trunk/java/com/l2jserver/commons/geodriver/blocks/MultilayerBlock.java new file mode 100644 index 0000000000..df35d0c5d5 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/geodriver/blocks/MultilayerBlock.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2004-2015 L2J Server + * + * This file is part of L2J Server. + * + * L2J Server is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * L2J Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jserver.commons.geodriver.blocks; + +import java.nio.ByteBuffer; + +import com.l2jserver.commons.geodriver.IBlock; + +/** + * @author FBIagent + */ +public class MultilayerBlock extends AbstractBlock +{ + private final byte[] _data; + + /** + * Initializes a new instance of this block reading the specified buffer. + * @param bb the buffer + */ + public MultilayerBlock(ByteBuffer bb) + { + int start = bb.position(); + + for (int blockCellOffset = 0; blockCellOffset < IBlock.BLOCK_CELLS; blockCellOffset++) + { + byte nLayers = bb.get(); + if ((nLayers <= 0) || (nLayers > 125)) + { + throw new RuntimeException("L2JGeoDriver: Geo file corrupted! Invalid layers count!"); + } + + bb.position(bb.position() + (nLayers * 2)); + } + + _data = new byte[bb.position() - start]; + bb.position(start); + bb.get(_data); + } + + private short _getNearestLayer(int geoX, int geoY, int worldZ) + { + int startOffset = _getCellDataOffset(geoX, geoY); + byte nLayers = _data[startOffset]; + int endOffset = startOffset + 1 + (nLayers * 2); + + // 1 layer at least was required on loading so this is set at least once on the loop below + int nearestDZ = 0; + short nearestData = 0; + for (int offset = startOffset + 1; offset < endOffset; offset += 2) + { + short layerData = _extractLayerData(offset); + int layerZ = _extractLayerHeight(layerData); + if (layerZ == worldZ) + { + // exact z + return layerData; + } + + int layerDZ = Math.abs(layerZ - worldZ); + if ((offset == (startOffset + 1)) || (layerDZ < nearestDZ)) + { + nearestDZ = layerDZ; + nearestData = layerData; + } + } + + return nearestData; + } + + private int _getCellDataOffset(int geoX, int geoY) + { + int cellLocalOffset = ((geoX % IBlock.BLOCK_CELLS_X) * IBlock.BLOCK_CELLS_Y) + (geoY % IBlock.BLOCK_CELLS_Y); + int cellDataOffset = 0; + // move index to cell, we need to parse on each request, OR we parse on creation and save indexes + for (int i = 0; i < cellLocalOffset; i++) + { + cellDataOffset += 1 + (_data[cellDataOffset] * 2); + } + // now the index points to the cell we need + + return cellDataOffset; + } + + private short _extractLayerData(int dataOffset) + { + return (short) ((_data[dataOffset] & 0xFF) | (_data[dataOffset + 1] << 8)); + } + + private int _getNearestNSWE(int geoX, int geoY, int worldZ) + { + return _extractLayerNswe(_getNearestLayer(geoX, geoY, worldZ)); + } + + private int _extractLayerNswe(short layer) + { + return (byte) (layer & 0x000F); + } + + private int _extractLayerHeight(short layer) + { + layer = (short) (layer & 0x0fff0); + return layer >> 1; + } + + @Override + public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe) + { + return (_getNearestNSWE(geoX, geoY, worldZ) & nswe) == nswe; + } + + @Override + public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe, int zDeltaLimit) + { + short layer = _getNearestLayer(geoX, geoY, worldZ); + int height = _extractLayerHeight(layer); + return Math.abs(worldZ - height) > zDeltaLimit ? true : (_extractLayerNswe(layer) & nswe) == nswe; + } + + @Override + public int getNearestZ(int geoX, int geoY, int worldZ) + { + return _extractLayerHeight(_getNearestLayer(geoX, geoY, worldZ)); + } + + @Override + public int getNextLowerZ(int geoX, int geoY, int worldZ) + { + int startOffset = _getCellDataOffset(geoX, geoY); + byte nLayers = _data[startOffset]; + int endOffset = startOffset + 1 + (nLayers * 2); + + int lowerZ = Integer.MIN_VALUE; + for (int offset = startOffset + 1; offset < endOffset; offset += 2) + { + short layerData = _extractLayerData(offset); + + int layerZ = _extractLayerHeight(layerData); + if (layerZ == worldZ) + { + // exact z + return layerZ; + } + + if ((layerZ < worldZ) && (layerZ > lowerZ)) + { + lowerZ = layerZ; + } + } + + return lowerZ == Integer.MIN_VALUE ? worldZ : lowerZ; + } + + @Override + public int getNextHigherZ(int geoX, int geoY, int worldZ) + { + int startOffset = _getCellDataOffset(geoX, geoY); + byte nLayers = _data[startOffset]; + int endOffset = startOffset + 1 + (nLayers * 2); + + int higherZ = Integer.MAX_VALUE; + for (int offset = startOffset + 1; offset < endOffset; offset += 2) + { + short layerData = _extractLayerData(offset); + + int layerZ = _extractLayerHeight(layerData); + if (layerZ == worldZ) + { + // exact z + return layerZ; + } + + if ((layerZ > worldZ) && (layerZ < higherZ)) + { + higherZ = layerZ; + } + } + + return higherZ == Integer.MAX_VALUE ? worldZ : higherZ; + } +} diff --git a/trunk/java/com/l2jserver/commons/geodriver/regions/NullRegion.java b/trunk/java/com/l2jserver/commons/geodriver/regions/NullRegion.java new file mode 100644 index 0000000000..db4302531b --- /dev/null +++ b/trunk/java/com/l2jserver/commons/geodriver/regions/NullRegion.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2004-2015 L2J Server + * + * This file is part of L2J Server. + * + * L2J Server is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * L2J Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jserver.commons.geodriver.regions; + +import com.l2jserver.commons.geodriver.IRegion; + +/** + * @author HorridoJoho + */ +public final class NullRegion implements IRegion +{ + public static final NullRegion INSTANCE = new NullRegion(); + + @Override + public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe) + { + return true; + } + + @Override + public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe, int zDeltaLimit) + { + return true; + } + + @Override + public int getNearestZ(int geoX, int geoY, int worldZ) + { + return worldZ; + } + + @Override + public int getNearestZ(int geoX, int geoY, int worldZ, int zDeltaLimit) + { + return worldZ; + } + + @Override + public int getNextLowerZ(int geoX, int geoY, int worldZ) + { + return worldZ; + } + + @Override + public int getNextLowerZ(int geoX, int geoY, int worldZ, int zDeltaLimit) + { + return worldZ; + } + + @Override + public int getNextHigherZ(int geoX, int geoY, int worldZ) + { + return worldZ; + } + + @Override + public int getNextHigherZ(int geoX, int geoY, int worldZ, int zDeltaLimit) + { + return worldZ; + } + + @Override + public boolean hasGeo() + { + return false; + } +} diff --git a/trunk/java/com/l2jserver/commons/geodriver/regions/Region.java b/trunk/java/com/l2jserver/commons/geodriver/regions/Region.java new file mode 100644 index 0000000000..948e8009f1 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/geodriver/regions/Region.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2004-2015 L2J Server + * + * This file is part of L2J Server. + * + * L2J Server is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * L2J Server is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.l2jserver.commons.geodriver.regions; + +import java.nio.ByteBuffer; + +import com.l2jserver.commons.geodriver.IBlock; +import com.l2jserver.commons.geodriver.IRegion; +import com.l2jserver.commons.geodriver.blocks.ComplexBlock; +import com.l2jserver.commons.geodriver.blocks.FlatBlock; +import com.l2jserver.commons.geodriver.blocks.MultilayerBlock; + +/** + * @author HorridoJoho + */ +public final class Region implements IRegion +{ + private final IBlock[] _blocks = new IBlock[IRegion.REGION_BLOCKS]; + + public Region(ByteBuffer bb) + { + for (int blockOffset = 0; blockOffset < IRegion.REGION_BLOCKS; blockOffset++) + { + int blockType = bb.get(); + switch (blockType) + { + case IBlock.TYPE_FLAT: + _blocks[blockOffset] = new FlatBlock(bb); + break; + case IBlock.TYPE_COMPLEX: + _blocks[blockOffset] = new ComplexBlock(bb); + break; + case IBlock.TYPE_MULTILAYER: + _blocks[blockOffset] = new MultilayerBlock(bb); + break; + default: + throw new RuntimeException("Invalid block type " + blockType + "!"); + } + } + } + + private IBlock getBlock(int geoX, int geoY) + { + return _blocks[(((geoX / IBlock.BLOCK_CELLS_X) % IRegion.REGION_BLOCKS_X) * IRegion.REGION_BLOCKS_Y) + ((geoY / IBlock.BLOCK_CELLS_Y) % IRegion.REGION_BLOCKS_Y)]; + } + + @Override + public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe) + { + return getBlock(geoX, geoY).checkNearestNswe(geoX, geoY, worldZ, nswe); + } + + @Override + public boolean checkNearestNswe(int geoX, int geoY, int worldZ, int nswe, int zDeltaLimit) + { + return getBlock(geoX, geoY).checkNearestNswe(geoX, geoY, worldZ, nswe, zDeltaLimit); + } + + @Override + public int getNearestZ(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNearestZ(geoX, geoY, worldZ); + } + + @Override + public int getNearestZ(int geoX, int geoY, int worldZ, int zDeltaLimit) + { + return getBlock(geoX, geoY).getNearestZ(geoX, geoY, worldZ, zDeltaLimit); + } + + @Override + public int getNextLowerZ(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNextLowerZ(geoX, geoY, worldZ); + } + + @Override + public int getNextLowerZ(int geoX, int geoY, int worldZ, int zDeltaLimit) + { + return getBlock(geoX, geoY).getNextLowerZ(geoX, geoY, worldZ, zDeltaLimit); + } + + @Override + public int getNextHigherZ(int geoX, int geoY, int worldZ) + { + return getBlock(geoX, geoY).getNextHigherZ(geoX, geoY, worldZ); + } + + @Override + public int getNextHigherZ(int geoX, int geoY, int worldZ, int zDeltaLimit) + { + return getBlock(geoX, geoY).getNextHigherZ(geoX, geoY, worldZ, zDeltaLimit); + } + + @Override + public boolean hasGeo() + { + return true; + } +} diff --git a/trunk/java/com/l2jserver/commons/javaengine/CompilationException.java b/trunk/java/com/l2jserver/commons/javaengine/CompilationException.java new file mode 100644 index 0000000000..60324f56d1 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/javaengine/CompilationException.java @@ -0,0 +1,11 @@ +package com.l2jserver.commons.javaengine; + +public class CompilationException extends Exception +{ + private static final long serialVersionUID = 1L; + + public CompilationException(String message) + { + super(message); + } +} diff --git a/trunk/java/com/l2jserver/commons/javaengine/JavaCompiler.java b/trunk/java/com/l2jserver/commons/javaengine/JavaCompiler.java new file mode 100644 index 0000000000..49a15e3551 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/javaengine/JavaCompiler.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: Redistributions of source code + * must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. Neither the name of the Sun Microsystems nor the names of + * is contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.l2jserver.commons.javaengine; + +import java.io.PrintWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.JavaFileObject; + +import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler; + +/** + * Simple interface to Java compiler using JSR 199 Compiler API. + * @author A. Sundararajan + */ +public class JavaCompiler +{ + private final javax.tools.JavaCompiler tool; + + public JavaCompiler() + { + tool = new EclipseCompiler(); + } + + public Map compile(String source, String fileName) + { + PrintWriter err = new PrintWriter(System.err); + return compile(source, fileName, err, null, null); + } + + public Map compile(String fileName, String source, Writer err) + { + return compile(fileName, source, err, null, null); + } + + public Map compile(String fileName, String source, Writer err, String sourcePath) + { + return compile(fileName, source, err, sourcePath, null); + } + + /** + * compile given String source and return bytecodes as a Map. + * @param fileName source fileName to be used for error messages etc. + * @param source Java source as String + * @param err error writer where diagnostic messages are written + * @param sourcePath location of additional .java source files + * @param classPath location of additional .class files + * @return + */ + public Map compile(String fileName, String source, Writer err, String sourcePath, String classPath) + { + // to collect errors, warnings etc. + DiagnosticCollector diagnostics = new DiagnosticCollector<>(); + + // create a new memory JavaFileManager + MemoryJavaFileManager manager = new MemoryJavaFileManager(); + + // prepare the compilation unit + List compUnits = new ArrayList<>(1); + compUnits.add(MemoryJavaFileManager.makeStringSource(fileName, source)); + + // javac options + List options = new ArrayList<>(); + options.add("-warn:-enumSwitch"); + options.add("-g"); + options.add("-deprecation"); + options.add("-1.8"); + if (sourcePath != null) + { + options.add("-sourcepath"); + options.add(sourcePath); + } + if (classPath != null) + { + options.add("-classpath"); + options.add(classPath); + } + + // create a compilation task + CompilationTask task = tool.getTask(err, manager, diagnostics, options, null, compUnits); + + if (!task.call()) + { + PrintWriter perr = new PrintWriter(err); + for (Diagnostic diagnostic : diagnostics.getDiagnostics()) + { + perr.println(diagnostic.getMessage(Locale.getDefault())); + } + perr.flush(); + return null; + } + + Map classBytes = manager.getClassBytes(); + manager.close(); + return classBytes; + } +} diff --git a/trunk/java/com/l2jserver/commons/javaengine/JavaScriptEngine.java b/trunk/java/com/l2jserver/commons/javaengine/JavaScriptEngine.java new file mode 100644 index 0000000000..88c663e7a3 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/javaengine/JavaScriptEngine.java @@ -0,0 +1,500 @@ +/* + * Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: Redistributions of source code + * must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. Neither the name of the Sun Microsystems nor the names of + * is contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.l2jserver.commons.javaengine; + +import java.io.IOException; +import java.io.Reader; +import java.io.Serializable; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.script.AbstractScriptEngine; +import javax.script.Bindings; +import javax.script.Compilable; +import javax.script.CompiledScript; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptException; +import javax.script.SimpleBindings; + +/** + * This is script engine for Java programming language. + * @author A. Sundararajan + */ +public class JavaScriptEngine extends AbstractScriptEngine implements Compilable +{ + // Java compiler + private final JavaCompiler compiler; + + public JavaScriptEngine() + { + compiler = new JavaCompiler(); + } + + // my factory, may be null + private ScriptEngineFactory factory; + + // my implementation for CompiledScript + private static class JavaCompiledScript extends CompiledScript implements Serializable + { + private static final long serialVersionUID = 1L; + private final transient JavaScriptEngine _engine; + private transient Class _class; + private final Map _classBytes; + private final String _classPath; + + JavaCompiledScript(JavaScriptEngine engine, Map classBytes, String classPath) + { + _engine = engine; + _classBytes = classBytes; + _classPath = classPath; + } + + @Override + public ScriptEngine getEngine() + { + return _engine; + } + + @Override + public Object eval(ScriptContext ctx) throws ScriptException + { + if (_class == null) + { + Map classBytesCopy = new HashMap<>(); + classBytesCopy.putAll(_classBytes); + MemoryClassLoader loader = new MemoryClassLoader(classBytesCopy, _classPath, JavaScriptEngine.getParentLoader(ctx)); + _class = JavaScriptEngine.parseMain(loader, ctx); + } + return JavaScriptEngine.evalClass(_class, ctx); + } + } + + @Override + public CompiledScript compile(String script) throws ScriptException + { + return compile(script, context); + } + + @Override + public CompiledScript compile(Reader reader) throws ScriptException + { + return compile(readFully(reader)); + } + + @Override + public Object eval(String str, ScriptContext ctx) throws ScriptException + { + Class clazz = parse(str, ctx); + return evalClass(clazz, ctx); + } + + @Override + public Object eval(Reader reader, ScriptContext ctx) throws ScriptException + { + return eval(readFully(reader), ctx); + } + + @Override + public ScriptEngineFactory getFactory() + { + synchronized (this) + { + if (factory == null) + { + factory = new JavaScriptEngineFactory(); + } + } + return factory; + } + + @Override + public Bindings createBindings() + { + return new SimpleBindings(); + } + + void setFactory(ScriptEngineFactory factory) + { + this.factory = factory; + } + + // Internals only below this point + + private Class parse(String str, ScriptContext ctx) throws ScriptException + { + String fileName = getFileName(ctx); + String sourcePath = getSourcePath(ctx); + String classPath = getClassPath(ctx); + + Writer err = ctx.getErrorWriter(); + if (err == null) + { + err = new StringWriter(); + } + + Map classBytes = compiler.compile(fileName, str, err, sourcePath, classPath); + + if (classBytes == null) + { + if (err instanceof StringWriter) + { + throw new ScriptException(((StringWriter) err).toString()); + } + throw new ScriptException("compilation failed"); + } + + // create a ClassLoader to load classes from MemoryJavaFileManager + MemoryClassLoader loader = new MemoryClassLoader(classBytes, classPath, getParentLoader(ctx)); + return parseMain(loader, ctx); + } + + protected static Class parseMain(MemoryClassLoader loader, ScriptContext ctx) throws ScriptException + { + String mainClassName = getMainClassName(ctx); + if (mainClassName != null) + { + try + { + Class clazz = loader.load(mainClassName); + Method mainMethod = findMainMethod(clazz); + if (mainMethod == null) + { + throw new ScriptException("no main method in " + mainClassName); + } + return clazz; + } + catch (ClassNotFoundException cnfe) + { + cnfe.printStackTrace(); + throw new ScriptException(cnfe); + } + } + + // no main class configured - load all compiled classes + Iterable> classes; + try + { + classes = loader.loadAll(); + } + catch (ClassNotFoundException exp) + { + throw new ScriptException(exp); + } + + // search for class with main method + Class c = findMainClass(classes); + if (c != null) + { + return c; + } + + // if class with "main" method, then + // return first class + Iterator> itr = classes.iterator(); + if (itr.hasNext()) + { + return itr.next(); + } + return null; + } + + private JavaCompiledScript compile(String str, ScriptContext ctx) throws ScriptException + { + String fileName = getFileName(ctx); + String sourcePath = getSourcePath(ctx); + String classPath = getClassPath(ctx); + + Writer err = ctx.getErrorWriter(); + if (err == null) + { + err = new StringWriter(); + } + + Map classBytes = compiler.compile(fileName, str, err, sourcePath, classPath); + if (classBytes == null) + { + if (err instanceof StringWriter) + { + throw new ScriptException(((StringWriter) err).toString()); + } + throw new ScriptException("compilation failed"); + } + + return new JavaCompiledScript(this, classBytes, classPath); + } + + private static Class findMainClass(Iterable> classes) + { + // find a public class with public static main method + for (Class clazz : classes) + { + int modifiers = clazz.getModifiers(); + if (Modifier.isPublic(modifiers)) + { + Method mainMethod = findMainMethod(clazz); + if (mainMethod != null) + { + return clazz; + } + } + } + + // okay, try to find package private class that + // has public static main method + for (Class clazz : classes) + { + Method mainMethod = findMainMethod(clazz); + if (mainMethod != null) + { + return clazz; + } + } + + // no main class found! + return null; + } + + // find public static void main(String[]) method, if any + private static Method findMainMethod(Class clazz) + { + try + { + Method mainMethod = clazz.getMethod("main", new Class[] + { + String[].class + }); + int modifiers = mainMethod.getModifiers(); + if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)) + { + return mainMethod; + } + } + catch (NoSuchMethodException nsme) + { + } + return null; + } + + // find public static void setScriptContext(ScriptContext) method, if any + private static Method findSetScriptContextMethod(Class clazz) + { + try + { + Method setCtxMethod = clazz.getMethod("setScriptContext", new Class[] + { + ScriptContext.class + }); + int modifiers = setCtxMethod.getModifiers(); + if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)) + { + return setCtxMethod; + } + } + catch (NoSuchMethodException nsme) + { + } + return null; + } + + private static String getFileName(ScriptContext ctx) + { + int scope = ctx.getAttributesScope("javax.script.filename"); + if (scope != -1) + { + return ctx.getAttribute("javax.script.filename", scope).toString(); + } + return "$unnamed.java"; + } + + // for certain variables, we look for System properties. This is + // the prefix used for such System properties + private static final String SYSPROP_PREFIX = "com.sun.script.java."; + + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + private static final String ARGUMENTS = "arguments"; + + private static String[] getArguments(ScriptContext ctx) + { + int scope = ctx.getAttributesScope(ARGUMENTS); + if (scope != -1) + { + Object obj = ctx.getAttribute(ARGUMENTS, scope); + if (obj instanceof String[]) + { + return (String[]) obj; + } + } + // return zero length array + return EMPTY_STRING_ARRAY; + } + + private static final String SOURCEPATH = "sourcepath"; + + private static String getSourcePath(ScriptContext ctx) + { + int scope = ctx.getAttributesScope(SOURCEPATH); + if (scope != -1) + { + return ctx.getAttribute(SOURCEPATH).toString(); + } + + // look for "com.sun.script.java.sourcepath" + return System.getProperty(SYSPROP_PREFIX + SOURCEPATH); + } + + private static final String CLASSPATH = "classpath"; + + private static String getClassPath(ScriptContext ctx) + { + int scope = ctx.getAttributesScope(CLASSPATH); + if (scope != -1) + { + return ctx.getAttribute(CLASSPATH).toString(); + } + + // look for "com.sun.script.java.classpath" + String res = System.getProperty(SYSPROP_PREFIX + CLASSPATH); + if (res == null) + { + res = System.getProperty("java.class.path"); + } + return res; + } + + private static final String MAINCLASS = "mainClass"; + + private static String getMainClassName(ScriptContext ctx) + { + int scope = ctx.getAttributesScope(MAINCLASS); + if (scope != -1) + { + return ctx.getAttribute(MAINCLASS).toString(); + } + + // look for "com.sun.script.java.mainClass" + return System.getProperty("com.sun.script.java.mainClass"); + } + + private static final String PARENTLOADER = "parentLoader"; + + protected static ClassLoader getParentLoader(ScriptContext ctx) + { + int scope = ctx.getAttributesScope(PARENTLOADER); + if (scope != -1) + { + Object loader = ctx.getAttribute(PARENTLOADER); + if (loader instanceof ClassLoader) + { + return (ClassLoader) loader; + } + } + return ClassLoader.getSystemClassLoader(); + } + + protected static Object evalClass(Class clazz, ScriptContext ctx) throws ScriptException + { + // JSR-223 requirement + ctx.setAttribute("context", ctx, 100); + if (clazz == null) + { + return null; + } + try + { + boolean isPublicClazz = Modifier.isPublic(clazz.getModifiers()); + + // find the setScriptContext method + Method setCtxMethod = findSetScriptContextMethod(clazz); + // call setScriptContext and pass current ctx variable + if (setCtxMethod != null) + { + if (!isPublicClazz) + { + // try to relax access + setCtxMethod.setAccessible(true); + } + setCtxMethod.invoke(null, new Object[] + { + ctx + }); + } + + // find the main method + Method mainMethod = findMainMethod(clazz); + if (mainMethod != null) + { + if (!isPublicClazz) + { + // try to relax access + mainMethod.setAccessible(true); + } + + // get "command line" args for the main method + String args[] = getArguments(ctx); + + // call main method + mainMethod.invoke(null, new Object[] + { + args + }); + } + + // return main class as eval's result + return clazz; + } + catch (Exception exp) + { + exp.printStackTrace(); + throw new ScriptException(exp); + } + } + + // read a Reader fully and return the content as string + private String readFully(Reader reader) throws ScriptException + { + char[] arr = new char[8 * 1024]; // 8K at a time + StringBuilder buf = new StringBuilder(); + int numChars; + try + { + while ((numChars = reader.read(arr, 0, arr.length)) > 0) + { + buf.append(arr, 0, numChars); + } + } + catch (IOException exp) + { + throw new ScriptException(exp); + } + return buf.toString(); + } + +} diff --git a/trunk/java/com/l2jserver/commons/javaengine/JavaScriptEngineFactory.java b/trunk/java/com/l2jserver/commons/javaengine/JavaScriptEngineFactory.java new file mode 100644 index 0000000000..9a63462f8c --- /dev/null +++ b/trunk/java/com/l2jserver/commons/javaengine/JavaScriptEngineFactory.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: Redistributions of source code + * must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. Neither the name of the Sun Microsystems nor the names of + * is contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.l2jserver.commons.javaengine; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +/** + * This is script engine factory for "Java" script engine. + * @author A. Sundararajan + */ +public class JavaScriptEngineFactory implements ScriptEngineFactory +{ + @Override + public String getEngineName() + { + return "java"; + } + + @Override + public String getEngineVersion() + { + return "1.8"; + } + + @Override + public List getExtensions() + { + return extensions; + } + + @Override + public String getLanguageName() + { + return "java"; + } + + @Override + public String getLanguageVersion() + { + return "1.8"; + } + + @Override + public String getMethodCallSyntax(String obj, String m, String... args) + { + StringBuilder buf = new StringBuilder(); + buf.append(obj); + buf.append('.'); + buf.append(m); + buf.append('('); + if (args.length != 0) + { + int i = 0; + for (; i < (args.length - 1); i++) + { + buf.append(args[i] + ", "); + } + buf.append(args[i]); + } + buf.append(')'); + return buf.toString(); + } + + @Override + public List getMimeTypes() + { + return mimeTypes; + } + + @Override + public List getNames() + { + return names; + } + + @Override + public String getOutputStatement(String toDisplay) + { + StringBuilder buf = new StringBuilder(); + buf.append("System.out.print(\""); + int len = toDisplay.length(); + for (int i = 0; i < len; i++) + { + char ch = toDisplay.charAt(i); + switch (ch) + { + case 34: // '"' + buf.append("\\\""); + break; + case 92: // '\\' + buf.append("\\\\"); + break; + default: + buf.append(ch); + break; + } + } + buf.append("\");"); + return buf.toString(); + } + + @Override + public String getParameter(String key) + { + if (key.equals("javax.script.engine")) + { + return getEngineName(); + } + if (key.equals("javax.script.engine_version")) + { + return getEngineVersion(); + } + if (key.equals("javax.script.name")) + { + return getEngineName(); + } + if (key.equals("javax.script.language")) + { + return getLanguageName(); + } + if (key.equals("javax.script.language_version")) + { + return getLanguageVersion(); + } + if (key.equals("THREADING")) + { + return "MULTITHREADED"; + } + return null; + } + + @Override + public String getProgram(String... statements) + { + // we generate a Main class with main method + // that contains all the given statements + + StringBuilder buf = new StringBuilder(); + buf.append("class "); + buf.append(getClassName()); + buf.append(" {\n"); + buf.append(" public static void main(String[] args) {\n"); + if (statements.length != 0) + { + for (String statement : statements) + { + buf.append(" "); + buf.append(statement); + buf.append(";\n"); + } + } + buf.append(" }\n"); + buf.append("}\n"); + return buf.toString(); + } + + @Override + public ScriptEngine getScriptEngine() + { + JavaScriptEngine engine = new JavaScriptEngine(); + engine.setFactory(this); + return engine; + } + + // used to generate a unique class name in getProgram + private String getClassName() + { + return "com_sun_script_java_Main$" + getNextClassNumber(); + } + + private static synchronized long getNextClassNumber() + { + return nextClassNum++; + } + + private static long nextClassNum = 0L; + private static List names; + private static List extensions; + private static List mimeTypes; + + static + { + names = new ArrayList<>(1); + names.add("java"); + names = Collections.unmodifiableList(names); + extensions = names; + mimeTypes = new ArrayList<>(0); + mimeTypes = Collections.unmodifiableList(mimeTypes); + } +} diff --git a/trunk/java/com/l2jserver/commons/javaengine/MemoryClassLoader.java b/trunk/java/com/l2jserver/commons/javaengine/MemoryClassLoader.java new file mode 100644 index 0000000000..ead675be30 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/javaengine/MemoryClassLoader.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: Redistributions of source code + * must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. Neither the name of the Sun Microsystems nor the names of + * is contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.l2jserver.commons.javaengine; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * ClassLoader that loads .class bytes from memory. + * @author A. Sundararajan + */ +public final class MemoryClassLoader extends URLClassLoader +{ + private final Map classBytes; + + public MemoryClassLoader(Map classBytes, String classPath, ClassLoader parent) + { + super(toURLs(classPath), parent); + this.classBytes = classBytes; + } + + public MemoryClassLoader(Map classBytes, String classPath) + { + this(classBytes, classPath, null); + } + + public Class load(String className) throws ClassNotFoundException + { + return loadClass(className); + } + + public Iterable> loadAll() throws ClassNotFoundException + { + List> classes = new ArrayList<>(classBytes.size()); + for (String name : classBytes.keySet()) + { + classes.add(loadClass(name)); + } + return classes; + } + + @Override + protected Class findClass(String className) throws ClassNotFoundException + { + byte buf[] = classBytes.get(className); + if (buf != null) + { + // clear the bytes in map -- we don't need it anymore + classBytes.put(className, null); + return defineClass(className, buf, 0, buf.length); + } + return super.findClass(className); + } + + private static URL[] toURLs(String classPath) + { + if (classPath == null) + { + return new URL[0]; + } + + List list = new ArrayList<>(); + StringTokenizer st = new StringTokenizer(classPath, File.pathSeparator); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + File file = new File(token); + if (file.exists()) + { + try + { + list.add(file.toURI().toURL()); + } + catch (MalformedURLException mue) + { + // + } + } + else + { + try + { + list.add(new URL(token)); + } + catch (MalformedURLException mue) + { + // + } + } + } + + URL res[] = new URL[list.size()]; + list.toArray(res); + return res; + } +} diff --git a/trunk/java/com/l2jserver/commons/javaengine/MemoryJavaFileManager.java b/trunk/java/com/l2jserver/commons/javaengine/MemoryJavaFileManager.java new file mode 100644 index 0000000000..926d4a9fc8 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/javaengine/MemoryJavaFileManager.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: Redistributions of source code + * must retain the above copyright notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. Neither the name of the Sun Microsystems nor the names of + * is contributors may be used to endorse or promote products derived from this software + * without specific prior written permission. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.l2jserver.commons.javaengine; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.nio.CharBuffer; +import java.util.HashMap; +import java.util.Map; + +import javax.tools.FileObject; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.SimpleJavaFileObject; + +import org.eclipse.jdt.internal.compiler.tool.EclipseFileManager; + +/** + * JavaFileManager that keeps compiled .class bytes in memory. + * @author A. Sundararajan + */ +public final class MemoryJavaFileManager extends EclipseFileManager +{ + private static final String EXT = ".java"; + protected Map classBytes; + + public MemoryJavaFileManager() + { + super(null, null); + classBytes = new HashMap<>(); + } + + public Map getClassBytes() + { + return classBytes; + } + + @Override + public void close() + { + classBytes = new HashMap<>(); + } + + @Override + public void flush() + { + } + + /** + * A file object used to represent Java source coming from a string. + */ + private static class StringInputBuffer extends SimpleJavaFileObject + { + final String code; + + StringInputBuffer(String name, String code) + { + super(toURI(name), Kind.SOURCE); + this.code = code; + } + + @Override + public CharBuffer getCharContent(boolean ignoreEncodingErrors) + { + return CharBuffer.wrap(code); + } + } + + /** + * A file object that stores Java bytecode into the classBytes map. + */ + private class ClassOutputBuffer extends SimpleJavaFileObject + { + protected final String name; + + ClassOutputBuffer(String name) + { + super(toURI(name), Kind.CLASS); + this.name = name; + } + + @Override + public OutputStream openOutputStream() + { + return new FilterOutputStream(new ByteArrayOutputStream()) + { + @Override + public void close() throws IOException + { + out.close(); + ByteArrayOutputStream bos = (ByteArrayOutputStream) out; + classBytes.put(name, bos.toByteArray()); + } + }; + } + } + + @Override + public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location, String className, Kind kind, FileObject sibling) throws IOException + { + if (kind == Kind.CLASS) + { + return new ClassOutputBuffer(className.replace('/', '.')); + } + return super.getJavaFileForOutput(location, className, kind, sibling); + } + + static JavaFileObject makeStringSource(String name, String code) + { + return new StringInputBuffer(name, code); + } + + static URI toURI(String name) + { + File file = new File(name); + if (file.exists()) + { + return file.toURI(); + } + + try + { + final StringBuilder newUri = new StringBuilder(); + newUri.append("file:///"); + newUri.append(name.replace('.', '/')); + if (name.endsWith(EXT)) + { + newUri.replace(newUri.length() - EXT.length(), newUri.length(), EXT); + } + return URI.create(newUri.toString()); + } + catch (Exception exp) + { + return URI.create("file:///com/sun/script/java/java_source"); + } + } +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/AbstractPacket.java b/trunk/java/com/l2jserver/commons/mmocore/AbstractPacket.java new file mode 100644 index 0000000000..1950407028 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/AbstractPacket.java @@ -0,0 +1,36 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +import java.nio.ByteBuffer; + +/** + * @author KenM + * @param + */ +public abstract class AbstractPacket> +{ + protected ByteBuffer _buf; + + protected T _client; + + public final T getClient() + { + return _client; + } +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/IAcceptFilter.java b/trunk/java/com/l2jserver/commons/mmocore/IAcceptFilter.java new file mode 100644 index 0000000000..b9db8224c9 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/IAcceptFilter.java @@ -0,0 +1,28 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +import java.nio.channels.SocketChannel; + +/** + * @author KenM + */ +public interface IAcceptFilter +{ + public boolean accept(SocketChannel sc); +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/IClientFactory.java b/trunk/java/com/l2jserver/commons/mmocore/IClientFactory.java new file mode 100644 index 0000000000..f7985580e7 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/IClientFactory.java @@ -0,0 +1,27 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +/** + * @author KenM + * @param + */ +public interface IClientFactory> +{ + public T create(final MMOConnection con); +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/IMMOExecutor.java b/trunk/java/com/l2jserver/commons/mmocore/IMMOExecutor.java new file mode 100644 index 0000000000..19407aadea --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/IMMOExecutor.java @@ -0,0 +1,27 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +/** + * @author KenM + * @param + */ +public interface IMMOExecutor> +{ + public void execute(ReceivablePacket packet); +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/IPacketHandler.java b/trunk/java/com/l2jserver/commons/mmocore/IPacketHandler.java new file mode 100644 index 0000000000..fd50cf9ef3 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/IPacketHandler.java @@ -0,0 +1,29 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +import java.nio.ByteBuffer; + +/** + * @author KenM + * @param + */ +public interface IPacketHandler> +{ + public ReceivablePacket handlePacket(ByteBuffer buf, T client); +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/MMOClient.java b/trunk/java/com/l2jserver/commons/mmocore/MMOClient.java new file mode 100644 index 0000000000..9ddff48df1 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/MMOClient.java @@ -0,0 +1,47 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +import java.nio.ByteBuffer; + +/** + * @author KenM + * @param + */ +public abstract class MMOClient> +{ + private final T _con; + + public MMOClient(final T con) + { + _con = con; + } + + public T getConnection() + { + return _con; + } + + public abstract boolean decrypt(final ByteBuffer buf, final int size); + + public abstract boolean encrypt(final ByteBuffer buf, final int size); + + protected abstract void onDisconnection(); + + protected abstract void onForcedDisconnection(); +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/MMOConnection.java b/trunk/java/com/l2jserver/commons/mmocore/MMOConnection.java new file mode 100644 index 0000000000..e40692b61d --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/MMOConnection.java @@ -0,0 +1,288 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.channels.CancelledKeyException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.WritableByteChannel; + +/** + * @author KenM + * @param + */ +public class MMOConnection> +{ + private final SelectorThread _selectorThread; + + private final Socket _socket; + + private final InetAddress _address; + + private final ReadableByteChannel _readableByteChannel; + + private final WritableByteChannel _writableByteChannel; + + private final int _port; + + private final NioNetStackList> _sendQueue; + + private final SelectionKey _selectionKey; + + // private SendablePacket _closePacket; + + private ByteBuffer _readBuffer; + + private ByteBuffer _primaryWriteBuffer; + + private ByteBuffer _secondaryWriteBuffer; + + private volatile boolean _pendingClose; + + private T _client; + + public MMOConnection(final SelectorThread selectorThread, final Socket socket, final SelectionKey key, boolean tcpNoDelay) + { + _selectorThread = selectorThread; + _socket = socket; + _address = socket.getInetAddress(); + _readableByteChannel = socket.getChannel(); + _writableByteChannel = socket.getChannel(); + _port = socket.getPort(); + _selectionKey = key; + + _sendQueue = new NioNetStackList<>(); + + try + { + _socket.setTcpNoDelay(tcpNoDelay); + } + catch (SocketException e) + { + e.printStackTrace(); + } + } + + final void setClient(final T client) + { + _client = client; + } + + public final T getClient() + { + return _client; + } + + public final void sendPacket(final SendablePacket sp) + { + sp._client = _client; + + if (_pendingClose) + { + return; + } + + synchronized (getSendQueue()) + { + _sendQueue.addLast(sp); + } + + if (!_sendQueue.isEmpty()) + { + try + { + _selectionKey.interestOps(_selectionKey.interestOps() | SelectionKey.OP_WRITE); + } + catch (CancelledKeyException e) + { + // ignore + } + } + } + + final SelectionKey getSelectionKey() + { + return _selectionKey; + } + + public final InetAddress getInetAddress() + { + return _address; + } + + public final int getPort() + { + return _port; + } + + final void close() throws IOException + { + _socket.close(); + } + + final int read(final ByteBuffer buf) throws IOException + { + return _readableByteChannel.read(buf); + } + + final int write(final ByteBuffer buf) throws IOException + { + return _writableByteChannel.write(buf); + } + + final void createWriteBuffer(final ByteBuffer buf) + { + if (_primaryWriteBuffer == null) + { + _primaryWriteBuffer = _selectorThread.getPooledBuffer(); + _primaryWriteBuffer.put(buf); + } + else + { + final ByteBuffer temp = _selectorThread.getPooledBuffer(); + temp.put(buf); + + final int remaining = temp.remaining(); + _primaryWriteBuffer.flip(); + final int limit = _primaryWriteBuffer.limit(); + + if (remaining >= _primaryWriteBuffer.remaining()) + { + temp.put(_primaryWriteBuffer); + _selectorThread.recycleBuffer(_primaryWriteBuffer); + _primaryWriteBuffer = temp; + } + else + { + _primaryWriteBuffer.limit(remaining); + temp.put(_primaryWriteBuffer); + _primaryWriteBuffer.limit(limit); + _primaryWriteBuffer.compact(); + _secondaryWriteBuffer = _primaryWriteBuffer; + _primaryWriteBuffer = temp; + } + } + } + + final boolean hasPendingWriteBuffer() + { + return _primaryWriteBuffer != null; + } + + final void movePendingWriteBufferTo(final ByteBuffer dest) + { + _primaryWriteBuffer.flip(); + dest.put(_primaryWriteBuffer); + _selectorThread.recycleBuffer(_primaryWriteBuffer); + _primaryWriteBuffer = _secondaryWriteBuffer; + _secondaryWriteBuffer = null; + } + + final void setReadBuffer(final ByteBuffer buf) + { + _readBuffer = buf; + } + + final ByteBuffer getReadBuffer() + { + return _readBuffer; + } + + public final boolean isClosed() + { + return _pendingClose; + } + + final NioNetStackList> getSendQueue() + { + return _sendQueue; + } + + /* + * final SendablePacket getClosePacket() { return _closePacket; } + */ + + @SuppressWarnings("unchecked") + public final void close(final SendablePacket sp) + { + + close(new SendablePacket[] + { + sp + }); + } + + public final void close(final SendablePacket[] closeList) + { + if (_pendingClose) + { + return; + } + + synchronized (getSendQueue()) + { + if (!_pendingClose) + { + _pendingClose = true; + _sendQueue.clear(); + for (SendablePacket sp : closeList) + { + _sendQueue.addLast(sp); + } + } + } + + try + { + _selectionKey.interestOps(_selectionKey.interestOps() & ~SelectionKey.OP_WRITE); + } + catch (CancelledKeyException e) + { + // ignore + } + + // _closePacket = sp; + _selectorThread.closeConnection(this); + } + + final void releaseBuffers() + { + if (_primaryWriteBuffer != null) + { + _selectorThread.recycleBuffer(_primaryWriteBuffer); + _primaryWriteBuffer = null; + + if (_secondaryWriteBuffer != null) + { + _selectorThread.recycleBuffer(_secondaryWriteBuffer); + _secondaryWriteBuffer = null; + } + } + + if (_readBuffer != null) + { + _selectorThread.recycleBuffer(_readBuffer); + _readBuffer = null; + } + } +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/NioNetStackList.java b/trunk/java/com/l2jserver/commons/mmocore/NioNetStackList.java new file mode 100644 index 0000000000..e521ae67e6 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/NioNetStackList.java @@ -0,0 +1,102 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +/** + * @author Forsaiken + * @param + */ +public final class NioNetStackList +{ + private final NioNetStackNode _start = new NioNetStackNode(); + + private final NioNetStackNodeBuf _buf = new NioNetStackNodeBuf(); + + private NioNetStackNode _end = new NioNetStackNode(); + + public NioNetStackList() + { + clear(); + } + + public final void addLast(final E elem) + { + final NioNetStackNode newEndNode = _buf.removeFirst(); + _end._value = elem; + _end._next = newEndNode; + _end = newEndNode; + } + + public final E removeFirst() + { + final NioNetStackNode old = _start._next; + final E value = old._value; + _start._next = old._next; + _buf.addLast(old); + return value; + } + + public final boolean isEmpty() + { + return _start._next == _end; + } + + public final void clear() + { + _start._next = _end; + } + + protected final class NioNetStackNode + { + protected NioNetStackNode _next; + + protected E _value; + } + + private final class NioNetStackNodeBuf + { + private final NioNetStackNode _start = new NioNetStackNode(); + + private NioNetStackNode _end = new NioNetStackNode(); + + NioNetStackNodeBuf() + { + _start._next = _end; + } + + final void addLast(final NioNetStackNode node) + { + node._next = null; + node._value = null; + _end._next = node; + _end = node; + } + + final NioNetStackNode removeFirst() + { + if (_start._next == _end) + { + return new NioNetStackNode(); + } + + final NioNetStackNode old = _start._next; + _start._next = old._next; + return old; + } + } +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/NioNetStringBuffer.java b/trunk/java/com/l2jserver/commons/mmocore/NioNetStringBuffer.java new file mode 100644 index 0000000000..ce5cecbf3f --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/NioNetStringBuffer.java @@ -0,0 +1,62 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +import java.nio.BufferOverflowException; + +/** + * @author Forsaiken + */ +public final class NioNetStringBuffer +{ + private final char[] _buf; + + private final int _size; + + private int _len; + + public NioNetStringBuffer(final int size) + { + _buf = new char[size]; + _size = size; + _len = 0; + } + + public final void clear() + { + _len = 0; + } + + public final void append(final char c) + { + if (_len < _size) + { + _buf[_len++] = c; + } + else + { + throw new BufferOverflowException(); + } + } + + @Override + public final String toString() + { + return new String(_buf, 0, _len); + } +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/ReceivablePacket.java b/trunk/java/com/l2jserver/commons/mmocore/ReceivablePacket.java new file mode 100644 index 0000000000..c9c843db37 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/ReceivablePacket.java @@ -0,0 +1,141 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +import java.nio.ByteBuffer; + +/** + * @author KenM + * @param + */ +public abstract class ReceivablePacket> extends AbstractPacket implements Runnable +{ + NioNetStringBuffer _sbuf; + + protected ReceivablePacket() + { + + } + + protected abstract boolean read(); + + @Override + public abstract void run(); + + /** + * Reads byte[] from the buffer.
+ * Reads as many bytes as the length of the array. + * @param dst : the byte array which will be filled with the data. + */ + protected final void readB(final byte[] dst) + { + _buf.get(dst); + } + + /** + * Reads byte[] from the buffer.
+ * Reads as many bytes as the given length (len). Starts to fill the byte array from the given offset to offset + len. + * @param dst : the byte array which will be filled with the data. + * @param offset : starts to fill the byte array from the given offset. + * @param len : the given length of bytes to be read. + */ + protected final void readB(final byte[] dst, final int offset, final int len) + { + _buf.get(dst, offset, len); + } + + /** + * Reads byte from the buffer.
+ * 8bit integer (00) + * @return + */ + protected final int readC() + { + return _buf.get() & 0xFF; + } + + /** + * Reads short from the buffer.
+ * 16bit integer (00 00) + * @return + */ + protected final int readH() + { + return _buf.getShort() & 0xFFFF; + } + + /** + * Reads int from the buffer.
+ * 32bit integer (00 00 00 00) + * @return + */ + protected final int readD() + { + return _buf.getInt(); + } + + /** + * Reads long from the buffer.
+ * 64bit integer (00 00 00 00 00 00 00 00) + * @return + */ + protected final long readQ() + { + return _buf.getLong(); + } + + /** + * Reads double from the buffer.
+ * 64bit double precision float (00 00 00 00 00 00 00 00) + * @return + */ + protected final double readF() + { + return _buf.getDouble(); + } + + /** + * Reads String from the buffer. + * @return + */ + protected final String readS() + { + _sbuf.clear(); + + char ch; + while ((ch = _buf.getChar()) != 0) + { + _sbuf.append(ch); + } + + return _sbuf.toString(); + } + + /** + * packet forge purpose + * @param data + * @param client + * @param sBuffer + */ + public void setBuffers(ByteBuffer data, T client, NioNetStringBuffer sBuffer) + { + _buf = data; + _client = client; + _sbuf = sBuffer; + } +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/SelectorConfig.java b/trunk/java/com/l2jserver/commons/mmocore/SelectorConfig.java new file mode 100644 index 0000000000..ce4acd5d25 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/SelectorConfig.java @@ -0,0 +1,64 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +/** + * @author KenM + */ +public final class SelectorConfig +{ + public int READ_BUFFER_SIZE = 64 * 1024; + + public int WRITE_BUFFER_SIZE = 64 * 1024; + + public int HELPER_BUFFER_COUNT = 20; + + public int HELPER_BUFFER_SIZE = 64 * 1024; + + /** + * Server will try to send MAX_SEND_PER_PASS packets per socket write call
+ * however it may send less if the write buffer was filled before achieving this value. + */ + public int MAX_SEND_PER_PASS = 10; + + /** + * Server will try to read MAX_READ_PER_PASS packets per socket read call
+ * however it may read less if the read buffer was empty before achieving this value. + */ + public int MAX_READ_PER_PASS = 10; + + /** + * Defines how much time (in milis) should the selector sleep, an higher value increases throughput but also increases latency(to a max of the sleep value itself).
+ * Also an extremely high value(usually > 100) will decrease throughput due to the server not doing enough sends per second (depends on max sends per pass).
+ *
+ * Recommended values:
+ * 1 for minimal latency.
+ * 10-30 for an latency/troughput trade-off based on your needs.
+ */ + public int SLEEP_TIME = 10; + + /** + * Used to enable/disable TCP_NODELAY which disable/enable Nagle's algorithm.
+ *
+ * Nagle's algorithm try to conserve bandwidth by minimizing the number of segments that are sent. When applications wish to decrease network latency and increase performance, they can disable Nagle's algorithm (that is enable TCP_NODELAY). Data will be sent earlier, at the cost of an increase + * in bandwidth consumption. The Nagle's algorithm is described in RFC 896.
+ *
+ * Summary, data will be sent earlier, thus lowering the ping, at the cost of a small increase in bandwidth consumption. + */ + public boolean TCP_NODELAY = false; +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/SelectorThread.java b/trunk/java/com/l2jserver/commons/mmocore/SelectorThread.java new file mode 100644 index 0000000000..f915484cd8 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/SelectorThread.java @@ -0,0 +1,703 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.util.Iterator; +import java.util.LinkedList; + +/** + * @author KenM
+ * Parts of design based on networkcore from WoodenGil + * @param + */ +public final class SelectorThread> extends Thread +{ + // default BYTE_ORDER + private static final ByteOrder BYTE_ORDER = ByteOrder.LITTLE_ENDIAN; + // default HEADER_SIZE + private static final int HEADER_SIZE = 2; + // Selector + private final Selector _selector; + // Implementations + private final IPacketHandler _packetHandler; + private final IMMOExecutor _executor; + private final IClientFactory _clientFactory; + private final IAcceptFilter _acceptFilter; + // Configurations + private final int HELPER_BUFFER_SIZE; + private final int HELPER_BUFFER_COUNT; + private final int MAX_SEND_PER_PASS; + private final int MAX_READ_PER_PASS; + private final long SLEEP_TIME; + public boolean TCP_NODELAY; + // Main Buffers + private final ByteBuffer DIRECT_WRITE_BUFFER; + private final ByteBuffer WRITE_BUFFER; + private final ByteBuffer READ_BUFFER; + // String Buffer + private final NioNetStringBuffer STRING_BUFFER; + // ByteBuffers General Purpose Pool + private final LinkedList _bufferPool; + // Pending Close + private final NioNetStackList> _pendingClose; + + private boolean _shutdown; + + public SelectorThread(final SelectorConfig sc, final IMMOExecutor executor, final IPacketHandler packetHandler, final IClientFactory clientFactory, final IAcceptFilter acceptFilter) throws IOException + { + super.setName("SelectorThread-" + super.getId()); + + HELPER_BUFFER_SIZE = sc.HELPER_BUFFER_SIZE; + HELPER_BUFFER_COUNT = sc.HELPER_BUFFER_COUNT; + MAX_SEND_PER_PASS = sc.MAX_SEND_PER_PASS; + MAX_READ_PER_PASS = sc.MAX_READ_PER_PASS; + SLEEP_TIME = sc.SLEEP_TIME; + TCP_NODELAY = sc.TCP_NODELAY; + + DIRECT_WRITE_BUFFER = ByteBuffer.allocateDirect(sc.WRITE_BUFFER_SIZE).order(BYTE_ORDER); + WRITE_BUFFER = ByteBuffer.wrap(new byte[sc.WRITE_BUFFER_SIZE]).order(BYTE_ORDER); + READ_BUFFER = ByteBuffer.wrap(new byte[sc.READ_BUFFER_SIZE]).order(BYTE_ORDER); + + STRING_BUFFER = new NioNetStringBuffer(64 * 1024); + + _pendingClose = new NioNetStackList<>(); + _bufferPool = new LinkedList<>(); + + for (int i = 0; i < HELPER_BUFFER_COUNT; i++) + { + _bufferPool.addLast(ByteBuffer.wrap(new byte[HELPER_BUFFER_SIZE]).order(BYTE_ORDER)); + } + + _acceptFilter = acceptFilter; + _packetHandler = packetHandler; + _clientFactory = clientFactory; + _executor = executor; + _selector = Selector.open(); + } + + public final void openServerSocket(InetAddress address, int tcpPort) throws IOException + { + ServerSocketChannel selectable = ServerSocketChannel.open(); + selectable.configureBlocking(false); + + ServerSocket ss = selectable.socket(); + + if (address == null) + { + ss.bind(new InetSocketAddress(tcpPort)); + } + else + { + ss.bind(new InetSocketAddress(address, tcpPort)); + } + + selectable.register(_selector, SelectionKey.OP_ACCEPT); + } + + final ByteBuffer getPooledBuffer() + { + if (_bufferPool.isEmpty()) + { + return ByteBuffer.wrap(new byte[HELPER_BUFFER_SIZE]).order(BYTE_ORDER); + } + + return _bufferPool.removeFirst(); + } + + final void recycleBuffer(final ByteBuffer buf) + { + if (_bufferPool.size() < HELPER_BUFFER_COUNT) + { + buf.clear(); + _bufferPool.addLast(buf); + } + } + + @SuppressWarnings("unchecked") + @Override + public final void run() + { + int selectedKeysCount = 0; + + SelectionKey key; + MMOConnection con; + + Iterator selectedKeys; + + while (!_shutdown) + { + try + { + selectedKeysCount = _selector.selectNow(); + } + catch (IOException e) + { + e.printStackTrace(); + } + + if (selectedKeysCount > 0) + { + selectedKeys = _selector.selectedKeys().iterator(); + + while (selectedKeys.hasNext()) + { + key = selectedKeys.next(); + selectedKeys.remove(); + + con = (MMOConnection) key.attachment(); + + switch (key.readyOps()) + { + case SelectionKey.OP_CONNECT: + finishConnection(key, con); + break; + case SelectionKey.OP_ACCEPT: + acceptConnection(key, con); + break; + case SelectionKey.OP_READ: + readPacket(key, con); + break; + case SelectionKey.OP_WRITE: + writePacket(key, con); + break; + case SelectionKey.OP_READ | SelectionKey.OP_WRITE: + writePacket(key, con); + if (key.isValid()) + { + readPacket(key, con); + } + break; + } + } + } + + synchronized (_pendingClose) + { + while (!_pendingClose.isEmpty()) + { + try + { + con = _pendingClose.removeFirst(); + writeClosePacket(con); + closeConnectionImpl(con.getSelectionKey(), con); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + } + + try + { + Thread.sleep(SLEEP_TIME); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + } + closeSelectorThread(); + } + + private final void finishConnection(final SelectionKey key, final MMOConnection con) + { + try + { + ((SocketChannel) key.channel()).finishConnect(); + } + catch (IOException e) + { + con.getClient().onForcedDisconnection(); + closeConnectionImpl(key, con); + } + + // key might have been invalidated on finishConnect() + if (key.isValid()) + { + key.interestOps(key.interestOps() | SelectionKey.OP_READ); + key.interestOps(key.interestOps() & ~SelectionKey.OP_CONNECT); + } + } + + private final void acceptConnection(final SelectionKey key, MMOConnection con) + { + ServerSocketChannel ssc = (ServerSocketChannel) key.channel(); + SocketChannel sc; + + try + { + while ((sc = ssc.accept()) != null) + { + if ((_acceptFilter == null) || _acceptFilter.accept(sc)) + { + sc.configureBlocking(false); + SelectionKey clientKey = sc.register(_selector, SelectionKey.OP_READ); + con = new MMOConnection<>(this, sc.socket(), clientKey, TCP_NODELAY); + con.setClient(_clientFactory.create(con)); + clientKey.attach(con); + } + else + { + sc.socket().close(); + } + } + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + private final void readPacket(final SelectionKey key, final MMOConnection con) + { + if (!con.isClosed()) + { + ByteBuffer buf; + if ((buf = con.getReadBuffer()) == null) + { + buf = READ_BUFFER; + } + + // if we try to to do a read with no space in the buffer it will + // read 0 bytes + // going into infinite loop + if (buf.position() == buf.limit()) + { + System.exit(0); + } + + int result = -2; + + try + { + result = con.read(buf); + } + catch (IOException e) + { + // error handling goes bellow + } + + if (result > 0) + { + buf.flip(); + + final T client = con.getClient(); + + for (int i = 0; i < MAX_READ_PER_PASS; i++) + { + if (!tryReadPacket(key, client, buf, con)) + { + return; + } + } + + // only reachable if MAX_READ_PER_PASS has been reached + // check if there are some more bytes in buffer + // and allocate/compact to prevent content lose. + if (buf.remaining() > 0) + { + // did we use the READ_BUFFER ? + if (buf == READ_BUFFER) + { + // move the pending byte to the connections READ_BUFFER + allocateReadBuffer(con); + } + else + { + // move the first byte to the beginning :) + buf.compact(); + } + } + } + else + { + switch (result) + { + case 0: + case -1: + closeConnectionImpl(key, con); + break; + case -2: + con.getClient().onForcedDisconnection(); + closeConnectionImpl(key, con); + break; + } + } + } + } + + private final boolean tryReadPacket(final SelectionKey key, final T client, final ByteBuffer buf, final MMOConnection con) + { + switch (buf.remaining()) + { + case 0: + // buffer is full + // nothing to read + return false; + case 1: + // we don`t have enough data for header so we need to read + key.interestOps(key.interestOps() | SelectionKey.OP_READ); + + // did we use the READ_BUFFER ? + if (buf == READ_BUFFER) + { + // move the pending byte to the connections READ_BUFFER + allocateReadBuffer(con); + } + else + { + // move the first byte to the beginning :) + buf.compact(); + } + return false; + default: + // data size excluding header size :> + final int dataPending = (buf.getShort() & 0xFFFF) - HEADER_SIZE; + + // do we got enough bytes for the packet? + if (dataPending <= buf.remaining()) + { + // avoid parsing dummy packets (packets without body) + if (dataPending > 0) + { + final int pos = buf.position(); + parseClientPacket(pos, buf, dataPending, client); + buf.position(pos + dataPending); + } + + // if we are done with this buffer + if (!buf.hasRemaining()) + { + if (buf != READ_BUFFER) + { + con.setReadBuffer(null); + recycleBuffer(buf); + } + else + { + READ_BUFFER.clear(); + } + return false; + } + return true; + } + + // we don`t have enough bytes for the dataPacket so we need + // to read + key.interestOps(key.interestOps() | SelectionKey.OP_READ); + + // did we use the READ_BUFFER ? + if (buf == READ_BUFFER) + { + // move it`s position + buf.position(buf.position() - HEADER_SIZE); + // move the pending byte to the connections READ_BUFFER + allocateReadBuffer(con); + } + else + { + buf.position(buf.position() - HEADER_SIZE); + buf.compact(); + } + return false; + } + } + + private final void allocateReadBuffer(final MMOConnection con) + { + con.setReadBuffer(getPooledBuffer().put(READ_BUFFER)); + READ_BUFFER.clear(); + } + + private final void parseClientPacket(final int pos, final ByteBuffer buf, final int dataSize, final T client) + { + final boolean ret = client.decrypt(buf, dataSize); + + if (ret && buf.hasRemaining()) + { + // apply limit + final int limit = buf.limit(); + buf.limit(pos + dataSize); + final ReceivablePacket cp = _packetHandler.handlePacket(buf, client); + + if (cp != null) + { + cp._buf = buf; + cp._sbuf = STRING_BUFFER; + cp._client = client; + + if (cp.read()) + { + _executor.execute(cp); + } + + cp._buf = null; + cp._sbuf = null; + } + buf.limit(limit); + } + } + + private final void writeClosePacket(final MMOConnection con) + { + SendablePacket sp; + synchronized (con.getSendQueue()) + { + if (con.getSendQueue().isEmpty()) + { + return; + } + + while ((sp = con.getSendQueue().removeFirst()) != null) + { + WRITE_BUFFER.clear(); + + putPacketIntoWriteBuffer(con.getClient(), sp); + + WRITE_BUFFER.flip(); + + try + { + con.write(WRITE_BUFFER); + } + catch (IOException e) + { + // error handling goes on the if bellow + } + } + } + } + + protected final void writePacket(final SelectionKey key, final MMOConnection con) + { + if (!prepareWriteBuffer(con)) + { + key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); + return; + } + + DIRECT_WRITE_BUFFER.flip(); + + final int size = DIRECT_WRITE_BUFFER.remaining(); + + int result = -1; + + try + { + result = con.write(DIRECT_WRITE_BUFFER); + } + catch (IOException e) + { + // error handling goes on the if bellow + } + + // check if no error happened + if (result >= 0) + { + // check if we written everything + if (result == size) + { + // complete write + synchronized (con.getSendQueue()) + { + if (con.getSendQueue().isEmpty() && !con.hasPendingWriteBuffer()) + { + key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); + } + } + } + else + { + // incomplete write + con.createWriteBuffer(DIRECT_WRITE_BUFFER); + } + } + else + { + con.getClient().onForcedDisconnection(); + closeConnectionImpl(key, con); + } + } + + private final boolean prepareWriteBuffer(final MMOConnection con) + { + boolean hasPending = false; + DIRECT_WRITE_BUFFER.clear(); + + // if there is pending content add it + if (con.hasPendingWriteBuffer()) + { + con.movePendingWriteBufferTo(DIRECT_WRITE_BUFFER); + hasPending = true; + } + + if ((DIRECT_WRITE_BUFFER.remaining() > 1) && !con.hasPendingWriteBuffer()) + { + final NioNetStackList> sendQueue = con.getSendQueue(); + final T client = con.getClient(); + SendablePacket sp; + + for (int i = 0; i < MAX_SEND_PER_PASS; i++) + { + synchronized (con.getSendQueue()) + { + if (sendQueue.isEmpty()) + { + sp = null; + } + else + { + sp = sendQueue.removeFirst(); + } + } + + if (sp == null) + { + break; + } + + hasPending = true; + + // put into WriteBuffer + putPacketIntoWriteBuffer(client, sp); + + WRITE_BUFFER.flip(); + + if (DIRECT_WRITE_BUFFER.remaining() >= WRITE_BUFFER.limit()) + { + DIRECT_WRITE_BUFFER.put(WRITE_BUFFER); + } + else + { + con.createWriteBuffer(WRITE_BUFFER); + break; + } + } + } + return hasPending; + } + + private final void putPacketIntoWriteBuffer(final T client, final SendablePacket sp) + { + WRITE_BUFFER.clear(); + + // reserve space for the size + final int headerPos = WRITE_BUFFER.position(); + final int dataPos = headerPos + HEADER_SIZE; + WRITE_BUFFER.position(dataPos); + + // set the write buffer + sp._buf = WRITE_BUFFER; + // set the client. + sp._client = client; + // write content to buffer + sp.write(); + // delete the write buffer + sp._buf = null; + + // size (inclusive header) + int dataSize = WRITE_BUFFER.position() - dataPos; + WRITE_BUFFER.position(dataPos); + client.encrypt(WRITE_BUFFER, dataSize); + + // recalculate size after encryption + dataSize = WRITE_BUFFER.position() - dataPos; + + WRITE_BUFFER.position(headerPos); + // write header + WRITE_BUFFER.putShort((short) (dataSize + HEADER_SIZE)); + WRITE_BUFFER.position(dataPos + dataSize); + } + + final void closeConnection(final MMOConnection con) + { + synchronized (_pendingClose) + { + _pendingClose.addLast(con); + } + } + + private final void closeConnectionImpl(final SelectionKey key, final MMOConnection con) + { + try + { + // notify connection + con.getClient().onDisconnection(); + } + finally + { + try + { + // close socket and the SocketChannel + con.close(); + } + catch (IOException e) + { + // ignore, we are closing anyway + } + finally + { + con.releaseBuffers(); + // clear attachment + key.attach(null); + // cancel key + key.cancel(); + } + } + } + + public final void shutdown() + { + _shutdown = true; + } + + protected void closeSelectorThread() + { + for (final SelectionKey key : _selector.keys()) + { + try + { + key.channel().close(); + } + catch (IOException e) + { + // ignore + } + } + + try + { + _selector.close(); + } + catch (IOException e) + { + // Ignore + } + } +} diff --git a/trunk/java/com/l2jserver/commons/mmocore/SendablePacket.java b/trunk/java/com/l2jserver/commons/mmocore/SendablePacket.java new file mode 100644 index 0000000000..5a875137f2 --- /dev/null +++ b/trunk/java/com/l2jserver/commons/mmocore/SendablePacket.java @@ -0,0 +1,120 @@ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * http://www.gnu.org/copyleft/gpl.html + */ +package com.l2jserver.commons.mmocore; + +/** + * @author KenM + * @param + */ +public abstract class SendablePacket> extends AbstractPacket +{ + protected final void putInt(final int value) + { + _buf.putInt(value); + } + + protected final void putDouble(final double value) + { + _buf.putDouble(value); + } + + protected final void putFloat(final float value) + { + _buf.putFloat(value); + } + + /** + * Write byte to the buffer.
+ * 8bit integer (00) + * @param data + */ + protected final void writeC(final int data) + { + _buf.put((byte) data); + } + + /** + * Write double to the buffer.
+ * 64bit double precision float (00 00 00 00 00 00 00 00) + * @param value + */ + protected final void writeF(final double value) + { + _buf.putDouble(value); + } + + /** + * Write short to the buffer.
+ * 16bit integer (00 00) + * @param value + */ + protected final void writeH(final int value) + { + _buf.putShort((short) value); + } + + /** + * Write int to the buffer.
+ * 32bit integer (00 00 00 00) + * @param value + */ + protected final void writeD(final int value) + { + _buf.putInt(value); + } + + /** + * Write long to the buffer.
+ * 64bit integer (00 00 00 00 00 00 00 00) + * @param value + */ + protected final void writeQ(final long value) + { + _buf.putLong(value); + } + + /** + * Write byte[] to the buffer.
+ * 8bit integer array (00 ...) + * @param data + */ + protected final void writeB(final byte[] data) + { + _buf.put(data); + } + + /** + * Write String to the buffer. + * @param text + */ + protected final void writeS(final String text) + { + if (text != null) + { + final int len = text.length(); + for (int i = 0; i < len; i++) + { + _buf.putChar(text.charAt(i)); + } + } + + _buf.putChar('\000'); + } + + protected abstract void write(); +} diff --git a/trunk/java/com/l2jserver/gameserver/GameServer.java b/trunk/java/com/l2jserver/gameserver/GameServer.java index 4f2c2b7cac..f0a5369c11 100644 --- a/trunk/java/com/l2jserver/gameserver/GameServer.java +++ b/trunk/java/com/l2jserver/gameserver/GameServer.java @@ -30,13 +30,12 @@ import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; -import org.mmocore.network.SelectorConfig; -import org.mmocore.network.SelectorThread; - import com.l2jserver.Config; import com.l2jserver.L2DatabaseFactory; import com.l2jserver.Server; import com.l2jserver.UPnPService; +import com.l2jserver.commons.mmocore.SelectorConfig; +import com.l2jserver.commons.mmocore.SelectorThread; import com.l2jserver.gameserver.cache.HtmCache; import com.l2jserver.gameserver.data.sql.impl.AnnouncementsTable; import com.l2jserver.gameserver.data.sql.impl.CharNameTable; diff --git a/trunk/java/com/l2jserver/gameserver/GeoData.java b/trunk/java/com/l2jserver/gameserver/GeoData.java index c69f004866..a6be0b5a88 100644 --- a/trunk/java/com/l2jserver/gameserver/GeoData.java +++ b/trunk/java/com/l2jserver/gameserver/GeoData.java @@ -24,6 +24,8 @@ import java.util.logging.Level; import java.util.logging.Logger; import com.l2jserver.Config; +import com.l2jserver.commons.geodriver.Cell; +import com.l2jserver.commons.geodriver.GeoDriver; import com.l2jserver.gameserver.data.xml.impl.DoorData; import com.l2jserver.gameserver.model.L2Object; import com.l2jserver.gameserver.model.L2World; @@ -32,8 +34,6 @@ import com.l2jserver.gameserver.model.interfaces.ILocational; import com.l2jserver.gameserver.util.GeoUtils; import com.l2jserver.gameserver.util.LinePointIterator; import com.l2jserver.gameserver.util.LinePointIterator3D; -import com.l2jserver.geodriver.Cell; -import com.l2jserver.geodriver.GeoDriver; /** * @author -Nemesiss-, HorridoJoho diff --git a/trunk/java/com/l2jserver/gameserver/network/L2GameClient.java b/trunk/java/com/l2jserver/gameserver/network/L2GameClient.java index 6693f6c851..d5d5553edd 100644 --- a/trunk/java/com/l2jserver/gameserver/network/L2GameClient.java +++ b/trunk/java/com/l2jserver/gameserver/network/L2GameClient.java @@ -33,12 +33,11 @@ import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; -import org.mmocore.network.MMOClient; -import org.mmocore.network.MMOConnection; -import org.mmocore.network.ReceivablePacket; - import com.l2jserver.Config; import com.l2jserver.L2DatabaseFactory; +import com.l2jserver.commons.mmocore.MMOClient; +import com.l2jserver.commons.mmocore.MMOConnection; +import com.l2jserver.commons.mmocore.ReceivablePacket; import com.l2jserver.gameserver.LoginServerThread; import com.l2jserver.gameserver.LoginServerThread.SessionKey; import com.l2jserver.gameserver.ThreadPoolManager; diff --git a/trunk/java/com/l2jserver/gameserver/network/L2GamePacketHandler.java b/trunk/java/com/l2jserver/gameserver/network/L2GamePacketHandler.java index df05c06a62..e9726aa7a7 100644 --- a/trunk/java/com/l2jserver/gameserver/network/L2GamePacketHandler.java +++ b/trunk/java/com/l2jserver/gameserver/network/L2GamePacketHandler.java @@ -21,13 +21,12 @@ package com.l2jserver.gameserver.network; import java.nio.ByteBuffer; import java.util.logging.Logger; -import org.mmocore.network.IClientFactory; -import org.mmocore.network.IMMOExecutor; -import org.mmocore.network.IPacketHandler; -import org.mmocore.network.MMOConnection; -import org.mmocore.network.ReceivablePacket; - import com.l2jserver.Config; +import com.l2jserver.commons.mmocore.IClientFactory; +import com.l2jserver.commons.mmocore.IMMOExecutor; +import com.l2jserver.commons.mmocore.IPacketHandler; +import com.l2jserver.commons.mmocore.MMOConnection; +import com.l2jserver.commons.mmocore.ReceivablePacket; import com.l2jserver.gameserver.network.L2GameClient.GameClientState; import com.l2jserver.gameserver.network.clientpackets.*; import com.l2jserver.gameserver.network.clientpackets.crystalization.RequestCrystallizeEstimate; diff --git a/trunk/java/com/l2jserver/gameserver/network/clientpackets/L2GameClientPacket.java b/trunk/java/com/l2jserver/gameserver/network/clientpackets/L2GameClientPacket.java index 134c77fc5b..d6f824b5c6 100644 --- a/trunk/java/com/l2jserver/gameserver/network/clientpackets/L2GameClientPacket.java +++ b/trunk/java/com/l2jserver/gameserver/network/clientpackets/L2GameClientPacket.java @@ -22,9 +22,8 @@ import java.nio.BufferUnderflowException; import java.util.logging.Level; import java.util.logging.Logger; -import org.mmocore.network.ReceivablePacket; - import com.l2jserver.Config; +import com.l2jserver.commons.mmocore.ReceivablePacket; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.network.L2GameClient; import com.l2jserver.gameserver.network.SystemMessageId; diff --git a/trunk/java/com/l2jserver/gameserver/network/serverpackets/L2GameServerPacket.java b/trunk/java/com/l2jserver/gameserver/network/serverpackets/L2GameServerPacket.java index 31be943e46..f17fd1e55a 100644 --- a/trunk/java/com/l2jserver/gameserver/network/serverpackets/L2GameServerPacket.java +++ b/trunk/java/com/l2jserver/gameserver/network/serverpackets/L2GameServerPacket.java @@ -21,8 +21,7 @@ package com.l2jserver.gameserver.network.serverpackets; import java.util.logging.Level; import java.util.logging.Logger; -import org.mmocore.network.SendablePacket; - +import com.l2jserver.commons.mmocore.SendablePacket; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.model.interfaces.IPositionable; import com.l2jserver.gameserver.model.interfaces.IUpdateTypeComponent; diff --git a/trunk/java/com/l2jserver/gameserver/pathfinding/cellnodes/NodeLoc.java b/trunk/java/com/l2jserver/gameserver/pathfinding/cellnodes/NodeLoc.java index a843ee3235..2bdb36be8b 100644 --- a/trunk/java/com/l2jserver/gameserver/pathfinding/cellnodes/NodeLoc.java +++ b/trunk/java/com/l2jserver/gameserver/pathfinding/cellnodes/NodeLoc.java @@ -18,9 +18,9 @@ */ package com.l2jserver.gameserver.pathfinding.cellnodes; +import com.l2jserver.commons.geodriver.Cell; import com.l2jserver.gameserver.GeoData; import com.l2jserver.gameserver.pathfinding.AbstractNodeLoc; -import com.l2jserver.geodriver.Cell; /** * @author -Nemesiss-, HorridoJoho diff --git a/trunk/java/com/l2jserver/gameserver/script/Expression.java b/trunk/java/com/l2jserver/gameserver/script/Expression.java index 42e890e6ab..0ab50aa88d 100644 --- a/trunk/java/com/l2jserver/gameserver/script/Expression.java +++ b/trunk/java/com/l2jserver/gameserver/script/Expression.java @@ -23,8 +23,6 @@ import java.util.logging.Logger; import javax.script.ScriptContext; -import com.l2jserver.gameserver.scripting.L2ScriptEngineManager; - public class Expression { protected static final Logger _log = Logger.getLogger(Expression.class.getName()); @@ -34,32 +32,6 @@ public class Expression @SuppressWarnings("unused") private final String _code; - public static Object eval(String lang, String code) - { - try - { - return L2ScriptEngineManager.getInstance().eval(lang, code); - } - catch (Exception e) - { - _log.log(Level.WARNING, "", e); - return null; - } - } - - public static Object eval(ScriptContext context, String lang, String code) - { - try - { - return L2ScriptEngineManager.getInstance().eval(lang, code, context); - } - catch (Exception e) - { - _log.log(Level.WARNING, "", e); - return null; - } - } - public static Expression create(ScriptContext context, String lang, String code) { try diff --git a/trunk/java/com/l2jserver/gameserver/scripting/L2ScriptEngineManager.java b/trunk/java/com/l2jserver/gameserver/scripting/L2ScriptEngineManager.java index 12a1031a50..c0f2d808da 100644 --- a/trunk/java/com/l2jserver/gameserver/scripting/L2ScriptEngineManager.java +++ b/trunk/java/com/l2jserver/gameserver/scripting/L2ScriptEngineManager.java @@ -25,6 +25,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.LineNumberReader; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -40,9 +41,8 @@ import javax.script.ScriptEngineManager; import javax.script.ScriptException; import javax.script.SimpleScriptContext; -import javolution.util.FastMap; - import com.l2jserver.Config; +import com.l2jserver.commons.javaengine.JavaScriptEngineFactory; /** * Caches script engines and provides functionality for executing and managing scripts. @@ -59,8 +59,7 @@ public final class L2ScriptEngineManager return SingletonHolder._instance; } - private final Map _nameEngines = new FastMap<>(); - private final Map _extEngines = new FastMap<>(); + private final Map _extEngines = new HashMap<>(); private final List> _scriptManagers = new LinkedList<>(); private File _currentLoadingScript; @@ -87,56 +86,10 @@ public final class L2ScriptEngineManager protected L2ScriptEngineManager() { ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); - List factories = scriptEngineManager.getEngineFactories(); - - for (ScriptEngineFactory factory : factories) - { - try - { - ScriptEngine engine = factory.getScriptEngine(); - boolean reg = false; - for (String name : factory.getNames()) - { - ScriptEngine existentEngine = _nameEngines.get(name); - - if (existentEngine != null) - { - double engineVer = Double.parseDouble(factory.getEngineVersion()); - double existentEngVer = Double.parseDouble(existentEngine.getFactory().getEngineVersion()); - - if (engineVer <= existentEngVer) - { - continue; - } - } - - reg = true; - _nameEngines.put(name, engine); - } - - if (reg) - { - _log.info("Script Engine: " + factory.getEngineName() + " " + factory.getEngineVersion() + " - Language: " + factory.getLanguageName() + " - Language Version: " + factory.getLanguageVersion()); - } - - for (String ext : factory.getExtensions()) - { - if (!ext.equals("java") || factory.getLanguageName().equals("java")) - { - _extEngines.put(ext, engine); - } - } - } - catch (Exception e) - { - _log.log(Level.WARNING, "Failed initializing factory: " + e.getMessage(), e); - } - } - } - - private ScriptEngine getEngineByName(String name) - { - return _nameEngines.get(name); + ScriptEngineFactory factory = new JavaScriptEngineFactory(); + scriptEngineManager.registerEngineExtension("java", factory); + _extEngines.put("java", factory.getScriptEngine()); + _log.info("Script Engine: " + factory.getEngineName() + " " + factory.getEngineVersion() + " - Language: " + factory.getLanguageName() + " - Language Version: " + factory.getLanguageVersion()); } private ScriptEngine getEngineByExtension(String ext) @@ -303,16 +256,6 @@ public final class L2ScriptEngineManager executeScript(engine, file); } - public void executeScript(String engineName, File file) throws ScriptException - { - ScriptEngine engine = getEngineByName(engineName); - if (engine == null) - { - throw new ScriptException("No engine registered with name (" + engineName + ")"); - } - executeScript(engine, file); - } - public void executeScript(ScriptEngine engine, File file) throws ScriptException { if (VERBOSE_LOADING) @@ -375,16 +318,6 @@ public final class L2ScriptEngineManager return engine.getContext(); } - public ScriptContext getScriptContext(String engineName) - { - ScriptEngine engine = getEngineByName(engineName); - if (engine == null) - { - throw new IllegalStateException("No engine registered with name (" + engineName + ")"); - } - return getScriptContext(engine); - } - public Object eval(ScriptEngine engine, String script, ScriptContext context) throws ScriptException { if ((engine instanceof Compilable) && ATTEMPT_COMPILATION) @@ -396,21 +329,6 @@ public final class L2ScriptEngineManager return context != null ? engine.eval(script, context) : engine.eval(script); } - public Object eval(String engineName, String script) throws ScriptException - { - return eval(engineName, script, null); - } - - public Object eval(String engineName, String script, ScriptContext context) throws ScriptException - { - ScriptEngine engine = getEngineByName(engineName); - if (engine == null) - { - throw new ScriptException("No engine registered with name (" + engineName + ")"); - } - return eval(engine, script, context); - } - public Object eval(ScriptEngine engine, String script) throws ScriptException { return eval(engine, script, null); @@ -454,7 +372,6 @@ public final class L2ScriptEngineManager public List> getScriptManagers() { return _scriptManagers; - } /** diff --git a/trunk/java/com/l2jserver/gameserver/util/GeoUtils.java b/trunk/java/com/l2jserver/gameserver/util/GeoUtils.java index bbef02a38c..444943315e 100644 --- a/trunk/java/com/l2jserver/gameserver/util/GeoUtils.java +++ b/trunk/java/com/l2jserver/gameserver/util/GeoUtils.java @@ -20,10 +20,10 @@ package com.l2jserver.gameserver.util; import java.awt.Color; +import com.l2jserver.commons.geodriver.Cell; import com.l2jserver.gameserver.GeoData; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.network.serverpackets.ExServerPrimitive; -import com.l2jserver.geodriver.Cell; /** * @author HorridoJoho diff --git a/trunk/java/com/l2jserver/loginserver/L2LoginServer.java b/trunk/java/com/l2jserver/loginserver/L2LoginServer.java index 24754b2ebb..239c17f92f 100644 --- a/trunk/java/com/l2jserver/loginserver/L2LoginServer.java +++ b/trunk/java/com/l2jserver/loginserver/L2LoginServer.java @@ -32,13 +32,12 @@ import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; -import org.mmocore.network.SelectorConfig; -import org.mmocore.network.SelectorThread; - import com.l2jserver.Config; import com.l2jserver.L2DatabaseFactory; import com.l2jserver.Server; import com.l2jserver.UPnPService; +import com.l2jserver.commons.mmocore.SelectorConfig; +import com.l2jserver.commons.mmocore.SelectorThread; import com.l2jserver.loginserver.mail.MailSystem; import com.l2jserver.loginserver.network.L2LoginClient; import com.l2jserver.loginserver.network.L2LoginPacketHandler; diff --git a/trunk/java/com/l2jserver/loginserver/SelectorHelper.java b/trunk/java/com/l2jserver/loginserver/SelectorHelper.java index e646375d50..6bca5b08f9 100644 --- a/trunk/java/com/l2jserver/loginserver/SelectorHelper.java +++ b/trunk/java/com/l2jserver/loginserver/SelectorHelper.java @@ -23,12 +23,11 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; -import org.mmocore.network.IAcceptFilter; -import org.mmocore.network.IClientFactory; -import org.mmocore.network.IMMOExecutor; -import org.mmocore.network.MMOConnection; -import org.mmocore.network.ReceivablePacket; - +import com.l2jserver.commons.mmocore.IAcceptFilter; +import com.l2jserver.commons.mmocore.IClientFactory; +import com.l2jserver.commons.mmocore.IMMOExecutor; +import com.l2jserver.commons.mmocore.MMOConnection; +import com.l2jserver.commons.mmocore.ReceivablePacket; import com.l2jserver.loginserver.network.L2LoginClient; import com.l2jserver.loginserver.network.serverpackets.Init; import com.l2jserver.util.IPv4Filter; diff --git a/trunk/java/com/l2jserver/loginserver/network/L2LoginClient.java b/trunk/java/com/l2jserver/loginserver/network/L2LoginClient.java index 62485496bc..ddd37142b6 100644 --- a/trunk/java/com/l2jserver/loginserver/network/L2LoginClient.java +++ b/trunk/java/com/l2jserver/loginserver/network/L2LoginClient.java @@ -26,11 +26,10 @@ import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; -import org.mmocore.network.MMOClient; -import org.mmocore.network.MMOConnection; -import org.mmocore.network.SendablePacket; - import com.l2jserver.Config; +import com.l2jserver.commons.mmocore.MMOClient; +import com.l2jserver.commons.mmocore.MMOConnection; +import com.l2jserver.commons.mmocore.SendablePacket; import com.l2jserver.loginserver.LoginController; import com.l2jserver.loginserver.SessionKey; import com.l2jserver.loginserver.network.serverpackets.L2LoginServerPacket; diff --git a/trunk/java/com/l2jserver/loginserver/network/L2LoginPacketHandler.java b/trunk/java/com/l2jserver/loginserver/network/L2LoginPacketHandler.java index d837f76b2e..7e7aca5f44 100644 --- a/trunk/java/com/l2jserver/loginserver/network/L2LoginPacketHandler.java +++ b/trunk/java/com/l2jserver/loginserver/network/L2LoginPacketHandler.java @@ -21,9 +21,8 @@ package com.l2jserver.loginserver.network; import java.nio.ByteBuffer; import java.util.logging.Logger; -import org.mmocore.network.IPacketHandler; -import org.mmocore.network.ReceivablePacket; - +import com.l2jserver.commons.mmocore.IPacketHandler; +import com.l2jserver.commons.mmocore.ReceivablePacket; import com.l2jserver.loginserver.network.L2LoginClient.LoginClientState; import com.l2jserver.loginserver.network.clientpackets.AuthGameGuard; import com.l2jserver.loginserver.network.clientpackets.RequestAuthLogin; diff --git a/trunk/java/com/l2jserver/loginserver/network/clientpackets/L2LoginClientPacket.java b/trunk/java/com/l2jserver/loginserver/network/clientpackets/L2LoginClientPacket.java index 6ad35b9aff..ecd01624fd 100644 --- a/trunk/java/com/l2jserver/loginserver/network/clientpackets/L2LoginClientPacket.java +++ b/trunk/java/com/l2jserver/loginserver/network/clientpackets/L2LoginClientPacket.java @@ -21,8 +21,7 @@ package com.l2jserver.loginserver.network.clientpackets; import java.util.logging.Level; import java.util.logging.Logger; -import org.mmocore.network.ReceivablePacket; - +import com.l2jserver.commons.mmocore.ReceivablePacket; import com.l2jserver.loginserver.network.L2LoginClient; /** diff --git a/trunk/java/com/l2jserver/loginserver/network/serverpackets/L2LoginServerPacket.java b/trunk/java/com/l2jserver/loginserver/network/serverpackets/L2LoginServerPacket.java index 13540602b0..75ad9379a6 100644 --- a/trunk/java/com/l2jserver/loginserver/network/serverpackets/L2LoginServerPacket.java +++ b/trunk/java/com/l2jserver/loginserver/network/serverpackets/L2LoginServerPacket.java @@ -18,8 +18,7 @@ */ package com.l2jserver.loginserver.network.serverpackets; -import org.mmocore.network.SendablePacket; - +import com.l2jserver.commons.mmocore.SendablePacket; import com.l2jserver.loginserver.network.L2LoginClient; /** diff --git a/trunk/java/com/l2jserver/util/IPv4Filter.java b/trunk/java/com/l2jserver/util/IPv4Filter.java index c35aee1659..1e5a856949 100644 --- a/trunk/java/com/l2jserver/util/IPv4Filter.java +++ b/trunk/java/com/l2jserver/util/IPv4Filter.java @@ -24,7 +24,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; -import org.mmocore.network.IAcceptFilter; +import com.l2jserver.commons.mmocore.IAcceptFilter; /** * IPv4 filter. diff --git a/trunk/launcher/Gameserver.launch b/trunk/launcher/Gameserver.launch index ec2dadc500..79600c7fcd 100644 --- a/trunk/launcher/Gameserver.launch +++ b/trunk/launcher/Gameserver.launch @@ -7,7 +7,7 @@ - + diff --git a/trunk/launcher/Loginserver.launch b/trunk/launcher/Loginserver.launch index 5f0e1061fc..9db50a66a0 100644 --- a/trunk/launcher/Loginserver.launch +++ b/trunk/launcher/Loginserver.launch @@ -7,7 +7,7 @@ - +