Jump to content
  • 0

Automatic verify and ban unauthorized skills - L2JFrozen


Question

Posted

Hello, i need some help if anyone know:

 

I have a multiskill server (L2JFrozen rev) and I've recently had some hacker enter my server and he was able to learn monster passive skills/active skills and some skills that aren't in any character skill tree, like valakas buff, super haste, etc.

 

Since it happened i activated the AllowedSkills function (plus also activating it on the Protected folder CheckSkillsOnEnter), and added on the list only the character skills on the list (1-500 and 1000-1500), however, the function doesn't seem to be working.

 

Is there a way a can put a verification on L2PcInstance or some other java instance to automatically ban player/delete skills between 3000-7000 or something like that? My source code already has something like this (i'll be posting below), but it doesn't seem to be working (i tested with another character and nothing happened to it).

 

	/**
	 * check player skills and remove unlegit ones (excludes hero, noblesse and cursed weapon skills).
	 */
	public void checkAllowedSkills()
	{
		boolean foundskill = false;
		if (!isGM())
		{
			Collection<L2SkillLearn> skillTree = SkillTreeTable.getInstance().getAllowedSkills(getClassId());
			// loop through all skills of player
			for (final L2Skill skill : getAllSkills())
			{
				final int skillid = skill.getId();
				// int skilllevel = skill.getLevel();
				
				foundskill = false;
				// loop through all skills in players skilltree
				for (final L2SkillLearn temp : skillTree)
				{
					// if the skill was found and the level is possible to obtain for his class everything is ok
					if (temp.getId() == skillid)
					{
						foundskill = true;
					}
				}
				
				// exclude noble skills
				if (isNoble() && skillid >= 325 && skillid <= 397)
				{
					foundskill = true;
				}
				
				if (isNoble() && skillid >= 1323 && skillid <= 1327)
				{
					foundskill = true;
				}
				
				// exclude hero skills
				if (isHero() && skillid >= 395 && skillid <= 396)
				{
					foundskill = true;
				}
				
				if (isHero() && skillid >= 1374 && skillid <= 1376)
				{
					foundskill = true;
				}
				
				// exclude cursed weapon skills
				if (isCursedWeaponEquiped() && skillid == CursedWeaponsManager.getInstance().getCursedWeapon(_cursedWeaponEquipedId).getSkillId())
				{
					foundskill = true;
				}
				
				// exclude clan skills
				if (getClan() != null && skillid >= 370 && skillid <= 391)
				{
					foundskill = true;
				}
				
				// exclude seal of ruler / build siege hq
				if (getClan() != null && (skillid == 246 || skillid == 247))
					if (getClan().getLeaderId() == getObjectId())
					{
						foundskill = true;
					}
				
				// exclude fishing skills and common skills + dwarfen craft
				if (skillid >= 1312 && skillid <= 1322)
				{
					foundskill = true;
				}
				
				if (skillid >= 1368 && skillid <= 1373)
				{
					foundskill = true;
				}
				
				// exclude sa / enchant bonus / penality etc. skills
				if (skillid >= 3000 && skillid < 7000)
				{
					foundskill = true;
				}
				
				// exclude Skills from AllowedSkills in options.properties
				if (Config.ALLOWED_SKILLS_LIST.contains(skillid))
				{
					foundskill = true;
				}
				
				// exclude Donator character
				if (isDonator())
				{
					foundskill = true;
				}
				
				// exclude Aio character
				if (isAio())
				{
					foundskill = true;
				}
				
				// remove skill and do a lil LOGGER message
				if (!foundskill)
				{
					removeSkill(skill);
					
					if (Config.DEBUG)
					{
						// sendMessage("Skill " + skill.getName() + " removed and gm informed!");
						LOGGER.warn("Character " + getName() + " of Account " + getAccountName() + " got skill " + skill.getName() + ".. Removed!"/* + IllegalPlayerAction.PUNISH_KICK */);
						
					}
				}
			}
			
			// Update skill list
			sendSkillList();
			
			skillTree = null;
		}
	}
	

 

 

Recommended Posts

  • 0
Posted
6 minutes ago, dextroy said:

I understand, but i'm not sure if i can cover every single possibility of "how he did it" as there were no specific logs generated. 

 

The normal learn skill process on my server calls for the database skill tree on class masters, and the db skill tree only displays skills under 1500, which are the regular skill classes.

 

image.png.883504599d4d172595c9508cc89d5a85.png

 

If he used a class master to learn the skill, the new line i added on my previous post should already block them from learning. But if he did some other way, i can't figure out 'cause there were no logs.

 

And i think i can assume it's not addSkill command 'cause only GM/ADM access level can call for those. And i'm assuming it's nothing of the sort, because if it was, he could've cause more damage than simply learning monster/items skills.

Did you carefully read what I wrote?
ADM / GM has nothing to do with it, I make it clear that you think narrowly.

You are trying to guess how he does it, although you have an understanding of what he does.

 

Any skill that a character gains goes through the skill addition method. You can also track the hacker through it.   

  • 0
Posted
16 hours ago, dextroy said:

Hello, i need some help if anyone know:

 

I have a multiskill server (L2JFrozen rev) and I've recently had some hacker enter my server and he was able to learn monster passive skills/active skills and some skills that aren't in any character skill tree, like valakas buff, super haste, etc.

 

Since it happened i activated the AllowedSkills function (plus also activating it on the Protected folder CheckSkillsOnEnter), and added on the list only the character skills on the list (1-500 and 1000-1500), however, the function doesn't seem to be working.

 

Is there a way a can put a verification on L2PcInstance or some other java instance to automatically ban player/delete skills between 3000-7000 or something like that? My source code already has something like this (i'll be posting below), but it doesn't seem to be working (i tested with another character and nothing happened to it).

 

	/**
	 * check player skills and remove unlegit ones (excludes hero, noblesse and cursed weapon skills).
	 */
	public void checkAllowedSkills()
	{
		boolean foundskill = false;
		if (!isGM())
		{
			Collection<L2SkillLearn> skillTree = SkillTreeTable.getInstance().getAllowedSkills(getClassId());
			// loop through all skills of player
			for (final L2Skill skill : getAllSkills())
			{
				final int skillid = skill.getId();
				// int skilllevel = skill.getLevel();
				
				foundskill = false;
				// loop through all skills in players skilltree
				for (final L2SkillLearn temp : skillTree)
				{
					// if the skill was found and the level is possible to obtain for his class everything is ok
					if (temp.getId() == skillid)
					{
						foundskill = true;
					}
				}
				
				// exclude noble skills
				if (isNoble() && skillid >= 325 && skillid <= 397)
				{
					foundskill = true;
				}
				
				if (isNoble() && skillid >= 1323 && skillid <= 1327)
				{
					foundskill = true;
				}
				
				// exclude hero skills
				if (isHero() && skillid >= 395 && skillid <= 396)
				{
					foundskill = true;
				}
				
				if (isHero() && skillid >= 1374 && skillid <= 1376)
				{
					foundskill = true;
				}
				
				// exclude cursed weapon skills
				if (isCursedWeaponEquiped() && skillid == CursedWeaponsManager.getInstance().getCursedWeapon(_cursedWeaponEquipedId).getSkillId())
				{
					foundskill = true;
				}
				
				// exclude clan skills
				if (getClan() != null && skillid >= 370 && skillid <= 391)
				{
					foundskill = true;
				}
				
				// exclude seal of ruler / build siege hq
				if (getClan() != null && (skillid == 246 || skillid == 247))
					if (getClan().getLeaderId() == getObjectId())
					{
						foundskill = true;
					}
				
				// exclude fishing skills and common skills + dwarfen craft
				if (skillid >= 1312 && skillid <= 1322)
				{
					foundskill = true;
				}
				
				if (skillid >= 1368 && skillid <= 1373)
				{
					foundskill = true;
				}
				
				// exclude sa / enchant bonus / penality etc. skills
				if (skillid >= 3000 && skillid < 7000)
				{
					foundskill = true;
				}
				
				// exclude Skills from AllowedSkills in options.properties
				if (Config.ALLOWED_SKILLS_LIST.contains(skillid))
				{
					foundskill = true;
				}
				
				// exclude Donator character
				if (isDonator())
				{
					foundskill = true;
				}
				
				// exclude Aio character
				if (isAio())
				{
					foundskill = true;
				}
				
				// remove skill and do a lil LOGGER message
				if (!foundskill)
				{
					removeSkill(skill);
					
					if (Config.DEBUG)
					{
						// sendMessage("Skill " + skill.getName() + " removed and gm informed!");
						LOGGER.warn("Character " + getName() + " of Account " + getAccountName() + " got skill " + skill.getName() + ".. Removed!"/* + IllegalPlayerAction.PUNISH_KICK */);
						
					}
				}
			}
			
			// Update skill list
			sendSkillList();
			
			skillTree = null;
		}
	}
	

 

 

If I remember correctly, this bug used to work on old Interlude versions using PHX. Where you request to learn an skill, but in reality you send other skill through phx. Put there a check to verify if that skill that is beeing added belongs to that class. If not, simply ignore. If you want to use that method you specified, use it more times on teleport, certain actions, enter/leave zone... Although its not an fix but rather an shortcut to dealing with your problem.

  • 0
Posted
16 minutes ago, Psygrammator said:

Did you carefully read what I wrote?
ADM / GM has nothing to do with it, I make it clear that you think narrowly.

You are trying to guess how he does it, although you have an understanding of what he does.

 

Any skill that a character gains goes through the skill addition method. You can also track the hacker through it.   

Ok, but what should i be looking into then? What java file? I'm trying to understand within my knowledge, which is not that advanced, so i ask for some patience. I did what i said about skills > 1500 on RequestAquireSkill.java. Is that enough?

 

7 minutes ago, HyperBlown said:

If I remember correctly, this bug used to work on old Interlude versions using PHX. Where you request to learn an skill, but in reality you send other skill through phx. Put there a check to verify if that skill that is beeing added belongs to that class. If not, simply ignore. If you want to use that method you specified, use it more times on teleport, certain actions, enter/leave zone... Although its not an fix but rather an shortcut to dealing with your problem.

And is there a way i can verify/block what that phx sends? I'm not experienced with hack systems, so i don't know exactly how it's done. Where would i put that verification, considering the server is multiskill and it should allow all classes skills (skills under 1500)? And i don't know exactly where to put the method i asked for, that's why i'm here, i don't know which java file or how to code as i'm not an experienced developer/programmer.

  • 0
Posted (edited)
9 minutes ago, dextroy said:

Ok, but what should i be looking into then? What java file? I'm trying to understand within my knowledge, which is not that advanced, so i ask for some patience. I did what i said about skills > 1500 on RequestAquireSkill.java. Is that enough?

 

And is there a way i can verify/block what that phx sends? I'm not experienced with hack systems, so i don't know exactly how it's done. Where would i put that verification, considering the server is multiskill and it should allow all classes skills (skills under 1500)? And i don't know exactly where to put the method i asked for, that's why i'm here, i don't know which java file or how to code as i'm not an experienced developer/programmer.

There can be many reasons for how he does this, if l2phx, then protection is needed that will encrypt the packets so that the hacker cannot send them modified. (What l2phx is using is guesswork from the user above)
 

If this is a bug in the emulator, no amount of protection will help you until you find the cause. To find the reason, I gave you a detailed answer above how to track the process, how a hacker does it, and through which class.

Edited by Psygrammator
  • 0
Posted
6 minutes ago, Psygrammator said:

There can be many reasons for how he does this, if l2phx, then protection is needed that will encrypt the packets so that the hacker cannot send them modified. (What l2phx is using is guesswork from the user above)
 

If this is a bug in the emulator, no amount of protection will help you until you find the cause. To find the reason, I gave you a detailed answer above how to track the process, how a hacker does it, and through which class.

 

I appreciate that, but being honest i still couldn't understand what my next steps should be. Tracing the code could literally be looking into every single .java file, and as i said, i'm not a programmer/developer.

 

That's why i've been asking as least for a countermeasure, if someone is sending illegal packets that i can't track (i don't know how or it'd require too much programming knowlege), wouldn't a block on it's effects at least partially solve the issue?

 

I still don't know where to look at. If you could pinpoint something like: "You can add some code lines on WhateverFile.java and it will verify the skills" and somewhat of what the code would look like, then i can attempt a solution here.

 

But i'm not at advanced knowledge with java. Tracing everything, check packets, hacking, those are not things i'm experenced at, so i just honestly don't know where to start looking. With the information i'm receiving.

 

Zake told me to look on RequestAquireSkill.java and i was able to put an extra code line there. But i don't know if that's enough or where else i could put an extra verification.

  • 0
Posted
1 hour ago, HyperBlown said:

If I remember correctly, this bug used to work on old Interlude versions using PHX. Where you request to learn an skill, but in reality you send other skill through phx. Put there a check to verify if that skill that is beeing added belongs to that class. If not, simply ignore. If you want to use that method you specified, use it more times on teleport, certain actions, enter/leave zone... Although its not an fix but rather an shortcut to dealing with your problem.

ya i remember old times, when i learned some skill after i took from phx packet, changed some numbers and learned new different skill 

  • Haha 1
  • 0
Posted (edited)
1 hour ago, dextroy said:

 

I appreciate that, but being honest i still couldn't understand what my next steps should be. Tracing the code could literally be looking into every single .java file, and as i said, i'm not a programmer/developer.

 

That's why i've been asking as least for a countermeasure, if someone is sending illegal packets that i can't track (i don't know how or it'd require too much programming knowlege), wouldn't a block on it's effects at least partially solve the issue?

 

I still don't know where to look at. If you could pinpoint something like: "You can add some code lines on WhateverFile.java and it will verify the skills" and somewhat of what the code would look like, then i can attempt a solution here.

 

But i'm not at advanced knowledge with java. Tracing everything, check packets, hacking, those are not things i'm experenced at, so i just honestly don't know where to start looking. With the information i'm receiving.

 

Zake told me to look on RequestAquireSkill.java and i was able to put an extra code line there. But i don't know if that's enough or where else i could put an extra verification.

As I mentioned, You need to verify if the requested skill to learn exists in the List of learnable skills from the current class the character is in.  

Something like this would do. 
(taking in consideration that this here below has indeed the "allowed" ids per class)
 

SkillTreeTable.getInstance().getAllowedSkills(getClassId())

Then on your learn skill method or even on the RequestAquireSkill you could put something like this.
 

if(SkillTreeTable.getInstance().getAllowedSkills(activeChar.getClassId()).stream().noneMatch(e->e.getId == _skillId))
    return;

Again, if this method does what it should do by its name, this if will check if the requested skillId exists on the allowed skill list for the current class of the character. If the requested Id doesnt exist, it will simply ignore.
But this is a very simple test, ideally you would want to check on level too since some classes can have the same skill but are capped on different levels. 

 

Edited by HyperBlown
  • 0
Posted
43 minutes ago, HyperBlown said:

As I mentioned, You need to verify if the requested skill to learn exists in the List of learnable skills from the current class the character is in.  

Something like this would do. 
(taking in consideration that this here below has indeed the "allowed" ids per class)
 

SkillTreeTable.getInstance().getAllowedSkills(getClassId())

Then on your learn skill method or even on the RequestAquireSkill you could put something like this.
 

if(SkillTreeTable.getInstance().getAllowedSkills(activeChar.getClassId()).stream().noneMatch(e->e.getId == _skillId))
    return;

 

Again, if this method does what it should do by its name, this if will check if the requested skillId exists on the allowed skill list for the current class of the character. If the requested Id doesnt exist, it will simply ignore.
But this is a very simple test, ideally you would want to check on level too since some classes can have the same skill but are capped on different levels. 

 

In order for me to understand, isn't the "Allowed Skills" list the skill tree sql table? If so, as i mentioned the skill tree only marks skills up to 1430. I don't get how they'd see any different. Here, i found the get allowed skills on the following java files:

image.png.86027caeb113e9bde8f2fecdc972eeef.png

 

Would it be on the L2PcInstance then? Here's the bit marked:

	/**
	 * check player skills and remove unlegit ones (excludes hero, noblesse and cursed weapon skills).
	 */
	public void checkAllowedSkills()
	{
		boolean foundskill = false;
		if (!isGM())
		{
			Collection<L2SkillLearn> skillTree = SkillTreeTable.getInstance().getAllowedSkills(getClassId());
			// loop through all skills of player
			for (final L2Skill skill : getAllSkills())
			{
				final int skillid = skill.getId();
				// int skilllevel = skill.getLevel();
				
				foundskill = false;
				// loop through all skills in players skilltree
				for (final L2SkillLearn temp : skillTree)
				{
					// if the skill was found and the level is possible to obtain for his class everything is ok
					if (temp.getId() == skillid)
					{
						foundskill = true;
					}
				}
				
				// exclude noble skills
				if (isNoble() && skillid >= 325 && skillid <= 397)
				{
					foundskill = true;
				}
				
				if (isNoble() && skillid >= 1323 && skillid <= 1327)
				{
					foundskill = true;
				}
				
				// exclude hero skills
				if (isHero() && skillid >= 395 && skillid <= 396)
				{
					foundskill = true;
				}
				
				if (isHero() && skillid >= 1374 && skillid <= 1376)
				{
					foundskill = true;
				}
				
				// exclude cursed weapon skills
				if (isCursedWeaponEquiped() && skillid == CursedWeaponsManager.getInstance().getCursedWeapon(_cursedWeaponEquipedId).getSkillId())
				{
					foundskill = true;
				}
				
				// exclude clan skills
				if (getClan() != null && skillid >= 370 && skillid <= 391)
				{
					foundskill = true;
				}
				
				// exclude seal of ruler / build siege hq
				if (getClan() != null && (skillid == 246 || skillid == 247))
					if (getClan().getLeaderId() == getObjectId())
					{
						foundskill = true;
					}
				
				// exclude fishing skills and common skills + dwarfen craft
				if (skillid >= 1312 && skillid <= 1322)
				{
					foundskill = true;
				}
				
				if (skillid >= 1368 && skillid <= 1373)
				{
					foundskill = true;
				}
				
				// exclude sa / enchant bonus / penality etc. skills
				if (skillid >= 3000 && skillid < 7000)
				{
					removeSkill(skill);
					LOGGER.warn("Character " + getName() + " of Account " + getAccountName() + " got skill " + skill.getName() + ".. Removed!"/* + IllegalPlayerAction.PUNISH_KICK */);
					foundskill = true;
				}
				
				// exclude Skills from AllowedSkills in options.properties
				if (Config.ALLOWED_SKILLS_LIST.contains(skillid))
				{
					foundskill = true;
				}
				
				// exclude Donator character
				if (isDonator())
				{
					foundskill = true;
				}
				
				// exclude Aio character
				if (isAio())
				{
					foundskill = true;
				}
				
				// remove skill and do a lil LOGGER message
				if (!foundskill)
				{
					removeSkill(skill);
					
					if (Config.DEBUG)
					{
						// sendMessage("Skill " + skill.getName() + " removed and gm informed!");
						LOGGER.warn("Character " + getName() + " of Account " + getAccountName() + " got skill " + skill.getName() + ".. Removed!"/* + IllegalPlayerAction.PUNISH_KICK */);
						
					}
				}
			}
			
			// Update skill list
			sendSkillList();
			
			skillTree = null;
		}
	}

 

How would i insert your code there? I tried but got some errors, so, i'm sending the source code and trying to understand the code's logic.

image.png.860fb30fe6ced257da045dd5e5772c2f.png

  • 0
Posted
6 minutes ago, dextroy said:

In order for me to understand, isn't the "Allowed Skills" list the skill tree sql table? If so, as i mentioned the skill tree only marks skills up to 1430. I don't get how they'd see any different. Here, i found the get allowed skills on the following java files:

image.png.86027caeb113e9bde8f2fecdc972eeef.png

 

Would it be on the L2PcInstance then? Here's the bit marked:

	/**
	 * check player skills and remove unlegit ones (excludes hero, noblesse and cursed weapon skills).
	 */
	public void checkAllowedSkills()
	{
		boolean foundskill = false;
		if (!isGM())
		{
			Collection<L2SkillLearn> skillTree = SkillTreeTable.getInstance().getAllowedSkills(getClassId());
			// loop through all skills of player
			for (final L2Skill skill : getAllSkills())
			{
				final int skillid = skill.getId();
				// int skilllevel = skill.getLevel();
				
				foundskill = false;
				// loop through all skills in players skilltree
				for (final L2SkillLearn temp : skillTree)
				{
					// if the skill was found and the level is possible to obtain for his class everything is ok
					if (temp.getId() == skillid)
					{
						foundskill = true;
					}
				}
				
				// exclude noble skills
				if (isNoble() && skillid >= 325 && skillid <= 397)
				{
					foundskill = true;
				}
				
				if (isNoble() && skillid >= 1323 && skillid <= 1327)
				{
					foundskill = true;
				}
				
				// exclude hero skills
				if (isHero() && skillid >= 395 && skillid <= 396)
				{
					foundskill = true;
				}
				
				if (isHero() && skillid >= 1374 && skillid <= 1376)
				{
					foundskill = true;
				}
				
				// exclude cursed weapon skills
				if (isCursedWeaponEquiped() && skillid == CursedWeaponsManager.getInstance().getCursedWeapon(_cursedWeaponEquipedId).getSkillId())
				{
					foundskill = true;
				}
				
				// exclude clan skills
				if (getClan() != null && skillid >= 370 && skillid <= 391)
				{
					foundskill = true;
				}
				
				// exclude seal of ruler / build siege hq
				if (getClan() != null && (skillid == 246 || skillid == 247))
					if (getClan().getLeaderId() == getObjectId())
					{
						foundskill = true;
					}
				
				// exclude fishing skills and common skills + dwarfen craft
				if (skillid >= 1312 && skillid <= 1322)
				{
					foundskill = true;
				}
				
				if (skillid >= 1368 && skillid <= 1373)
				{
					foundskill = true;
				}
				
				// exclude sa / enchant bonus / penality etc. skills
				if (skillid >= 3000 && skillid < 7000)
				{
					removeSkill(skill);
					LOGGER.warn("Character " + getName() + " of Account " + getAccountName() + " got skill " + skill.getName() + ".. Removed!"/* + IllegalPlayerAction.PUNISH_KICK */);
					foundskill = true;
				}
				
				// exclude Skills from AllowedSkills in options.properties
				if (Config.ALLOWED_SKILLS_LIST.contains(skillid))
				{
					foundskill = true;
				}
				
				// exclude Donator character
				if (isDonator())
				{
					foundskill = true;
				}
				
				// exclude Aio character
				if (isAio())
				{
					foundskill = true;
				}
				
				// remove skill and do a lil LOGGER message
				if (!foundskill)
				{
					removeSkill(skill);
					
					if (Config.DEBUG)
					{
						// sendMessage("Skill " + skill.getName() + " removed and gm informed!");
						LOGGER.warn("Character " + getName() + " of Account " + getAccountName() + " got skill " + skill.getName() + ".. Removed!"/* + IllegalPlayerAction.PUNISH_KICK */);
						
					}
				}
			}
			
			// Update skill list
			sendSkillList();
			
			skillTree = null;
		}
	}

 

How would i insert your code there? I tried but got some errors, so, i'm sending the source code and trying to understand the code's logic.

image.png.860fb30fe6ced257da045dd5e5772c2f.png

checkAllowedSkills is a method that runs when logging on the character. So after logging in, it will be ignored and people can do their bug. Thats why I said to put the verification on the place where u add the skill to the character.

  • 0
Posted
54 minutes ago, HyperBlown said:

checkAllowedSkills is a method that runs when logging on the character. So after logging in, it will be ignored and people can do their bug. Thats why I said to put the verification on the place where u add the skill to the character.

 

Ok, so the RequestAquireSkill.java. I'll send below what i did and the full code aswell:

image.png.f30b093e40b620240ca6cf0cc3a60a50.png

 

The first line is the 'If' you've suggested, but as you can see, there's an incompatibility with that "Lambda expression". What can i replace it with?

 

The second if is the skill_id verification i implemented, and it appears to be working on skill masters (i tested with < 1500 and it didn't allow me to learn the skill)

 

 

Here's the full code:

/*
 * L2jFrozen Project - www.l2jfrozen.com 
 * 
 * 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.l2jfrozen.gameserver.network.clientpackets;

import org.apache.log4j.Logger;

import com.l2jfrozen.Config;
import com.l2jfrozen.gameserver.datatables.SkillTable;
import com.l2jfrozen.gameserver.datatables.sql.SkillSpellbookTable;
import com.l2jfrozen.gameserver.datatables.sql.SkillTreeTable;
import com.l2jfrozen.gameserver.model.L2PledgeSkillLearn;
import com.l2jfrozen.gameserver.model.L2ShortCut;
import com.l2jfrozen.gameserver.model.L2Skill;
import com.l2jfrozen.gameserver.model.L2SkillLearn;
import com.l2jfrozen.gameserver.model.actor.instance.L2FishermanInstance;
import com.l2jfrozen.gameserver.model.actor.instance.L2FolkInstance;
import com.l2jfrozen.gameserver.model.actor.instance.L2ItemInstance;
import com.l2jfrozen.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jfrozen.gameserver.model.actor.instance.L2PcInstance;
import com.l2jfrozen.gameserver.model.actor.instance.L2VillageMasterInstance;
import com.l2jfrozen.gameserver.network.SystemMessageId;
import com.l2jfrozen.gameserver.network.serverpackets.ExStorageMaxCount;
import com.l2jfrozen.gameserver.network.serverpackets.PledgeSkillList;
import com.l2jfrozen.gameserver.network.serverpackets.ShortCutRegister;
import com.l2jfrozen.gameserver.network.serverpackets.StatusUpdate;
import com.l2jfrozen.gameserver.network.serverpackets.SystemMessage;
import com.l2jfrozen.gameserver.util.IllegalPlayerAction;
import com.l2jfrozen.gameserver.util.Util;

public class RequestAquireSkill extends L2GameClientPacket
{
	private static Logger LOGGER = Logger.getLogger(RequestAquireSkill.class);
	
	private int _id;
	
	private int _level;
	
	private int _skillType;
	
	@Override
	protected void readImpl()
	{
		_id = readD();
		_level = readD();
		_skillType = readD();
	}
	
	@Override
	protected void runImpl()
	{
		
		final L2PcInstance player = getClient().getActiveChar();
		
		if (player == null)
			return;
		
		final L2FolkInstance trainer = player.getLastFolkNPC();
		
		if (trainer == null)
			return;
		
		final int npcid = trainer.getNpcId();
		
		if (!player.isInsideRadius(trainer, L2NpcInstance.INTERACTION_DISTANCE, false, false) && !player.isGM())
			return;
		
		if (!Config.ALT_GAME_SKILL_LEARN)
		{
			player.setSkillLearningClassId(player.getClassId());
		}
		
		if (player.getSkillLevel(_id) >= _level)
			// already knows the skill with this level
			return;
		
		if(SkillTreeTable.getInstance().getAllowedSkills(player.getClassId()).stream().noneMatch(e->e.getId == _skillId))
			return;
		
		// test block sills 1500+
		if ((_id) > 1500)
		{
			player.sendMessage("You are trying to learn an illegal skill");
			Util.handleIllegalPlayerAction(player, "Player " + player.getName() + " tried to learn skill that he can't!!!", IllegalPlayerAction.PUNISH_KICK);
			// illegal skill
			return;
		}
		
		final L2Skill skill = SkillTable.getInstance().getInfo(_id, _level);
		
		int counts = 0;
		int _requiredSp = 10000000;
		
		if (_skillType == 0)
		{
			
			final L2SkillLearn[] skills = SkillTreeTable.getInstance().getAvailableSkills(player, player.getSkillLearningClassId());
			
			for (final L2SkillLearn s : skills)
			{
				final L2Skill sk = SkillTable.getInstance().getInfo(s.getId(), s.getLevel());
				if (sk == null || sk != skill || !sk.getCanLearn(player.getSkillLearningClassId()) || !sk.canTeachBy(npcid))
				{
					continue;
				}
				counts++;
				_requiredSp = SkillTreeTable.getInstance().getSkillCost(player, skill);
			}
			
			if (counts == 0 && !Config.ALT_GAME_SKILL_LEARN)
			{
				player.sendMessage("You are trying to learn skill that u can't..");
				Util.handleIllegalPlayerAction(player, "Player " + player.getName() + " tried to learn skill that he can't!!!", IllegalPlayerAction.PUNISH_KICK);
				return;
			}
			
			if (player.getSp() >= _requiredSp)
			{
				int spbId = -1;
				// divine inspiration require book for each level
				if (Config.DIVINE_SP_BOOK_NEEDED && skill.getId() == L2Skill.SKILL_DIVINE_INSPIRATION)
				{
					spbId = SkillSpellbookTable.getInstance().getBookForSkill(skill, _level);
				}
				else if (Config.SP_BOOK_NEEDED && skill.getLevel() == 1)
				{
					spbId = SkillSpellbookTable.getInstance().getBookForSkill(skill);
				}
				
				// spellbook required
				if (spbId > -1)
				{
					final L2ItemInstance spb = player.getInventory().getItemByItemId(spbId);
					
					if (spb == null)
					{
						// Haven't spellbook
						player.sendPacket(new SystemMessage(SystemMessageId.ITEM_MISSING_TO_LEARN_SKILL));
						return;
					}
					
					// ok
					player.destroyItem("Consume", spb, trainer, true);
				}
			}
			else
			{
				final SystemMessage sm = new SystemMessage(SystemMessageId.NOT_ENOUGH_SP_TO_LEARN_SKILL);
				player.sendPacket(sm);
				
				return;
			}
		}
		else if (_skillType == 1)
		{
			int costid = 0;
			int costcount = 0;
			// Skill Learn bug Fix
			final L2SkillLearn[] skillsc = SkillTreeTable.getInstance().getAvailableSkills(player);
			
			for (final L2SkillLearn s : skillsc)
			{
				final L2Skill sk = SkillTable.getInstance().getInfo(s.getId(), s.getLevel());
				
				if (sk == null || sk != skill)
				{
					continue;
				}
				
				counts++;
				costid = s.getIdCost();
				costcount = s.getCostCount();
				_requiredSp = s.getSpCost();
			}
			
			if (counts == 0)
			{
				player.sendMessage("You are trying to learn skill that u can't..");
				Util.handleIllegalPlayerAction(player, "Player " + player.getName() + " tried to learn skill that he can't!!!", IllegalPlayerAction.PUNISH_KICK);
				return;
			}
			
			if (player.getSp() >= _requiredSp)
			{
				if (!player.destroyItemByItemId("Consume", costid, costcount, trainer, false))
				{
					// Haven't spellbook
					player.sendPacket(new SystemMessage(SystemMessageId.ITEM_MISSING_TO_LEARN_SKILL));
					return;
				}
				
				final SystemMessage sm = new SystemMessage(SystemMessageId.DISSAPEARED_ITEM);
				sm.addNumber(costcount);
				sm.addItemName(costid);
				sendPacket(sm);
			}
			else
			{
				final SystemMessage sm = new SystemMessage(SystemMessageId.NOT_ENOUGH_SP_TO_LEARN_SKILL);
				player.sendPacket(sm);
				return;
			}
		}
		else if (_skillType == 2) // pledgeskills TODO: Find appropriate system messages.
		{
			if (!player.isClanLeader())
			{
				// TODO: Find and add system msg
				player.sendMessage("This feature is available only for the clan leader");
				return;
			}
			
			int itemId = 0;
			int repCost = 100000000;
			// Skill Learn bug Fix
			final L2PledgeSkillLearn[] skills = SkillTreeTable.getInstance().getAvailablePledgeSkills(player);
			
			for (final L2PledgeSkillLearn s : skills)
			{
				final L2Skill sk = SkillTable.getInstance().getInfo(s.getId(), s.getLevel());
				
				if (sk == null || sk != skill)
				{
					continue;
				}
				
				counts++;
				itemId = s.getItemId();
				repCost = s.getRepCost();
			}
			
			if (counts == 0)
			{
				player.sendMessage("You are trying to learn skill that u can't..");
				Util.handleIllegalPlayerAction(player, "Player " + player.getName() + " tried to learn skill that he can't!!!", IllegalPlayerAction.PUNISH_KICK);
				return;
			}
			
			if (player.getClan().getReputationScore() >= repCost)
			{
				if (Config.LIFE_CRYSTAL_NEEDED)
				{
					if (!player.destroyItemByItemId("Consume", itemId, 1, trainer, false))
					{
						// Haven't spellbook
						player.sendPacket(new SystemMessage(SystemMessageId.ITEM_MISSING_TO_LEARN_SKILL));
						return;
					}
					
					final SystemMessage sm = new SystemMessage(SystemMessageId.DISSAPEARED_ITEM);
					sm.addItemName(itemId);
					sm.addNumber(1);
					sendPacket(sm);
				}
			}
			else
			{
				final SystemMessage sm = new SystemMessage(SystemMessageId.ACQUIRE_SKILL_FAILED_BAD_CLAN_REP_SCORE);
				player.sendPacket(sm);
				return;
			}
			player.getClan().setReputationScore(player.getClan().getReputationScore() - repCost, true);
			player.getClan().addNewSkill(skill);
			
			if (Config.DEBUG)
			{
				LOGGER.debug("Learned pledge skill " + _id + " for " + _requiredSp + " SP.");
			}
			
			final SystemMessage cr = new SystemMessage(SystemMessageId.S1_DEDUCTED_FROM_CLAN_REP);
			cr.addNumber(repCost);
			player.sendPacket(cr);
			final SystemMessage sm = new SystemMessage(SystemMessageId.CLAN_SKILL_S1_ADDED);
			sm.addSkillName(_id);
			player.sendPacket(sm);
			
			player.getClan().broadcastToOnlineMembers(new PledgeSkillList(player.getClan()));
			
			for (final L2PcInstance member : player.getClan().getOnlineMembers(""))
			{
				member.sendSkillList();
			}
			
			if (trainer instanceof L2VillageMasterInstance)
			{
				((L2VillageMasterInstance) trainer).showPledgeSkillList(player);
			}
			
			return;
		}
		
		else
		{
			LOGGER.warn("Recived Wrong Packet Data in Aquired Skill - unk1:" + _skillType);
			return;
		}
		
		player.addSkill(skill, true);
		
		if (Config.DEBUG)
		{
			LOGGER.debug("Learned skill " + _id + " for " + _requiredSp + " SP.");
		}
		
		player.setSp(player.getSp() - _requiredSp);
		
		final StatusUpdate su = new StatusUpdate(player.getObjectId());
		su.addAttribute(StatusUpdate.SP, player.getSp());
		player.sendPacket(su);
		
		final SystemMessage sp = new SystemMessage(SystemMessageId.SP_DECREASED_S1);
		sp.addNumber(_requiredSp);
		sendPacket(sp);
		
		final SystemMessage sm = new SystemMessage(SystemMessageId.LEARNED_SKILL_S1);
		sm.addSkillName(_id);
		player.sendPacket(sm);
		
		// update all the shortcuts to this skill
		if (_level > 1)
		{
			final L2ShortCut[] allShortCuts = player.getAllShortCuts();
			
			for (final L2ShortCut sc : allShortCuts)
			{
				if (sc.getId() == _id && sc.getType() == L2ShortCut.TYPE_SKILL)
				{
					final L2ShortCut newsc = new L2ShortCut(sc.getSlot(), sc.getPage(), sc.getType(), sc.getId(), _level, 1);
					player.sendPacket(new ShortCutRegister(newsc));
					player.registerShortCut(newsc);
				}
			}
		}
		
		if (trainer instanceof L2FishermanInstance)
		{
			((L2FishermanInstance) trainer).showSkillList(player);
		}
		else
		{
			trainer.showSkillList(player, player.getSkillLearningClassId());
		}
		
		if (_id >= 1368 && _id <= 1372) // if skill is expand sendpacket :)
		{
			final ExStorageMaxCount esmc = new ExStorageMaxCount(player);
			player.sendPacket(esmc);
		}
		
		player.sendSkillList();
	}
	
	@Override
	public String getType()
	{
		return "[C] 6C RequestAquireSkill";
	}
}

 

2 hours ago, AchYlek said:

ya i remember old times, when i learned some skill after i took from phx packet, changed some numbers and learned new different skill 

I'll Google it myself, but i'll just ask: do know a link to any tutorial on how to use this hack? This way i can use it myself to test if the fix worked.

  • 0
Posted
6 minutes ago, dextroy said:

 

Ok, so the RequestAquireSkill.java. I'll send below what i did and the full code aswell:

image.png.f30b093e40b620240ca6cf0cc3a60a50.png

 

The first line is the 'If' you've suggested, but as you can see, there's an incompatibility with that "Lambda expression". What can i replace it with?

 

The second if is the skill_id verification i implemented, and it appears to be working on skill masters (i tested with < 1500 and it didn't allow me to learn the skill)

 

 

Here's the full code:

/*
 * L2jFrozen Project - www.l2jfrozen.com 
 * 
 * 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.l2jfrozen.gameserver.network.clientpackets;

import org.apache.log4j.Logger;

import com.l2jfrozen.Config;
import com.l2jfrozen.gameserver.datatables.SkillTable;
import com.l2jfrozen.gameserver.datatables.sql.SkillSpellbookTable;
import com.l2jfrozen.gameserver.datatables.sql.SkillTreeTable;
import com.l2jfrozen.gameserver.model.L2PledgeSkillLearn;
import com.l2jfrozen.gameserver.model.L2ShortCut;
import com.l2jfrozen.gameserver.model.L2Skill;
import com.l2jfrozen.gameserver.model.L2SkillLearn;
import com.l2jfrozen.gameserver.model.actor.instance.L2FishermanInstance;
import com.l2jfrozen.gameserver.model.actor.instance.L2FolkInstance;
import com.l2jfrozen.gameserver.model.actor.instance.L2ItemInstance;
import com.l2jfrozen.gameserver.model.actor.instance.L2NpcInstance;
import com.l2jfrozen.gameserver.model.actor.instance.L2PcInstance;
import com.l2jfrozen.gameserver.model.actor.instance.L2VillageMasterInstance;
import com.l2jfrozen.gameserver.network.SystemMessageId;
import com.l2jfrozen.gameserver.network.serverpackets.ExStorageMaxCount;
import com.l2jfrozen.gameserver.network.serverpackets.PledgeSkillList;
import com.l2jfrozen.gameserver.network.serverpackets.ShortCutRegister;
import com.l2jfrozen.gameserver.network.serverpackets.StatusUpdate;
import com.l2jfrozen.gameserver.network.serverpackets.SystemMessage;
import com.l2jfrozen.gameserver.util.IllegalPlayerAction;
import com.l2jfrozen.gameserver.util.Util;

public class RequestAquireSkill extends L2GameClientPacket
{
	private static Logger LOGGER = Logger.getLogger(RequestAquireSkill.class);
	
	private int _id;
	
	private int _level;
	
	private int _skillType;
	
	@Override
	protected void readImpl()
	{
		_id = readD();
		_level = readD();
		_skillType = readD();
	}
	
	@Override
	protected void runImpl()
	{
		
		final L2PcInstance player = getClient().getActiveChar();
		
		if (player == null)
			return;
		
		final L2FolkInstance trainer = player.getLastFolkNPC();
		
		if (trainer == null)
			return;
		
		final int npcid = trainer.getNpcId();
		
		if (!player.isInsideRadius(trainer, L2NpcInstance.INTERACTION_DISTANCE, false, false) && !player.isGM())
			return;
		
		if (!Config.ALT_GAME_SKILL_LEARN)
		{
			player.setSkillLearningClassId(player.getClassId());
		}
		
		if (player.getSkillLevel(_id) >= _level)
			// already knows the skill with this level
			return;
		
		if(SkillTreeTable.getInstance().getAllowedSkills(player.getClassId()).stream().noneMatch(e->e.getId == _skillId))
			return;
		
		// test block sills 1500+
		if ((_id) > 1500)
		{
			player.sendMessage("You are trying to learn an illegal skill");
			Util.handleIllegalPlayerAction(player, "Player " + player.getName() + " tried to learn skill that he can't!!!", IllegalPlayerAction.PUNISH_KICK);
			// illegal skill
			return;
		}
		
		final L2Skill skill = SkillTable.getInstance().getInfo(_id, _level);
		
		int counts = 0;
		int _requiredSp = 10000000;
		
		if (_skillType == 0)
		{
			
			final L2SkillLearn[] skills = SkillTreeTable.getInstance().getAvailableSkills(player, player.getSkillLearningClassId());
			
			for (final L2SkillLearn s : skills)
			{
				final L2Skill sk = SkillTable.getInstance().getInfo(s.getId(), s.getLevel());
				if (sk == null || sk != skill || !sk.getCanLearn(player.getSkillLearningClassId()) || !sk.canTeachBy(npcid))
				{
					continue;
				}
				counts++;
				_requiredSp = SkillTreeTable.getInstance().getSkillCost(player, skill);
			}
			
			if (counts == 0 && !Config.ALT_GAME_SKILL_LEARN)
			{
				player.sendMessage("You are trying to learn skill that u can't..");
				Util.handleIllegalPlayerAction(player, "Player " + player.getName() + " tried to learn skill that he can't!!!", IllegalPlayerAction.PUNISH_KICK);
				return;
			}
			
			if (player.getSp() >= _requiredSp)
			{
				int spbId = -1;
				// divine inspiration require book for each level
				if (Config.DIVINE_SP_BOOK_NEEDED && skill.getId() == L2Skill.SKILL_DIVINE_INSPIRATION)
				{
					spbId = SkillSpellbookTable.getInstance().getBookForSkill(skill, _level);
				}
				else if (Config.SP_BOOK_NEEDED && skill.getLevel() == 1)
				{
					spbId = SkillSpellbookTable.getInstance().getBookForSkill(skill);
				}
				
				// spellbook required
				if (spbId > -1)
				{
					final L2ItemInstance spb = player.getInventory().getItemByItemId(spbId);
					
					if (spb == null)
					{
						// Haven't spellbook
						player.sendPacket(new SystemMessage(SystemMessageId.ITEM_MISSING_TO_LEARN_SKILL));
						return;
					}
					
					// ok
					player.destroyItem("Consume", spb, trainer, true);
				}
			}
			else
			{
				final SystemMessage sm = new SystemMessage(SystemMessageId.NOT_ENOUGH_SP_TO_LEARN_SKILL);
				player.sendPacket(sm);
				
				return;
			}
		}
		else if (_skillType == 1)
		{
			int costid = 0;
			int costcount = 0;
			// Skill Learn bug Fix
			final L2SkillLearn[] skillsc = SkillTreeTable.getInstance().getAvailableSkills(player);
			
			for (final L2SkillLearn s : skillsc)
			{
				final L2Skill sk = SkillTable.getInstance().getInfo(s.getId(), s.getLevel());
				
				if (sk == null || sk != skill)
				{
					continue;
				}
				
				counts++;
				costid = s.getIdCost();
				costcount = s.getCostCount();
				_requiredSp = s.getSpCost();
			}
			
			if (counts == 0)
			{
				player.sendMessage("You are trying to learn skill that u can't..");
				Util.handleIllegalPlayerAction(player, "Player " + player.getName() + " tried to learn skill that he can't!!!", IllegalPlayerAction.PUNISH_KICK);
				return;
			}
			
			if (player.getSp() >= _requiredSp)
			{
				if (!player.destroyItemByItemId("Consume", costid, costcount, trainer, false))
				{
					// Haven't spellbook
					player.sendPacket(new SystemMessage(SystemMessageId.ITEM_MISSING_TO_LEARN_SKILL));
					return;
				}
				
				final SystemMessage sm = new SystemMessage(SystemMessageId.DISSAPEARED_ITEM);
				sm.addNumber(costcount);
				sm.addItemName(costid);
				sendPacket(sm);
			}
			else
			{
				final SystemMessage sm = new SystemMessage(SystemMessageId.NOT_ENOUGH_SP_TO_LEARN_SKILL);
				player.sendPacket(sm);
				return;
			}
		}
		else if (_skillType == 2) // pledgeskills TODO: Find appropriate system messages.
		{
			if (!player.isClanLeader())
			{
				// TODO: Find and add system msg
				player.sendMessage("This feature is available only for the clan leader");
				return;
			}
			
			int itemId = 0;
			int repCost = 100000000;
			// Skill Learn bug Fix
			final L2PledgeSkillLearn[] skills = SkillTreeTable.getInstance().getAvailablePledgeSkills(player);
			
			for (final L2PledgeSkillLearn s : skills)
			{
				final L2Skill sk = SkillTable.getInstance().getInfo(s.getId(), s.getLevel());
				
				if (sk == null || sk != skill)
				{
					continue;
				}
				
				counts++;
				itemId = s.getItemId();
				repCost = s.getRepCost();
			}
			
			if (counts == 0)
			{
				player.sendMessage("You are trying to learn skill that u can't..");
				Util.handleIllegalPlayerAction(player, "Player " + player.getName() + " tried to learn skill that he can't!!!", IllegalPlayerAction.PUNISH_KICK);
				return;
			}
			
			if (player.getClan().getReputationScore() >= repCost)
			{
				if (Config.LIFE_CRYSTAL_NEEDED)
				{
					if (!player.destroyItemByItemId("Consume", itemId, 1, trainer, false))
					{
						// Haven't spellbook
						player.sendPacket(new SystemMessage(SystemMessageId.ITEM_MISSING_TO_LEARN_SKILL));
						return;
					}
					
					final SystemMessage sm = new SystemMessage(SystemMessageId.DISSAPEARED_ITEM);
					sm.addItemName(itemId);
					sm.addNumber(1);
					sendPacket(sm);
				}
			}
			else
			{
				final SystemMessage sm = new SystemMessage(SystemMessageId.ACQUIRE_SKILL_FAILED_BAD_CLAN_REP_SCORE);
				player.sendPacket(sm);
				return;
			}
			player.getClan().setReputationScore(player.getClan().getReputationScore() - repCost, true);
			player.getClan().addNewSkill(skill);
			
			if (Config.DEBUG)
			{
				LOGGER.debug("Learned pledge skill " + _id + " for " + _requiredSp + " SP.");
			}
			
			final SystemMessage cr = new SystemMessage(SystemMessageId.S1_DEDUCTED_FROM_CLAN_REP);
			cr.addNumber(repCost);
			player.sendPacket(cr);
			final SystemMessage sm = new SystemMessage(SystemMessageId.CLAN_SKILL_S1_ADDED);
			sm.addSkillName(_id);
			player.sendPacket(sm);
			
			player.getClan().broadcastToOnlineMembers(new PledgeSkillList(player.getClan()));
			
			for (final L2PcInstance member : player.getClan().getOnlineMembers(""))
			{
				member.sendSkillList();
			}
			
			if (trainer instanceof L2VillageMasterInstance)
			{
				((L2VillageMasterInstance) trainer).showPledgeSkillList(player);
			}
			
			return;
		}
		
		else
		{
			LOGGER.warn("Recived Wrong Packet Data in Aquired Skill - unk1:" + _skillType);
			return;
		}
		
		player.addSkill(skill, true);
		
		if (Config.DEBUG)
		{
			LOGGER.debug("Learned skill " + _id + " for " + _requiredSp + " SP.");
		}
		
		player.setSp(player.getSp() - _requiredSp);
		
		final StatusUpdate su = new StatusUpdate(player.getObjectId());
		su.addAttribute(StatusUpdate.SP, player.getSp());
		player.sendPacket(su);
		
		final SystemMessage sp = new SystemMessage(SystemMessageId.SP_DECREASED_S1);
		sp.addNumber(_requiredSp);
		sendPacket(sp);
		
		final SystemMessage sm = new SystemMessage(SystemMessageId.LEARNED_SKILL_S1);
		sm.addSkillName(_id);
		player.sendPacket(sm);
		
		// update all the shortcuts to this skill
		if (_level > 1)
		{
			final L2ShortCut[] allShortCuts = player.getAllShortCuts();
			
			for (final L2ShortCut sc : allShortCuts)
			{
				if (sc.getId() == _id && sc.getType() == L2ShortCut.TYPE_SKILL)
				{
					final L2ShortCut newsc = new L2ShortCut(sc.getSlot(), sc.getPage(), sc.getType(), sc.getId(), _level, 1);
					player.sendPacket(new ShortCutRegister(newsc));
					player.registerShortCut(newsc);
				}
			}
		}
		
		if (trainer instanceof L2FishermanInstance)
		{
			((L2FishermanInstance) trainer).showSkillList(player);
		}
		else
		{
			trainer.showSkillList(player, player.getSkillLearningClassId());
		}
		
		if (_id >= 1368 && _id <= 1372) // if skill is expand sendpacket :)
		{
			final ExStorageMaxCount esmc = new ExStorageMaxCount(player);
			player.sendPacket(esmc);
		}
		
		player.sendSkillList();
	}
	
	@Override
	public String getType()
	{
		return "[C] 6C RequestAquireSkill";
	}
}

 

I'll Google it myself, but i'll just ask: do know a link to any tutorial on how to use this hack? This way i can use it myself to test if the fix worked.

change _skillId to 

_id
  • 0
Posted
7 minutes ago, HyperBlown said:

change _skillId to 

_id

There's still an issue, possibly with the e->e due to the java version. Can i replace that with something else?

image.png.1e7ed9a9f9bffe9e9f16d31e54a26837.png

  • 0
Posted (edited)
17 minutes ago, dextroy said:

There's still an issue, possibly with the e->e due to the java version. Can i replace that with something else?

image.png.1e7ed9a9f9bffe9e9f16d31e54a26837.png

oh. you are using java 7 I assume?
then change it to this:

boolean foundSkill = false;            
        for(L2SkillLearn skillLearn : SkillTreeTable.getInstance().getAllowedSkills(player.getClassId())){
            if(skillLearn.getId() == _Id){
                foundSkill = true;
                break;
            }
        }
        if(!foundSkill)
            return;

 

Edited by HyperBlown
  • 0
Posted
3 hours ago, dextroy said:

....

Apparently you can not understand some essential things. You need to follow some strategy to get the right results in a bug fix but I wont go further about it.

I would like to dwell on 2 things that you keep saying.

  • I am not a programmer
    • Pay someone to do all the things you can't do
  • It is a hack.
    • It's not. It all depends on what answer the server will give to the client.

 

Anyway

Your bug is obvious by reading the client packet RequestAquireSkill.java.

 

- if (counts == 0 && !Config.ALT_GAME_SKILL_LEARN)
+ if (counts == 0)
{
	player.sendMessage("You are trying to learn skill that u can't..");
	Util.handleIllegalPlayerAction(player, "Player " + player.getName() + " tried to learn skill that he can't!!!", IllegalPlayerAction.PUNISH_KICK);
	return;
}

 

If you just c/p the above code, then ive just lost 5 minutes of my life to write this post.

If you continue reading this, well, i feel better...

 

A basic communication:

You (player) double clicking on the npc. The corresponding html is appearing to your screen. Guess what, the client didn't know the html. Guess what, the server checked if you are dead, if you are paralized, if if if if, and finally the server decided which html you have to read. After that, the client just appearing that 'box'.

When you click on "learn skills", a list of some skills would appear. Guess what, the client doesnt know what skills you have to see. The server checked your class,your level, your state, your effects and 1000 other things. Finally, the server accepted your request and after the click of a skill, you are about to see another html which is describes all the clicked skill infos (sp,exp,book etc). Once you click on learn, guess what! The client can't know if you are capable to learn that skill! and instead of decide alone this hard task, is sending to the server 3 things. 1) id, 2) level, 3) type. Now the server is about mess arround and collect any possible information about your request like if you are 1 class (and if yes, what skills you are capable to learn), if you are gm and 1000 other 'if'. Once the server approves, it consumes from you the required materials (exp,sp etc) and the, it gives you the skills. So now, (and finally) , guess what .... Do you believe that anything of what i wrote, is a hack? No! The 'hacker' the only thing that he did was to send the packet of the (id,lvl,type) a bit different. Like different id and level. If the 'hacker' will finally learn that skill, where's the glitch? The server responded OK and the client welcomed this new skill!

 

Enough with the words. Lets see the code.

 

Ignoring some code on the beggining and stand on this:

 

if (_skillType == 0)
		{

 

Like some ppl mentioned before, frozen is a bad choice. Here for example, what the fuck is 0 ? No comments from the developer and you cant know that shit. In that case, i know. Its the regular skills that the player requests. So 1st of all, here is the right place to check.

 

Inside of that brackets we can see this code

final L2SkillLearn[] skills = SkillTreeTable.getInstance().getAvailableSkills(player, player.getSkillLearningClassId());

for (final L2SkillLearn s : skills)
{
	final L2Skill sk = SkillTable.getInstance().getInfo(s.getId(), s.getLevel());
	if (sk == null || sk != skill || !sk.getCanLearn(player.getSkillLearningClassId()) || !sk.canTeachBy(npcid))
	{
		continue;
	}
	counts++;
	_requiredSp = SkillTreeTable.getInstance().getSkillCost(player, skill);
}

 

I know that its a bit hard for you to understand whats exactly in there, but there are some calculations and verifications in order to verify that the player can actually learn that skill. But hold on, whats the 

counts++;

thing? Is it counting the verified skills? Oh yeah. Lets move on! Lets print whats the value of that 'counts' variable! [ Compiling.... ]  [ Printing... ]   [  0  ]. The value is 0. Just because the super haste isn't registered at any class . So how the hell did he actually learned that skill? Lets see what comes next!

 

if (counts == 0 && !Config.ALT_GAME_SKILL_LEARN)
{
	player.sendMessage("You are trying to learn skill that u can't..");
	Util.handleIllegalPlayerAction(player, "Player " + player.getName() + " tried to learn skill that he can't!!!", IllegalPlayerAction.PUNISH_KICK);
	return;
}

 

Something bad is happening here. Lets expand it a bit.

if the counts are 0 (yes we are 0) and our config is false kick the player... Wait what?

if (counts == 0 and config == false) kick the player... Wait what?

The config is true!

 

 

Guess.... what.... This condition, would never be executed....

  • 0
Posted
16 minutes ago, HyperBlown said:

oh. you are using java 7 I assume?
then change it to this:

boolean foundSkill = false;            
        for(L2SkillLearn skillLearn : SkillTreeTable.getInstance().getAllowedSkills(player.getClassId())){
            if(skillLearn.getId() == _Id){
                foundSkill = true;
                break;
            }
        }
        if(!foundSkill)
            return;

 

Alright, in the meantime i was testing l2phx with my previous code. And it also seems like my protection worked. I used it's injection to learn Super Haste and got this:

image.png.1cb5a730babc51c9475260f18d17a7ec.png

So i'll use your code that fits plus the one i added previously. I guess this should fix this particular issue.

 

Additionally, would you know how i could make it create a simple log file, or add it's messages to the server log? This way i can keep up with players that are trying to exploit the server easily, because as of it is, there's no logs being generated, just kicking out.

Guest
This topic is now closed to further replies.



  • Posts

    • I'm using Myext64 HF and recently tried to replicate the "br_xmas09_event" Raising Rudolph Event. Detailed event information can be found at https://legacy-lineage2.com/news/_rudolf_the_red.html After configuring .eventdata.xml and starting the server, t  server log shows: 12/02/2025 15:39:01.809, [NO_ERROR] SpawnEx2 [br_xmas2009_invisible][schuttgart20_npc2213_xs03m1] [1][0][0][0][0][346796390] 12/02/2025 15:39:02.057, DummyPacket received from L2Server 12/02/2025 15:39:02.058, server socket close 312ac(f0820224) error(997) 12/02/2025 15:39:02.058, [CallStack][tid:0][tick:2][0] Begin 12/02/2025 15:39:02.058, [CallStack][tid:0][tick:2][1][0] void __cdecl IOThreadCallback::IOThread_common(void) 12/02/2025 15:39:02.059, [CallStack][tid:0][tick:2][2][1] void IOThread_common 1 12/02/2025 15:39:02.059, [CallStack][tid:0][tick:2][3][2] void __cdecl CIOSocketEx<class CIOBufferEx<16384> >::Close(void) 12/02/2025 15:39:02.059, [CallStack][tid:0][tick:2][4][3] void __cdecl CServerSocket::OnClose(void) 12/02/2025 15:39:02.059, [CallStack][tid:0][tick:2][5] End l2server log: 12/02/2025 15:39:02.112, npc server closed(127.0.0.1) error: 64 read buffer size: (server:0 npc:0) 12/02/2025 15:39:02.112, [NO_ERROR] L2Server is under protection mode!!! 12/02/2025 15:39:02.112, [NO_ERROR] L2Server is under protection mode!!! 12/02/2025 15:39:02.112, [NO_ERROR] L2Server is under protection mode!!! 12/02/2025 15:39:02.131, dwTime[0] < 80 !!!!!!! 12/02/2025 15:39:02.131, [CallStack][tid:7][tick:1][0] Begin 12/02/2025 15:39:02.132, [CallStack][tid:7][tick:1][1][0] void __cdecl IOThreadCallback::IOThread_common(void) 12/02/2025 15:39:02.132, [CallStack][tid:7][tick:1][2][1] void IOThread_common 1 12/02/2025 15:39:02.132, [CallStack][tid:7][tick:1][4][3] void __cdecl NpcSocket::OnClose(void) 12/02/2025 15:39:02.132, [CallStack][tid:7][tick:1][3][2] void __cdecl CIOSocketEx<class CIOBufferEx<16384> >::Close(void) 12/02/2025 15:39:02.132, [CallStack][tid:7][tick:1][5] End 12/02/2025 15:39:31.767, server closed(127.0.0.1) Error: 64 Read buffer size: (server:0 npc:0) 12/02/2025 15:39:31.768, [NO_ERROR] Logout All Characters : 1   The NPC server sent a packet to the L2 server while generating the br_xmas2009_invisible game NPC server, and the NPC server subsequently crashed.     After some digging, I found a clue in a very old MXC post, but the fix was for the GF version. The whole problem is in l2server side support for NPC function CreateOnePrivateNearUser. It sends CreatePacket but Koreans made some changes in it (added instance ID) so it got broken. As Santa event is the only AI that uses this function, they probably don't know about it    So is there a way to fix this problem, specifically for Myext64 HF? I'd be happy to buy him coffee. set_compiler_opt base_event_type(@NTYPE_NPC_EVENT) class ai_br_vital_manager : default_npc { parameter: int br_vitality2010_EVENT_ID = 20108888; handler: EventHandler CREATED() { } EventHandler TALKED(talker) { ShowPage(talker, "br_vi_stevu001.htm"); super; } EventHandler GIVE_EVENT_DATA(talker, i0, i1, i2, i3, i4) { i3 = i2 / 3600; i2 = i2 - i3 * 3600; i4 = i2 / 60; i2 = i2 - i4 * 60; if (i1 == 20108888) { if (i0 == 1) { CastBuffForQuestReward(talker, @s_br_vitality_day_1); CastBuffForQuestReward(talker, @s_br_vitality_day_2); ShowPage(talker, "br_vi_stevu002.htm"); } else { ShowPage(talker, "br_vi_stevu003.htm"); } } } EventHandler MENU_SELECTED(talker, ask, reply, c0) { if (ask == 50021) { select (reply) { case 1: CanGiveEventData(talker, 20108888); break; case 2: if (talker.level <= 75) { ShowPage(talker, "br_vi_stevu005.htm"); } else if (IsInCategory(@fighter_group, talker.occupation)) { CastBuffForQuestReward(talker, @s_wind_walk_for_newbie); CastBuffForQuestReward(talker, @s_shield_for_newbie); CastBuffForQuestReward(talker, @s_magic_barrier_for_adventurer); CastBuffForQuestReward(talker, @s_bless_the_body_for_newbie); CastBuffForQuestReward(talker, @s_vampiric_rage_for_newbie); CastBuffForQuestReward(talker, @s_regeneration_for_newbie); CastBuffForQuestReward(talker, @s_haste_for_adventurer); ShowPage(talker, "br_vi_stevu006.htm"); } else if (IsInCategory(@mage_group, talker.occupation)) { CastBuffForQuestReward(talker, @s_wind_walk_for_newbie); CastBuffForQuestReward(talker, @s_shield_for_newbie); CastBuffForQuestReward(talker, @s_magic_barrier_for_adventurer); CastBuffForQuestReward(talker, @s_bless_the_soul_for_newbie); CastBuffForQuestReward(talker, @s_acumen_for_newbie); CastBuffForQuestReward(talker, @s_concentration_for_newbie); CastBuffForQuestReward(talker, @s_empower_for_newbie); ShowPage(talker, "br_vi_stevu007.htm"); } break; case 3: c0 = GetSummon(talker); if (talker.level <= 75) { ShowPage(talker, "br_vi_stevu011.htm"); } else if (IsNullCreature(c0) == 0 && IsInCategory(@summon_npc_group, c0.class_id) && IsInCategory(@pet_group, c0.class_id) == 0) { CastBuffForQuestReward(c0, @s_wind_walk_for_newbie); CastBuffForQuestReward(c0, @s_shield_for_newbie); CastBuffForQuestReward(c0, @s_magic_barrier_for_adventurer); CastBuffForQuestReward(c0, @s_bless_the_body_for_newbie); CastBuffForQuestReward(c0, @s_vampiric_rage_for_newbie); CastBuffForQuestReward(c0, @s_regeneration_for_newbie); CastBuffForQuestReward(c0, @s_bless_the_soul_for_newbie); CastBuffForQuestReward(c0, @s_acumen_for_newbie); CastBuffForQuestReward(c0, @s_concentration_for_newbie); CastBuffForQuestReward(c0, @s_empower_for_newbie); CastBuffForQuestReward(c0, @s_haste_for_adventurer); ShowPage(talker, "br_vi_stevu009.htm"); } else { ShowPage(talker, "br_vi_stevu010.htm"); } break; } } } } Another one is about the " br_vitality2010_event event".   GIVE_EVENT_DATA is likely the only one in the activity AI script that uses this handle.      
    • Offtopic, personal attacks, probably too old to use that much memes and what's YOUR actual contribution to L2J, in order I laugh aswell ?   The main poster quotes my pack so I answer accordingly, while you advertise L2JFrozen in both of your posts - discontinued since 2014 (? 1132 rev), with none taking back the open source lead while anyone could.   If you're somewhat affiliated to hopzone, you probably packed way more money than me. Packs don't make any type of money (barely 100e/month) and if you would follow me, you would know there are ways to handle it or even getting paid.   Hope I was short enough, 🧂🤡.
    • Hi guys, this is a CMS im sharing for lineage 2 servers, im tired of the crap i see on new release servers. Dont let me start on the IA developed ones lmao.   📋 Description Free and open source template to create landing pages for Lineage 2 private servers. Designed with a dark fantasy theme and modern animations. ✨ Current Features This FREE version includes: Complete Landing Page - Professional design ready to use Multi-language Support - Spanish, English, Portuguese Dark Fantasy Theme - With animated UI elements Server Information - Rates, features, and rules Olympiad Ranking - Rankings display Download Section - For game client Skins and Animations Gallery Streaming Widget - Twitch/Kick integration Fully Customizable - Via configuration files ❌ Not Included in Free Version ❌ User Registration System ❌ Online Players Counter ❌ Donation Panel 💎 Premium Integrations IntegrationPrice Registration System $50 USD Online Players Counter $50 USD Donation Panel $50 USD   📧 Contact: https://gh0tstudio.com 🛠️ Tech Stack Technology    Version    Description React              19.2.0       UI Library TypeScript       5.8.2        Static typing Vite                 6.2.0         Build tool TailwindCSS   CDNCSS    Framework Lucide React   0.554.0         Icons i18next           23.16.0       Internationalization react-i18next   15.1.0        React bindings for i18n All documentation provided for AI AGENTS to make changes on the ui texts and so on. u can have a look on the cms fully working with donation panel, online count and register via: https://crmlineage2.vercel.app/ https://github.com/6h0T/CRM-LINEAGE2-FREE If u are in the lookings to develop a unique website for ur projects, u can dm me or contact me throw my socials on my profile. all code has encrypted references so any type of rebranding, copying or selling without authorization will result in take downs
    • Hello dude, i can help u out, i reached to u via DM, my studio is https://gh0tstudio.com i have worked with almost 40 brands on developing Private Lineage and Mu online servers, dashboard for vote pages and more. I sent u some examples too
    • L2 TARTARUS - HTML DESIGN       L2 KOMBAT - ANIMATED BORDER   L2 SERENITY - ANIMATED LOGO   L2 ARCANE - COMMUNITY BOARD     L2 AMERIKA - ADVERTISING BANNER   L2 ZERON - ADVERTISING BANNER  
  • Topics

×
×
  • Create New...

AdBlock Extension Detected!

Our website is made possible by displaying online advertisements to our members.

Please disable AdBlock browser extension first, to be able to use our community.

I've Disabled AdBlock