diff --git a/.settings/org.eclipse.buildship.core.prefs b/.settings/org.eclipse.buildship.core.prefs index d3def490542bf001de6b7ed62b76fc238071caf8..f03fcbd9fc6b1c0434a46d23e1fbcf9ac7ce3a47 100644 --- a/.settings/org.eclipse.buildship.core.prefs +++ b/.settings/org.eclipse.buildship.core.prefs @@ -1,11 +1,10 @@ -#Fri Oct 27 16:04:33 UYT 2017 +build.commands=org.eclipse.jdt.core.javabuilder connection.arguments= -containers=org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/ +connection.java.home=null connection.jvm.arguments= -build.commands=org.eclipse.jdt.core.javabuilder connection.project.dir= -natures=org.eclipse.jdt.core.javanature -eclipse.preferences.version=1 -connection.java.home=null +containers=org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/ derived.resources=.gradle,build +eclipse.preferences.version=1 +natures=org.eclipse.jdt.core.javanature project.path=\: diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index 43f72e784f56f35de7d5cc776fe7d0b366e328ce..e504933df816a4dfacb513d47d02ba31a77efb83 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -20,9 +20,9 @@ org.eclipse.jdt.core.compiler.annotation.nullable.secondary= org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=10 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.compliance=10 org.eclipse.jdt.core.compiler.debug.lineNumber=generate org.eclipse.jdt.core.compiler.debug.localVariable=generate org.eclipse.jdt.core.compiler.debug.sourceFile=generate @@ -127,7 +127,7 @@ org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=warning org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.compiler.source=10 org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0 diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml index 37352283964b9b2cdf50a5610197f12fc4cd18b8..6ec462bfe8e9a5dd980c33893c28357c6c0a43d3 100644 --- a/bitbucket-pipelines.yml +++ b/bitbucket-pipelines.yml @@ -1,4 +1,4 @@ -image: java:8 +image: openjdk:10.0.2-13-jre-sid pipelines: default: diff --git a/build.gradle b/build.gradle index 8b3a594781ab649e34f0733369d77baec803fe41..de7f966f8a83ebfbdee0c10e6ed5791e1f0f696d 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,8 @@ apply plugin: 'eclipse' defaultTasks('zip') -sourceCompatibility = JavaVersion.VERSION_1_8 +sourceCompatibility = JavaVersion.VERSION_1_10 +targetCompatibility = JavaVersion.VERSION_1_10 sourceSets { mainSource { @@ -25,8 +26,8 @@ dependencies { compile 'org.slf4j:slf4j-api:1.7.25' compile files('../L2J_Server/dist/libs/mmocore.jar') compile project(':L2J_Server') - testCompile 'org.testng:testng:6.11' - testCompile 'org.jmockit:jmockit:1.35' + testCompile 'org.testng:testng:6.14.3' + testCompile 'org.mockito:mockito-core:2.20.1' } task zip(type: Zip) { @@ -38,10 +39,6 @@ task zip(type: Zip) { build.finalizedBy(zip) -task wrapper(type: Wrapper) { - gradleVersion = '3.5' -} - eclipse { project { name = 'L2J_DataPack' diff --git a/dist/game/data/scripts/gracia/GraciaLoader.java b/dist/game/data/scripts/gracia/GraciaLoader.java index 208e488fee8f7898507165bffb9d2cb6c928ff5f..dce8a2ff5eb327587188b3268b7d213f6ace8ffd 100644 --- a/dist/game/data/scripts/gracia/GraciaLoader.java +++ b/dist/game/data/scripts/gracia/GraciaLoader.java @@ -86,7 +86,7 @@ public final class GraciaLoader { try { - script.newInstance(); + script.getDeclaredConstructor().newInstance(); } catch (Exception e) { diff --git a/dist/game/data/scripts/handlers/EffectMasterHandler.java b/dist/game/data/scripts/handlers/EffectMasterHandler.java index 850a344bae2c8893d821295eed85e6aa18fabb70..f28c566aed2573c531e1b127c6b02c105692a93c 100644 --- a/dist/game/data/scripts/handlers/EffectMasterHandler.java +++ b/dist/game/data/scripts/handlers/EffectMasterHandler.java @@ -18,7 +18,6 @@ */ package handlers; -import java.util.logging.Level; import java.util.logging.Logger; import com.l2jserver.gameserver.handler.EffectHandler; @@ -362,21 +361,8 @@ public final class EffectMasterHandler { for (Class<?> c : EFFECTS) { - if (c == null) - { - continue; // Disabled handler - } EffectHandler.getInstance().registerHandler((Class<? extends AbstractEffect>) c); } - - // And lets try get size - try - { - _log.log(Level.INFO, EffectMasterHandler.class.getSimpleName() + ": Loaded " + EffectHandler.getInstance().size() + " effect handlers."); - } - catch (Exception e) - { - _log.log(Level.WARNING, "Failed invoking size method for handler: " + EffectMasterHandler.class.getSimpleName(), e); - } + _log.info(EffectMasterHandler.class.getSimpleName() + ": Loaded " + EffectHandler.getInstance().size() + " effect handlers."); } } diff --git a/dist/game/data/scripts/handlers/MasterHandler.java b/dist/game/data/scripts/handlers/MasterHandler.java index ec5cab52034da38619005fbb1b52866af3b8e286..bd0287e04b003f913f636eae48f511abe32cc0e8 100644 --- a/dist/game/data/scripts/handlers/MasterHandler.java +++ b/dist/game/data/scripts/handlers/MasterHandler.java @@ -18,12 +18,8 @@ */ package handlers; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.logging.Level; -import java.util.logging.Logger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.l2jserver.Config; import com.l2jserver.gameserver.handler.ActionHandler; @@ -180,7 +176,6 @@ import handlers.communityboard.HomepageBoard; import handlers.communityboard.MailBoard; import handlers.communityboard.MemoBoard; import handlers.communityboard.RegionBoard; -import handlers.custom.CustomAnnouncePkPvP; import handlers.itemhandlers.BeastSoulShot; import handlers.itemhandlers.BeastSpiritShot; import handlers.itemhandlers.BlessedSpiritShot; @@ -286,370 +281,346 @@ import handlers.voicedcommandhandlers.Wedding; /** * Master handler. * @author UnAfraid + * @author Zoey76 */ public class MasterHandler { - private static final Logger _log = Logger.getLogger(MasterHandler.class.getName()); + private static final Logger LOG = LoggerFactory.getLogger(MasterHandler.class); - private static final IHandler<?, ?>[] LOAD_INSTANCES = + private static final Class<?>[] ACTION_HANDLERS = { - ActionHandler.getInstance(), - ActionShiftHandler.getInstance(), - AdminCommandHandler.getInstance(), - BypassHandler.getInstance(), - ChatHandler.getInstance(), - CommunityBoardHandler.getInstance(), - ItemHandler.getInstance(), - PunishmentHandler.getInstance(), - UserCommandHandler.getInstance(), - VoicedCommandHandler.getInstance(), - TargetHandler.getInstance(), - TelnetHandler.getInstance(), + L2ArtefactInstanceAction.class, + L2DecoyAction.class, + L2DoorInstanceAction.class, + L2ItemInstanceAction.class, + L2NpcAction.class, + L2PcInstanceAction.class, + L2PetInstanceAction.class, + L2StaticObjectInstanceAction.class, + L2SummonAction.class, + L2TrapAction.class, }; - private static final Class<?>[][] HANDLERS = + private static final Class<?>[] ACTION_SHIFT_HANDLERS = { - { - // Action Handlers - L2ArtefactInstanceAction.class, - L2DecoyAction.class, - L2DoorInstanceAction.class, - L2ItemInstanceAction.class, - L2NpcAction.class, - L2PcInstanceAction.class, - L2PetInstanceAction.class, - L2StaticObjectInstanceAction.class, - L2SummonAction.class, - L2TrapAction.class, - }, - { - // Action Shift Handlers - L2DoorInstanceActionShift.class, - L2ItemInstanceActionShift.class, - L2NpcActionShift.class, - L2PcInstanceActionShift.class, - L2StaticObjectInstanceActionShift.class, - L2SummonActionShift.class, - }, - { - // Admin Command Handlers - AdminAdmin.class, - AdminAnnouncements.class, - AdminBBS.class, - AdminBuffs.class, - AdminCamera.class, - AdminChangeAccessLevel.class, - AdminCHSiege.class, - AdminClan.class, - AdminPcCondOverride.class, - AdminCreateItem.class, - AdminCursedWeapons.class, - AdminDebug.class, - AdminDelete.class, - AdminDisconnect.class, - AdminDoorControl.class, - AdminEditChar.class, - AdminEffects.class, - AdminElement.class, - AdminEnchant.class, - AdminEventEngine.class, - AdminEvents.class, - AdminExpSp.class, - AdminFightCalculator.class, - AdminFortSiege.class, - AdminGeodata.class, - AdminGm.class, - AdminGmChat.class, - AdminGraciaSeeds.class, - AdminGrandBoss.class, - AdminHeal.class, - AdminHtml.class, - AdminInstance.class, - AdminInstanceZone.class, - AdminInvul.class, - AdminKick.class, - AdminKill.class, - AdminLevel.class, - AdminLogin.class, - AdminMammon.class, - AdminManor.class, - AdminMenu.class, - AdminMessages.class, - AdminMobGroup.class, - AdminMonsterRace.class, - AdminPathNode.class, - AdminPetition.class, - AdminPForge.class, - AdminPledge.class, - AdminPolymorph.class, - AdminPunishment.class, - AdminQuest.class, - AdminReload.class, - AdminRepairChar.class, - AdminRes.class, - AdminRide.class, - AdminScan.class, - AdminShop.class, - AdminShowQuests.class, - AdminShutdown.class, - AdminSiege.class, - AdminSkill.class, - AdminSpawn.class, - AdminSummon.class, - AdminTarget.class, - AdminTargetSay.class, - AdminTeleport.class, - AdminTerritoryWar.class, - AdminTest.class, - AdminTvTEvent.class, - AdminUnblockIp.class, - AdminVitality.class, - AdminZone.class, - }, - { - // Bypass Handlers - Augment.class, - Buy.class, - BuyShadowItem.class, - ChatLink.class, - ClanWarehouse.class, - EventEngine.class, - Festival.class, - Freight.class, - ItemAuctionLink.class, - Link.class, - Loto.class, - Multisell.class, - NpcViewMod.class, - Observation.class, - OlympiadObservation.class, - OlympiadManagerLink.class, - QuestLink.class, - PlayerHelp.class, - PrivateWarehouse.class, - QuestList.class, - ReceivePremium.class, - ReleaseAttribute.class, - RentPet.class, - Rift.class, - SkillList.class, - SupportBlessing.class, - SupportMagic.class, - TerritoryStatus.class, - TutorialClose.class, - VoiceCommand.class, - Wear.class, - }, - { - // Chat Handlers - ChatAll.class, - ChatAlliance.class, - ChatBattlefield.class, - ChatClan.class, - ChatHeroVoice.class, - ChatParty.class, - ChatPartyMatchRoom.class, - ChatPartyRoomAll.class, - ChatPartyRoomCommander.class, - ChatPetition.class, - ChatShout.class, - ChatTell.class, - ChatTrade.class, - }, - { - // Community Board - ClanBoard.class, - FavoriteBoard.class, - FriendsBoard.class, - HomeBoard.class, - HomepageBoard.class, - MailBoard.class, - MemoBoard.class, - RegionBoard.class, - }, - { - // Item Handlers - BeastSoulShot.class, - BeastSpiritShot.class, - BlessedSpiritShot.class, - Book.class, - Bypass.class, - Calculator.class, - CharmOfCourage.class, - Disguise.class, - Elixir.class, - EnchantAttribute.class, - EnchantScrolls.class, - EventItem.class, - ExtractableItems.class, - FishShots.class, - Harvester.class, - ItemSkills.class, - ItemSkillsTemplate.class, - ManaPotion.class, - Maps.class, - MercTicket.class, - NicknameColor.class, - PetFood.class, - Recipes.class, - RollingDice.class, - Seed.class, - SevenSignsRecord.class, - SoulShots.class, - SpecialXMas.class, - SpiritShot.class, - SummonItems.class, - TeleportBookmark.class, - }, - { - // Punishment Handlers - BanHandler.class, - ChatBanHandler.class, - JailHandler.class, - }, - { - // User Command Handlers - ClanPenalty.class, - ClanWarsList.class, - Dismount.class, - Unstuck.class, - InstanceZone.class, - Loc.class, - Mount.class, - PartyInfo.class, - Time.class, - OlympiadStat.class, - ChannelLeave.class, - ChannelDelete.class, - ChannelInfo.class, - MyBirthday.class, - SiegeStatus.class, - }, - { - // Voiced Command Handlers - StatsVCmd.class, - // TODO: Add configuration options for this voiced commands: - // CastleVCmd.class, - // SetVCmd.class, - (Config.L2JMOD_ALLOW_WEDDING ? Wedding.class : null), - (Config.BANKING_SYSTEM_ENABLED ? Banking.class : null), - (Config.L2JMOD_CHAT_ADMIN ? ChatAdmin.class : null), - (Config.L2JMOD_MULTILANG_ENABLE && Config.L2JMOD_MULTILANG_VOICED_ALLOW ? Lang.class : null), - (Config.L2JMOD_DEBUG_VOICE_COMMAND ? Debug.class : null), - (Config.L2JMOD_ALLOW_CHANGE_PASSWORD ? ChangePassword.class : null), - }, - { - // Target Handlers - Area.class, - AreaCorpseMob.class, - AreaFriendly.class, - AreaSummon.class, - Aura.class, - AuraCorpseMob.class, - AuraFriendly.class, - AuraUndeadEnemy.class, - BehindArea.class, - BehindAura.class, - Clan.class, - ClanMember.class, - CommandChannel.class, - CorpseClan.class, - CorpseMob.class, - Enemy.class, - EnemyOnly.class, - EnemySummon.class, - FlagPole.class, - FrontArea.class, - FrontAura.class, - Ground.class, - Holy.class, - One.class, - OwnerPet.class, - Party.class, - PartyClan.class, - PartyMember.class, - PartyNotMe.class, - PartyOther.class, - PcBody.class, - Pet.class, - Self.class, - Servitor.class, - Summon.class, - TargetParty.class, - Unlockable.class, - }, - { - // Telnet Handlers - ChatsHandler.class, - DebugHandler.class, - HelpHandler.class, - PlayerHandler.class, - ReloadHandler.class, - ServerHandler.class, - StatusHandler.class, - ThreadHandler.class, - }, - { - // Custom Handlers - CustomAnnouncePkPvP.class - } + L2DoorInstanceActionShift.class, + L2ItemInstanceActionShift.class, + L2NpcActionShift.class, + L2PcInstanceActionShift.class, + L2StaticObjectInstanceActionShift.class, + L2SummonActionShift.class, }; + private static final Class<?>[] ADMIN_HANDLERS = + { + AdminAdmin.class, + AdminAnnouncements.class, + AdminBBS.class, + AdminBuffs.class, + AdminCamera.class, + AdminChangeAccessLevel.class, + AdminCHSiege.class, + AdminClan.class, + AdminPcCondOverride.class, + AdminCreateItem.class, + AdminCursedWeapons.class, + AdminDebug.class, + AdminDelete.class, + AdminDisconnect.class, + AdminDoorControl.class, + AdminEditChar.class, + AdminEffects.class, + AdminElement.class, + AdminEnchant.class, + AdminEventEngine.class, + AdminEvents.class, + AdminExpSp.class, + AdminFightCalculator.class, + AdminFortSiege.class, + AdminGeodata.class, + AdminGm.class, + AdminGmChat.class, + AdminGraciaSeeds.class, + AdminGrandBoss.class, + AdminHeal.class, + AdminHtml.class, + AdminInstance.class, + AdminInstanceZone.class, + AdminInvul.class, + AdminKick.class, + AdminKill.class, + AdminLevel.class, + AdminLogin.class, + AdminMammon.class, + AdminManor.class, + AdminMenu.class, + AdminMessages.class, + AdminMobGroup.class, + AdminMonsterRace.class, + AdminPathNode.class, + AdminPetition.class, + AdminPForge.class, + AdminPledge.class, + AdminPolymorph.class, + AdminPunishment.class, + AdminQuest.class, + AdminReload.class, + AdminRepairChar.class, + AdminRes.class, + AdminRide.class, + AdminScan.class, + AdminShop.class, + AdminShowQuests.class, + AdminShutdown.class, + AdminSiege.class, + AdminSkill.class, + AdminSpawn.class, + AdminSummon.class, + AdminTarget.class, + AdminTargetSay.class, + AdminTeleport.class, + AdminTerritoryWar.class, + AdminTest.class, + AdminTvTEvent.class, + AdminUnblockIp.class, + AdminVitality.class, + AdminZone.class, + }; + + private static final Class<?>[] BYPASS_HANDLERS = + { + Augment.class, + Buy.class, + BuyShadowItem.class, + ChatLink.class, + ClanWarehouse.class, + EventEngine.class, + Festival.class, + Freight.class, + ItemAuctionLink.class, + Link.class, + Loto.class, + Multisell.class, + NpcViewMod.class, + Observation.class, + OlympiadObservation.class, + OlympiadManagerLink.class, + QuestLink.class, + PlayerHelp.class, + PrivateWarehouse.class, + QuestList.class, + ReceivePremium.class, + ReleaseAttribute.class, + RentPet.class, + Rift.class, + SkillList.class, + SupportBlessing.class, + SupportMagic.class, + TerritoryStatus.class, + TutorialClose.class, + VoiceCommand.class, + Wear.class, + }; + + private static final Class<?>[] CHAT_HANDLERS = + { + ChatAll.class, + ChatAlliance.class, + ChatBattlefield.class, + ChatClan.class, + ChatHeroVoice.class, + ChatParty.class, + ChatPartyMatchRoom.class, + ChatPartyRoomAll.class, + ChatPartyRoomCommander.class, + ChatPetition.class, + ChatShout.class, + ChatTell.class, + ChatTrade.class, + }; + + private static final Class<?>[] COMMUNITY_HANDLERS = + { + ClanBoard.class, + FavoriteBoard.class, + FriendsBoard.class, + HomeBoard.class, + HomepageBoard.class, + MailBoard.class, + MemoBoard.class, + RegionBoard.class, + }; + + private static final Class<?>[] ITEM_HANDLERS = + { + BeastSoulShot.class, + BeastSpiritShot.class, + BlessedSpiritShot.class, + Book.class, + Bypass.class, + Calculator.class, + CharmOfCourage.class, + Disguise.class, + Elixir.class, + EnchantAttribute.class, + EnchantScrolls.class, + EventItem.class, + ExtractableItems.class, + FishShots.class, + Harvester.class, + ItemSkillsTemplate.class, + ItemSkills.class, + ManaPotion.class, + Maps.class, + MercTicket.class, + NicknameColor.class, + PetFood.class, + Recipes.class, + RollingDice.class, + Seed.class, + SevenSignsRecord.class, + SoulShots.class, + SpecialXMas.class, + SpiritShot.class, + SummonItems.class, + TeleportBookmark.class, + }; + + private static final Class<?>[] PUNISHMENT_HANDLERS = + { + BanHandler.class, + ChatBanHandler.class, + JailHandler.class, + }; + + private static final Class<?>[] USER_COMMAND_HANDLERS = + { + ClanPenalty.class, + ClanWarsList.class, + Dismount.class, + Unstuck.class, + InstanceZone.class, + Loc.class, + Mount.class, + PartyInfo.class, + Time.class, + OlympiadStat.class, + ChannelLeave.class, + ChannelDelete.class, + ChannelInfo.class, + MyBirthday.class, + SiegeStatus.class, + }; + + private static final Class<?>[] TARGET_HANDLERS = + { + Area.class, + AreaCorpseMob.class, + AreaFriendly.class, + AreaSummon.class, + Aura.class, + AuraCorpseMob.class, + AuraFriendly.class, + AuraUndeadEnemy.class, + BehindArea.class, + BehindAura.class, + Clan.class, + ClanMember.class, + CommandChannel.class, + CorpseClan.class, + CorpseMob.class, + Enemy.class, + EnemyOnly.class, + EnemySummon.class, + FlagPole.class, + FrontArea.class, + FrontAura.class, + Ground.class, + Holy.class, + One.class, + OwnerPet.class, + Party.class, + PartyClan.class, + PartyMember.class, + PartyNotMe.class, + PartyOther.class, + PcBody.class, + Pet.class, + Self.class, + Servitor.class, + Summon.class, + TargetParty.class, + Unlockable.class, + }; + + private static final Class<?>[] TELNET_HANDLERS = + { + ChatsHandler.class, + DebugHandler.class, + HelpHandler.class, + PlayerHandler.class, + ReloadHandler.class, + ServerHandler.class, + StatusHandler.class, + ThreadHandler.class, + }; + + private static final Class<?>[] VOICED_COMMAND_HANDLERS = + { + StatsVCmd.class, + // TODO: Add configuration options for this voiced commands: + // CastleVCmd.class, + // SetVCmd.class, + (Config.L2JMOD_ALLOW_WEDDING ? Wedding.class : null), + (Config.BANKING_SYSTEM_ENABLED ? Banking.class : null), + (Config.L2JMOD_CHAT_ADMIN ? ChatAdmin.class : null), + (Config.L2JMOD_MULTILANG_ENABLE && Config.L2JMOD_MULTILANG_VOICED_ALLOW ? Lang.class : null), + (Config.L2JMOD_DEBUG_VOICE_COMMAND ? Debug.class : null), + (Config.L2JMOD_ALLOW_CHANGE_PASSWORD ? ChangePassword.class : null), + }; + + // TODO(Zoey76): Add this handler. + // private static final Class<?>[] CUSTOM_HANDLERS = + // { + // CustomAnnouncePkPvP.class + // }; + public static void main(String[] args) { - _log.log(Level.INFO, "Loading Handlers..."); - - Map<IHandler<?, ?>, Method> registerHandlerMethods = new HashMap<>(); - for (IHandler<?, ?> loadInstance : LOAD_INSTANCES) + LOG.info("Loading Handlers..."); + loadHandlers(VoicedCommandHandler.getInstance(), VOICED_COMMAND_HANDLERS); + loadHandlers(ActionHandler.getInstance(), ACTION_HANDLERS); + loadHandlers(ActionShiftHandler.getInstance(), ACTION_SHIFT_HANDLERS); + loadHandlers(AdminCommandHandler.getInstance(), ADMIN_HANDLERS); + loadHandlers(BypassHandler.getInstance(), BYPASS_HANDLERS); + loadHandlers(ChatHandler.getInstance(), CHAT_HANDLERS); + loadHandlers(CommunityBoardHandler.getInstance(), COMMUNITY_HANDLERS); + loadHandlers(ItemHandler.getInstance(), ITEM_HANDLERS); + loadHandlers(PunishmentHandler.getInstance(), PUNISHMENT_HANDLERS); + loadHandlers(UserCommandHandler.getInstance(), USER_COMMAND_HANDLERS); + loadHandlers(TargetHandler.getInstance(), TARGET_HANDLERS); + loadHandlers(TelnetHandler.getInstance(), TELNET_HANDLERS); + LOG.info("Handlers Loaded..."); + } + + private static void loadHandlers(IHandler<?, ?> handler, Class<?>[] classes) + { + for (Class<?> c : classes) { - registerHandlerMethods.put(loadInstance, null); - for (Method method : loadInstance.getClass().getMethods()) + if (c == null) { - if (method.getName().equals("registerHandler") && !method.isBridge()) - { - registerHandlerMethods.put(loadInstance, method); - } + continue; } - } - - registerHandlerMethods.entrySet().stream().filter(e -> e.getValue() == null).forEach(e -> - { - _log.log(Level.WARNING, "Failed loading handlers of: " + e.getKey().getClass().getSimpleName() + " seems registerHandler function does not exist."); - }); - - for (Class<?> classes[] : HANDLERS) - { - for (Class<?> c : classes) + + try { - if (c == null) - { - continue; // Disabled handler - } - - try - { - Object handler = c.newInstance(); - for (Entry<IHandler<?, ?>, Method> entry : registerHandlerMethods.entrySet()) - { - if ((entry.getValue() != null) && entry.getValue().getParameterTypes()[0].isInstance(handler)) - { - entry.getValue().invoke(entry.getKey(), handler); - } - } - } - catch (Exception e) - { - _log.log(Level.WARNING, "Failed loading handler: " + c.getSimpleName(), e); - continue; - } + handler.registerByClass(c); + } + catch (Exception ex) + { + LOG.error("Failed loading handler {}!", c.getSimpleName(), ex); } } - - for (IHandler<?, ?> loadInstance : LOAD_INSTANCES) - { - _log.log(Level.INFO, loadInstance.getClass().getSimpleName() + ": Loaded " + loadInstance.size() + " Handlers"); - } - - _log.log(Level.INFO, "Handlers Loaded..."); + LOG.info("{}: Loaded {} handlers.", handler.getClass().getSimpleName(), handler.size()); } } \ No newline at end of file diff --git a/dist/game/data/scripts/handlers/admincommandhandlers/AdminCHSiege.java b/dist/game/data/scripts/handlers/admincommandhandlers/AdminCHSiege.java index 4fff78ea048fd55e89c96632f41a7c0446888a8b..67526243e08c857e275cd1e5a29d206a04e48612 100644 --- a/dist/game/data/scripts/handlers/admincommandhandlers/AdminCHSiege.java +++ b/dist/game/data/scripts/handlers/admincommandhandlers/AdminCHSiege.java @@ -61,7 +61,7 @@ public final class AdminCHSiege implements IAdminCommandHandler { final String[] split = command.split(" "); SiegableHall hall = null; - if (Config.ALT_DEV_NO_QUESTS) + if (Config.NO_QUESTS) { activeChar.sendMessage("AltDevNoQuests = true; Clan Hall Sieges are disabled!"); return false; diff --git a/dist/game/data/scripts/handlers/admincommandhandlers/AdminQuest.java b/dist/game/data/scripts/handlers/admincommandhandlers/AdminQuest.java index 9f7b00bba2656f0d40058d6474d3334c7a1d8e46..f4dbb2a27914e803ba1fa263ed99eef1ed95d598 100644 --- a/dist/game/data/scripts/handlers/admincommandhandlers/AdminQuest.java +++ b/dist/game/data/scripts/handlers/admincommandhandlers/AdminQuest.java @@ -25,6 +25,9 @@ import java.util.TreeSet; import javax.script.ScriptException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.l2jserver.gameserver.handler.IAdminCommandHandler; import com.l2jserver.gameserver.instancemanager.QuestManager; import com.l2jserver.gameserver.model.actor.L2Character; @@ -35,11 +38,13 @@ import com.l2jserver.gameserver.model.events.listeners.AbstractEventListener; import com.l2jserver.gameserver.model.quest.Quest; import com.l2jserver.gameserver.model.quest.QuestTimer; import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage; -import com.l2jserver.gameserver.scripting.L2ScriptEngineManager; +import com.l2jserver.gameserver.scripting.ScriptEngineManager; import com.l2jserver.gameserver.util.Util; public class AdminQuest implements IAdminCommandHandler { + private static final Logger LOG = LoggerFactory.getLogger(AdminQuest.class); + private static final String[] ADMIN_COMMANDS = { "admin_quest_reload", @@ -117,14 +122,14 @@ public class AdminQuest implements IAdminCommandHandler } else { - File file = new File(L2ScriptEngineManager.SCRIPT_FOLDER, parts[1]); + File file = new File(ScriptEngineManager.SCRIPT_FOLDER, parts[1]); // Trying to reload by script name. if (!file.exists()) { Quest quest = QuestManager.getInstance().getQuest(parts[1]); if (quest != null) { - file = new File(L2ScriptEngineManager.SCRIPT_FOLDER, quest.getClass().getName().replaceAll("\\.", "/") + ".java"); + file = new File(ScriptEngineManager.SCRIPT_FOLDER, quest.getClass().getName().replaceAll("\\.", "/") + ".java"); } } @@ -133,15 +138,15 @@ public class AdminQuest implements IAdminCommandHandler { try { - L2ScriptEngineManager.getInstance().executeScript(file); + ScriptEngineManager.getInstance().executeScript(file); // This part should be called only when the script is successfully loaded. activeChar.sendMessage("Script Successfully Loaded."); } - catch (ScriptException e) + catch (ScriptException ex) { activeChar.sendMessage("Failed loading: " + parts[1]); - L2ScriptEngineManager.getInstance().reportScriptFileError(file, e); + LOG.error("Failed loading {}!", parts[1], ex); } catch (Exception e) { @@ -292,7 +297,8 @@ public class AdminQuest implements IAdminCommandHandler { for (QuestTimer timer : list) { - timers += "<tr><td colspan=\"4\"><table width=270 border=0 bgcolor=131210><tr><td width=270><font color=\"LEVEL\">" + timer.getName() + ":</font> <font color=00FF00>Active: " + timer.getIsActive() + " Repeatable: " + timer.getIsRepeating() + " Player: " + timer.getPlayer() + " Npc: " + timer.getNpc() + "</font></td></tr></table></td></tr>"; + timers += "<tr><td colspan=\"4\"><table width=270 border=0 bgcolor=131210><tr><td width=270><font color=\"LEVEL\">" + timer.getName() + ":</font> <font color=00FF00>Active: " + timer.getIsActive() + " Repeatable: " + timer.getIsRepeating() + " Player: " + timer.getPlayer() + + " Npc: " + timer.getNpc() + "</font></td></tr></table></td></tr>"; counter++; if (counter > 10) { @@ -305,7 +311,8 @@ public class AdminQuest implements IAdminCommandHandler sb.append("<tr><td colspan=\"4\"><table width=270 border=0 bgcolor=131210><tr><td width=270><font color=\"LEVEL\">ID:</font> <font color=00FF00>" + quest.getId() + "</font></td></tr></table></td></tr>"); sb.append("<tr><td colspan=\"4\"><table width=270 border=0 bgcolor=131210><tr><td width=270><font color=\"LEVEL\">Name:</font> <font color=00FF00>" + quest.getName() + "</font></td></tr></table></td></tr>"); sb.append("<tr><td colspan=\"4\"><table width=270 border=0 bgcolor=131210><tr><td width=270><font color=\"LEVEL\">Descr:</font> <font color=00FF00>" + quest.getDescr() + "</font></td></tr></table></td></tr>"); - sb.append("<tr><td colspan=\"4\"><table width=270 border=0 bgcolor=131210><tr><td width=270><font color=\"LEVEL\">Path:</font> <font color=00FF00>" + quest.getClass().getName().substring(0, quest.getClass().getName().lastIndexOf('.')).replaceAll("\\.", "/") + "</font></td></tr></table></td></tr>"); + sb.append("<tr><td colspan=\"4\"><table width=270 border=0 bgcolor=131210><tr><td width=270><font color=\"LEVEL\">Path:</font> <font color=00FF00>" + quest.getClass().getName().substring(0, quest.getClass().getName().lastIndexOf('.')).replaceAll("\\.", "/") + + "</font></td></tr></table></td></tr>"); sb.append("<tr><td colspan=\"4\"><table width=270 border=0 bgcolor=131210><tr><td width=270><font color=\"LEVEL\">Events:</font> <font color=00FF00>" + events + "</font></td></tr></table></td></tr>"); if (!npcs.isEmpty()) { @@ -324,7 +331,8 @@ public class AdminQuest implements IAdminCommandHandler final NpcHtmlMessage msg = new NpcHtmlMessage(0, 1); msg.setFile(activeChar.getHtmlPrefix(), "data/html/admin/npc-quests.htm"); msg.replace("%quests%", sb.toString()); - msg.replace("%questName%", "<table><tr><td width=\"50\" align=\"left\"><a action=\"bypass -h admin_script_load " + quest.getName() + "\">Reload</a></td> <td width=\"150\" align=\"center\"><a action=\"bypass -h admin_quest_info " + quest.getName() + "\">" + quest.getName() + "</a></td> <td width=\"50\" align=\"right\"><a action=\"bypass -h admin_script_unload " + quest.getName() + "\">Unload</a></tr></td></table>"); + msg.replace("%questName%", "<table><tr><td width=\"50\" align=\"left\"><a action=\"bypass -h admin_script_load " + quest.getName() + "\">Reload</a></td> <td width=\"150\" align=\"center\"><a action=\"bypass -h admin_quest_info " + quest.getName() + "\">" + quest.getName() + + "</a></td> <td width=\"50\" align=\"right\"><a action=\"bypass -h admin_script_unload " + quest.getName() + "\">Unload</a></tr></td></table>"); activeChar.sendPacket(msg); } return true; diff --git a/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java b/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java index a21a05e092e8a006a039dd4d68b64fd654b7fe1a..2beb883fbcc8e64b8430e77a7c6cd7b1bf408cc8 100644 --- a/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java +++ b/dist/game/data/scripts/handlers/admincommandhandlers/AdminReload.java @@ -21,8 +21,6 @@ package handlers.admincommandhandlers; import java.io.File; import java.util.StringTokenizer; -import javax.script.ScriptException; - import com.l2jserver.Config; import com.l2jserver.gameserver.cache.HtmCache; import com.l2jserver.gameserver.data.sql.impl.CrestTable; @@ -44,7 +42,7 @@ import com.l2jserver.gameserver.instancemanager.QuestManager; import com.l2jserver.gameserver.instancemanager.WalkingManager; import com.l2jserver.gameserver.instancemanager.ZoneManager; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; -import com.l2jserver.gameserver.scripting.L2ScriptEngineManager; +import com.l2jserver.gameserver.scripting.ScriptEngineManager; import com.l2jserver.gameserver.util.Util; /** @@ -207,32 +205,16 @@ public class AdminReload implements IAdminCommandHandler } case "effect": { - final File file = new File(L2ScriptEngineManager.SCRIPT_FOLDER, "handlers/EffectMasterHandler.java"); - try - { - L2ScriptEngineManager.getInstance().executeScript(file); - AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Effects."); - } - catch (ScriptException e) - { - L2ScriptEngineManager.getInstance().reportScriptFileError(file, e); - activeChar.sendMessage("There was an error while loading handlers."); - } + final File file = new File(ScriptEngineManager.SCRIPT_FOLDER, "handlers/EffectMasterHandler.java"); + ScriptEngineManager.getInstance().compileScript(file); + AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Effects."); break; } case "handler": { - final File file = new File(L2ScriptEngineManager.SCRIPT_FOLDER, "handlers/MasterHandler.java"); - try - { - L2ScriptEngineManager.getInstance().executeScript(file); - AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Handlers."); - } - catch (ScriptException e) - { - L2ScriptEngineManager.getInstance().reportScriptFileError(file, e); - activeChar.sendMessage("There was an error while loading handlers."); - } + final File file = new File(ScriptEngineManager.SCRIPT_FOLDER, "handlers/MasterHandler.java"); + ScriptEngineManager.getInstance().compileScript(file); + AdminData.getInstance().broadcastMessageToGMs(activeChar.getName() + ": Reloaded Handlers."); break; } case "enchant": diff --git a/dist/game/data/scripts/handlers/telnethandlers/ReloadHandler.java b/dist/game/data/scripts/handlers/telnethandlers/ReloadHandler.java index 7eabc02e4b7934288e1d4591ac1c23fb24596b65..8a370516391c8b26ba3bf6b83be2e32c39fdeed8 100644 --- a/dist/game/data/scripts/handlers/telnethandlers/ReloadHandler.java +++ b/dist/game/data/scripts/handlers/telnethandlers/ReloadHandler.java @@ -23,8 +23,6 @@ import java.io.PrintWriter; import java.net.Socket; import java.util.StringTokenizer; -import javax.script.ScriptException; - import com.l2jserver.gameserver.cache.HtmCache; import com.l2jserver.gameserver.data.sql.impl.TeleportLocationTable; import com.l2jserver.gameserver.data.xml.impl.MultisellData; @@ -38,7 +36,7 @@ import com.l2jserver.gameserver.instancemanager.QuestManager; import com.l2jserver.gameserver.instancemanager.RaidBossSpawnManager; import com.l2jserver.gameserver.instancemanager.ZoneManager; import com.l2jserver.gameserver.model.L2World; -import com.l2jserver.gameserver.scripting.L2ScriptEngineManager; +import com.l2jserver.gameserver.scripting.ScriptEngineManager; /** * @author UnAfraid @@ -120,19 +118,14 @@ public class ReloadHandler implements ITelnetHandler { String questPath = st.hasMoreTokens() ? st.nextToken() : ""; - File file = new File(L2ScriptEngineManager.SCRIPT_FOLDER, questPath); + File file = new File(ScriptEngineManager.SCRIPT_FOLDER, questPath); if (file.isFile()) { try { - L2ScriptEngineManager.getInstance().executeScript(file); + ScriptEngineManager.getInstance().compileScript(file); _print.println(file.getName() + " was successfully loaded!\n"); } - catch (ScriptException e) - { - _print.println("Failed loading: " + questPath); - L2ScriptEngineManager.getInstance().reportScriptFileError(file, e); - } catch (Exception e) { _print.println("Failed loading: " + questPath); diff --git a/dist/game/data/scripts/handlers/usercommandhandlers/ChannelDelete.java b/dist/game/data/scripts/handlers/usercommandhandlers/ChannelDelete.java index 42cf15357b5f11501085c86b9b200456d79adb2b..e45ed0ff80d8548ef108c97cd51d84dd192bd898 100644 --- a/dist/game/data/scripts/handlers/usercommandhandlers/ChannelDelete.java +++ b/dist/game/data/scripts/handlers/usercommandhandlers/ChannelDelete.java @@ -18,11 +18,11 @@ */ package handlers.usercommandhandlers; +import static com.l2jserver.gameserver.network.SystemMessageId.COMMAND_CHANNEL_DISBANDED; + import com.l2jserver.gameserver.handler.IUserCommandHandler; import com.l2jserver.gameserver.model.L2CommandChannel; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; -import com.l2jserver.gameserver.network.SystemMessageId; -import com.l2jserver.gameserver.network.serverpackets.SystemMessage; /** * Channel Delete user command. @@ -49,8 +49,7 @@ public class ChannelDelete implements IUserCommandHandler { L2CommandChannel channel = activeChar.getParty().getCommandChannel(); - SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.COMMAND_CHANNEL_DISBANDED); - channel.broadcastPacket(sm); + channel.broadcastMessage(COMMAND_CHANNEL_DISBANDED); channel.disbandChannel(); return true; diff --git a/dist/game/data/scripts/handlers/voicedcommandhandlers/StatsVCmd.java b/dist/game/data/scripts/handlers/voicedcommandhandlers/StatsVCmd.java index 7ec394139ca6ba2d25c974a9eeff86e0482b377e..20a16f7272a806e7a2ba56cac53c9e152a46405b 100644 --- a/dist/game/data/scripts/handlers/voicedcommandhandlers/StatsVCmd.java +++ b/dist/game/data/scripts/handlers/voicedcommandhandlers/StatsVCmd.java @@ -18,11 +18,13 @@ */ package handlers.voicedcommandhandlers; +import static com.l2jserver.gameserver.network.SystemMessageId.S1_OFFLINE; +import static com.l2jserver.gameserver.network.SystemMessageId.TARGET_IS_NOT_FOUND_IN_THE_GAME; + import com.l2jserver.gameserver.handler.IVoicedCommandHandler; import com.l2jserver.gameserver.model.L2World; import com.l2jserver.gameserver.model.actor.instance.L2PcInstance; import com.l2jserver.gameserver.model.entity.L2Event; -import com.l2jserver.gameserver.network.SystemMessageId; import com.l2jserver.gameserver.network.serverpackets.NpcHtmlMessage; import com.l2jserver.gameserver.network.serverpackets.SystemMessage; import com.l2jserver.util.StringUtil; @@ -49,13 +51,13 @@ public class StatsVCmd implements IVoicedCommandHandler final L2PcInstance pc = L2World.getInstance().getPlayer(params); if ((pc == null)) { - activeChar.sendPacket(SystemMessageId.TARGET_IS_NOT_FOUND_IN_THE_GAME); + activeChar.sendPacket(TARGET_IS_NOT_FOUND_IN_THE_GAME); return false; } if (pc.getClient().isDetached()) { - final SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.S1_OFFLINE); + final SystemMessage sm = SystemMessage.getSystemMessage(S1_OFFLINE); sm.addPcName(pc); activeChar.sendPacket(sm); return false; @@ -67,7 +69,8 @@ public class StatsVCmd implements IVoicedCommandHandler return false; } - final StringBuilder replyMSG = StringUtil.startAppend(300 + (pc.getEventStatus().getKills().size() * 50), "<html><body>" + "<center><font color=\"LEVEL\">[ L2J EVENT ENGINE ]</font></center><br><br>Statistics for player <font color=\"LEVEL\">", pc.getName(), "</font><br>Total kills <font color=\"FF0000\">", String.valueOf(pc.getEventStatus().getKills().size()), "</font><br><br>Detailed list: <br>"); + final StringBuilder replyMSG = StringUtil.startAppend(300 + (pc.getEventStatus().getKills().size() * 50), "<html><body>" + + "<center><font color=\"LEVEL\">[ L2J EVENT ENGINE ]</font></center><br><br>Statistics for player <font color=\"LEVEL\">", pc.getName(), "</font><br>Total kills <font color=\"FF0000\">", String.valueOf(pc.getEventStatus().getKills().size()), "</font><br><br>Detailed list: <br>"); for (L2PcInstance plr : pc.getEventStatus().getKills()) { StringUtil.append(replyMSG, "<font color=\"FF0000\">", plr.getName(), "</font><br>"); diff --git a/dist/game/data/scripts/hellbound/HellboundLoader.java b/dist/game/data/scripts/hellbound/HellboundLoader.java index db0a34ae3680abc81228f4720524ae92193702f9..ccb644627a31e7d5b0da5c6cc4164c3869cbd8a4 100644 --- a/dist/game/data/scripts/hellbound/HellboundLoader.java +++ b/dist/game/data/scripts/hellbound/HellboundLoader.java @@ -18,6 +18,14 @@ */ package hellbound; +import java.util.logging.Logger; + +import com.l2jserver.Config; +import com.l2jserver.gameserver.handler.AdminCommandHandler; +import com.l2jserver.gameserver.handler.IAdminCommandHandler; +import com.l2jserver.gameserver.handler.IVoicedCommandHandler; +import com.l2jserver.gameserver.handler.VoicedCommandHandler; + import handlers.admincommandhandlers.AdminHellbound; import handlers.voicedcommandhandlers.Hellbound; import hellbound.AI.Amaskari; @@ -52,18 +60,9 @@ import hellbound.AI.Zones.TullyWorkshop.TullyWorkshop; import hellbound.Instances.DemonPrinceFloor.DemonPrinceFloor; import hellbound.Instances.RankuFloor.RankuFloor; import hellbound.Instances.UrbanArea.UrbanArea; - -import java.util.logging.Logger; - import quests.Q00130_PathToHellbound.Q00130_PathToHellbound; import quests.Q00133_ThatsBloodyHot.Q00133_ThatsBloodyHot; -import com.l2jserver.Config; -import com.l2jserver.gameserver.handler.AdminCommandHandler; -import com.l2jserver.gameserver.handler.IAdminCommandHandler; -import com.l2jserver.gameserver.handler.IVoicedCommandHandler; -import com.l2jserver.gameserver.handler.VoicedCommandHandler; - /** * Hellbound class-loader. * @author Zoey76 @@ -130,7 +129,7 @@ public final class HellboundLoader { try { - final Object instance = script.newInstance(); + final Object instance = script.getDeclaredConstructor().newInstance(); if (instance instanceof IAdminCommandHandler) { AdminCommandHandler.getInstance().registerHandler((IAdminCommandHandler) instance); diff --git a/dist/game/data/scripts/instances/InstanceLoader.java b/dist/game/data/scripts/instances/InstanceLoader.java index 0a63f79bd3f525280b80b3cae14157bfade6c0d1..48fdc9fb994e33323f018f96463e11e2e1411b27 100644 --- a/dist/game/data/scripts/instances/InstanceLoader.java +++ b/dist/game/data/scripts/instances/InstanceLoader.java @@ -101,7 +101,7 @@ public final class InstanceLoader { try { - script.newInstance(); + script.getDeclaredConstructor().newInstance(); } catch (Exception e) { diff --git a/dist/game/data/scripts/quests/QuestMasterHandler.java b/dist/game/data/scripts/quests/QuestMasterHandler.java index d360dcff6c2ec0cee0be492a85f5772688b78b37..46a903abc7d212d3d9f2ac0bbb02f15f9859f46e 100644 --- a/dist/game/data/scripts/quests/QuestMasterHandler.java +++ b/dist/game/data/scripts/quests/QuestMasterHandler.java @@ -1037,7 +1037,7 @@ public class QuestMasterHandler { try { - quest.newInstance(); + quest.getDeclaredConstructor().newInstance(); } catch (Exception e) { diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 9d7ffea662cf6cccbe1c1ce55c4fd1886fabca60..0d4a9516871afd710a9d84d89e31ba77745607bd 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 5cbe776b315a65e096a7e740ce9b65068c5ed177..a95009c3b9edbe318f3510f6dd72e37ef7966af9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-bin.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 4453ccea33d960069d9137ee65f6b21fc65e7e92..cccdd3d517fc5249beaefa600691cf150f2fa3e6 100755 --- a/gradlew +++ b/gradlew @@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -155,7 +155,7 @@ if $cygwin ; then fi # Escape application args -save ( ) { +save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " }