Видел много тем на разных форумах про заточки, методы точки всякие "Баги" и про "способы" заточки, и скажу прямо это Глупость.
Существует 3 типа серверов.
Java сервера различных команд.(L2j,L2Free,etc)
C++ сервера обычно самописи etc...
Ну и офф Lineage.com.
В каждом по своему реализована функция Random.А значит и процесс заточки в зависимости от платформы отличается
Бред про "Корейский рандом" прошу засунуть в кладовку сумасшедших умозаключений.
поскольку официально проект C успешно загнулся, поговорим про самую распространённую платформу java.
Рандом в Java серверах реализован классом java.security.SecureRandom который импортируется из rt.jar который идёт в комплекте с Java Development Kit компании Sun Microsystems.
В классе Рандом реализован вот такой вот нехитрой функцией
Код:
package java.security;
import java.io.Serializable;
import java.util.Random;
import java.util.Enumeration;
public class SecureRandom extends Random
{
long counter = 0;
MessageDigest digest = null;
Provider provider = null;
byte[] randomBytes = null;
int randomBytesUsed = 0;
SecureRandomSpi secureRandomSpi = null;
byte[] state = null;
public SecureRandom()
{
Provider p[] = Security.getProviders();
String key;
String classname = null;
int i, flag = 0;
Enumeration e;
for (i = 0; i < p.length; i++)
{
e = p[i].propertyNames();
while (e.hasMoreElements())
{
key = (String) e.nextElement();
if (key.startsWith("SecureRandom."))
if ((classname = p[i].getProperty(key)) != null)
break;
}
if (classname != null)
break;
}
//if( classname == null)
// throw new NoSuchAlgorithmException();
try
{
this.secureRandomSpi =
(SecureRandomSpi) Class.forName(classname).newInstance();
//s.algorithm = algorithm;
this.provider = p[i];
}
catch (ClassNotFoundException cnfe)
{
//throw new NoSuchAlgorithmException("Class not found");
}
catch (InstantiationException ie)
{
//throw new NoSuchAlgorithmException("Class instantiation failed");
}
catch (IllegalAccessException iae)
{
//throw new NoSuchAlgorithmException("Illegal Access");
}
}
public SecureRandom(byte[] seed)
{
this();
setSeed(seed);
}
protected SecureRandom(SecureRandomSpi secureRandomSpi, Provider provider)
{
this.secureRandomSpi = secureRandomSpi;
this.provider = provider;
}
public static SecureRandom getInstance(String algorithm) throws
NoSuchAlgorithmException
{
Provider p[] = Security.getProviders();
//Format of Key: SecureRandom.algname
StringBuffer key = new StringBuffer("SecureRandom.");
key.append(algorithm);
String classname = null;
int i;
for (i = 0; i < p.length; i++)
{
if ((classname = p[i].getProperty(key.toString())) != null)
break;
}
if (classname == null)
throw new NoSuchAlgorithmException();
try
{
return new SecureRandom((SecureRandomSpi) Class.forName(classname).
newInstance(), p[i]);
}
catch (ClassNotFoundException cnfe)
{
throw new NoSuchAlgorithmException("Class not found");
}
catch (InstantiationException ie)
{
throw new NoSuchAlgorithmException("Class instantiation failed");
}
catch (IllegalAccessException iae)
{
throw new NoSuchAlgorithmException("Illegal Access");
}
}
public static SecureRandom getInstance(String algorithm,
String provider) throws
NoSuchAlgorithmException, NoSuchProviderException
{
Provider p = Security.getProvider(provider);
if (p == null)
throw new NoSuchProviderException();
//Format of Key: SecureRandom.algName
StringBuffer key = new StringBuffer("SecureRandom.");
key.append(algorithm);
String classname = p.getProperty(key.toString());
if (classname == null)
throw new NoSuchAlgorithmException();
try
{
return new SecureRandom((SecureRandomSpi) Class.forName(classname).
newInstance(), p);
}
catch (ClassNotFoundException cnfe)
{
throw new NoSuchAlgorithmException("Class not found");
}
catch (InstantiationException ie)
{
throw new NoSuchAlgorithmException("Class instantiation failed");
}
catch (IllegalAccessException iae)
{
throw new NoSuchAlgorithmException("Illegal Access");
}
}
public final Provider getProvider()
{
return provider;
}
public void setSeed(byte[] seed)
{
secureRandomSpi.engineSetSeed(seed);
}
public void setSeed(long seed)
{
if (secureRandomSpi != null)
{
byte tmp[] = { (byte) (0xff & (seed >> 56)),
(byte) (0xff & (seed >> 48)),
(byte) (0xff & (seed >> 40)),
(byte) (0xff & (seed >> 32)),
(byte) (0xff & (seed >> 24)),
(byte) (0xff & (seed >> 16)),
(byte) (0xff & (seed >> 8)),
(byte) (0xff & seed)
};
secureRandomSpi.engineSetSeed(tmp);
}
}
public void nextBytes(byte[] bytes)
{
randomBytesUsed += bytes.length;
counter++;
secureRandomSpi.engineNextBytes(bytes);
}
protected final int next(int numBits)
{
if (numBits == 0)
return 0;
byte tmp[] = new byte[numBits / 8 + (1 * (numBits % 8))];
secureRandomSpi.engineNextBytes(tmp);
randomBytesUsed += tmp.length;
counter++;
int ret = 0;
for (int i = 0; i < tmp.length; i++)
ret |= tmp[i] << (8 * i);
return ret;
}
public static byte[] getSeed(int numBytes)
{
byte tmp[] = new byte[numBytes];
new Random().nextBytes(tmp);
return tmp;
//return secureRandomSpi.engineGenerateSeed( numBytes );
}
public byte[] generateSeed(int numBytes)
{
return secureRandomSpi.engineGenerateSeed(numBytes);
}
}
}
после чего на него давят RIPEMD-160. и лишь затем мы получаем рзультат вида(ура заточилось и б"ять сломалась)
Возникает вопрос а откуда берётся seed?
А Зернышко друзья мои берётся из Алгоритма Mersenne Twister
Код:
package net.sf.l2j.util;
import java.util.Random;
public class MTRandom extends Random {
private static final long serialVersionUID = -515082678588212038L;
private final static int UPPER_MASK = 0x80000000;
private final static int LOWER_MASK = 0x7fffffff;
private final static int N = 624;
private final static int M = 397;
private final static int MAGIC[] = { 0x0, 0x9908b0df };
private final static int MAGIC_FACTOR1 = 1812433253;
private final static int MAGIC_FACTOR2 = 1664525;
private final static int MAGIC_FACTOR3 = 1566083941;
private final static int MAGIC_MASK1 = 0x9d2c5680;
private final static int MAGIC_MASK2 = 0xefc60000;
private final static int MAGIC_SEED = 19650218;
private final static long DEFAULT_SEED = 5489L;
private transient int[] mt;
private transient int mti;
private transient boolean compat = false;
// Temporary buffer used during setSeed(long)
private transient int[] ibuf;
public MTRandom() { }
public MTRandom(boolean compatible) {
super(0L);
compat = compatible;
setSeed(compat?DEFAULT_SEED:System.currentTimeMillis());
}
public MTRandom(long seed) {
super(seed);
}
public MTRandom(byte[] buf) {
super(0L);
setSeed(buf);
}
public MTRandom(int[] buf) {
super(0L);
setSeed(buf);
}
private final void setSeed(int seed) {
if (mt == null) mt = new int[N];
// ---- Begin Mersenne Twister Algorithm ----
mt[0] = seed;
for (mti = 1; mti < N; mti++) {
mt[mti] = (MAGIC_FACTOR1 * (mt[mti-1] ^ (mt[mti-1] >>> 30)) + mti);
}
// ---- End Mersenne Twister Algorithm ----
}
@Override
public final synchronized void setSeed(long seed) {
if (compat) {
setSeed((int)seed);
} else {
if (ibuf == null) ibuf = new int[2];
ibuf[0] = (int)seed;
ibuf[1] = (int)(seed >>> 32);
setSeed(ibuf);
}
}
public final void setSeed(byte[] buf) {
setSeed(pack(buf));
}
public final synchronized void setSeed(int[] buf) {
int length = buf.length;
if (length == 0) throw new IllegalArgumentException("Seed buffer may not be empty");
// ---- Begin Mersenne Twister Algorithm ----
int i = 1, j = 0, k = (N > length ? N : length);
setSeed(MAGIC_SEED);
for (; k > 0; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >>> 30)) * MAGIC_FACTOR2)) + buf[j] + j;
i++; j++;
if (i >= N) { mt[0] = mt[N-1]; i = 1; }
if (j >= length) j = 0;
}
for (k = N-1; k > 0; k--) {
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >>> 30)) * MAGIC_FACTOR3)) - i;
i++;
if (i >= N) { mt[0] = mt[N-1]; i = 1; }
}
mt[0] = UPPER_MASK; // MSB is 1; assuring non-zero initial array
// ---- End Mersenne Twister Algorithm ----
}
@Override
protected final synchronized int next(int bits) {
// ---- Begin Mersenne Twister Algorithm ----
int y, kk;
if (mti >= N) { // generate N words at one time
for (kk = 0; kk < N-M; kk++) {
y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
mt[kk] = mt[kk+M] ^ (y >>> 1) ^ MAGIC[y & 0x1];
}
for (;kk < N-1; kk++) {
y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
mt[kk] = mt[kk+(M-N)] ^ (y >>> 1) ^ MAGIC[y & 0x1];
}
y = (mt[N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[N-1] = mt[M-1] ^ (y >>> 1) ^ MAGIC[y & 0x1];
mti = 0;
}
y = mt[mti++];
// Tempering
y ^= (y >>> 11);
y ^= (y << 7) & MAGIC_MASK1;
y ^= (y << 15) & MAGIC_MASK2;
y ^= (y >>> 18);
// ---- End Mersenne Twister Algorithm ----
return (y >>> (32-bits));
}
public static int[] pack(byte[] buf) {
int k, blen = buf.length, ilen = ((buf.length+3) >>> 2);
int[] ibuf = new int[ilen];
for (int n = 0; n < ilen; n++) {
int m = (n+1) << 2;
if (m > blen) m = blen;
for (k = buf[--m]&0xff; (m & 0x3) != 0; k = (k << 8) | buf[--m]&0xff);
ibuf[n] = k;
}
return ibuf;
}
}
после чего состовляется в виртуальной памяти список + и - так сказать к которому во время заточки обращается сервер.
Процент лишь влияет на количество в этом "списке" "минусов" а точнее говоря 0.
Какой можно сделать из этого вывод?
Просчитать "рандом" по такому алгоритму теоретичиески можно но очень трудоёмко, на практике практически невозможно да и проще узнать у администратора сервера рейты заточек.
Например если шанс 75 и макс уровень 50 то заточив 100 вещей вы гарантировано заточите 2 - 3 до 50 уровня .Но это в тепличных условиях, без учёта времени и других игроков которые тоже используют данный "список".
Надеюсь этой статьёй я развею легенды и мифы про просчёт последовательности фейк заточки и прочие танцы с бубном.