Mods encryption
parent
d5a721dbc5
commit
c92e3d5ed6
|
@ -0,0 +1,133 @@
|
|||
1. Encryption
|
||||
|
||||
The Lua files can be encrypted using the 256 bit variant of the AES encryption algorithm.
|
||||
|
||||
The AES key is file name dependent, and is built using eight keys and eight prime numbers
|
||||
defined in "adel/src/encryption_data.h".
|
||||
|
||||
#define ENCRYPTION_KEY_0 0x01234567
|
||||
#define ENCRYPTION_KEY_1 0x01234567
|
||||
#define ENCRYPTION_KEY_2 0x01234567
|
||||
#define ENCRYPTION_KEY_3 0x01234567
|
||||
#define ENCRYPTION_KEY_4 0x01234567
|
||||
#define ENCRYPTION_KEY_5 0x01234567
|
||||
#define ENCRYPTION_KEY_6 0x01234567
|
||||
#define ENCRYPTION_KEY_7 0x01234567
|
||||
#define ENCRYPTION_PRIME_0 0x01234567
|
||||
#define ENCRYPTION_PRIME_1 0x01234567
|
||||
#define ENCRYPTION_PRIME_2 0x01234567
|
||||
#define ENCRYPTION_PRIME_3 0x01234567
|
||||
#define ENCRYPTION_PRIME_4 0x01234567
|
||||
#define ENCRYPTION_PRIME_5 0x01234567
|
||||
#define ENCRYPTION_PRIME_6 0x01234567
|
||||
#define ENCRYPTION_PRIME_7 0x01234567
|
||||
|
||||
Of course, the above values must be changed, if needed on a customer basis, and the version
|
||||
of "encryption_data.h" which contains the actual keys and prime numbers used for encryption
|
||||
must absolutely be kept secret, and thus should NEVER be put on a Github repository.
|
||||
|
||||
Be aware that when any key or prime number is changed in "encryption_data.h" :
|
||||
- the encryption tool, the game client and the game server must be rebuilt so that they all
|
||||
use the same keys.
|
||||
- the decrypted Lua files must be encrypted with the new encryption tool.
|
||||
- the server, the game and the encrypted Lua files must be deployed again.
|
||||
|
||||
Big 32-bit prime numbers can be generated here :
|
||||
|
||||
https://asecuritysite.com/encryption/random3?val=32
|
||||
|
||||
There is also a list with all the 32-bit prime numbers here :
|
||||
|
||||
http://www.fukudat.com/prime/prime.dat.gz
|
||||
|
||||
Sample data :
|
||||
|
||||
#define ENCRYPTION_KEY_0 0x9534A53F
|
||||
#define ENCRYPTION_KEY_1 0xE53823C4
|
||||
#define ENCRYPTION_KEY_2 0x31986584
|
||||
#define ENCRYPTION_KEY_3 0x3919F129
|
||||
#define ENCRYPTION_KEY_4 0x81683587
|
||||
#define ENCRYPTION_KEY_5 0x16E81A34
|
||||
#define ENCRYPTION_KEY_6 0xC9835185
|
||||
#define ENCRYPTION_KEY_7 0x246D32F5
|
||||
#define ENCRYPTION_PRIME_0 1977777259u
|
||||
#define ENCRYPTION_PRIME_1 3392428841u
|
||||
#define ENCRYPTION_PRIME_2 293353289u
|
||||
#define ENCRYPTION_PRIME_3 891334331u
|
||||
#define ENCRYPTION_PRIME_4 1926494413u
|
||||
#define ENCRYPTION_PRIME_5 1460369081u
|
||||
#define ENCRYPTION_PRIME_6 3938039173u
|
||||
#define ENCRYPTION_PRIME_7 1340222629u
|
||||
|
||||
|
||||
2. Encryption tool
|
||||
|
||||
Lua files can be encrypted/decrypted using a dedicated tool in the "adel/util/crypt/" folder.
|
||||
|
||||
The "-e" option is used to encrypt the files, and the "-d" option to decrypt them.
|
||||
|
||||
Only files which aren't already encrypted/decrypted are processed.
|
||||
|
||||
Files can be encrypted/decrypted manually, by providing their paths as additional arguments :
|
||||
|
||||
crypt -e *.lua
|
||||
crypt -d *.lua
|
||||
|
||||
The recommended way to use the tool is to create a "CryptList.txt" file in the current folder
|
||||
and call the tool without arguments :
|
||||
|
||||
crypt -e
|
||||
crypt -d
|
||||
|
||||
This file should contain the paths of all the Lua files to encrypt or decrypt.
|
||||
|
||||
The "CryptList.txt" file can be generated automatically using the following Linux command :
|
||||
|
||||
find . -name "*.lua" > CryptList.txt
|
||||
|
||||
This command will create a "CryptList.txt" file with the paths of the Lua files of this folder
|
||||
and its subfolder.
|
||||
|
||||
|
||||
3. Compilation
|
||||
|
||||
Encryption tool :
|
||||
|
||||
cd adel/util/crypt/
|
||||
rm CMakeCache.txt
|
||||
cmake .
|
||||
make
|
||||
|
||||
Game and server :
|
||||
|
||||
cd adel/
|
||||
rm CMakeCache.txt
|
||||
cmake . -DBUILD_CLIENT=1 -DBUILD_SERVER=1 -DRUN_IN_PLACE=TRUE
|
||||
make
|
||||
|
||||
or
|
||||
|
||||
cd adel/
|
||||
rm CMakeCache.txt
|
||||
cmake . -DBUILD_CLIENT=1 -DBUILD_SERVER=1 -DRUN_IN_PLACE=TRUE -DENABLE_CURL=1 -DENABLE_CURSES=1 -DENABLE_LUAJIT=1
|
||||
make
|
||||
|
||||
|
||||
4. Usage
|
||||
|
||||
At any time, the Lua files can be decrypted and encrypted in place in the development folder.
|
||||
|
||||
A safer approach is to copy the Lua files to deploy in a temporary folder and encrypt them there
|
||||
before deployment.
|
||||
|
||||
|
||||
5. Signature tool
|
||||
|
||||
The "md5.sh" shell script in the "adel/util/md5/" allows to update the production database,
|
||||
by generating an SQL script file with the required commands.
|
||||
|
||||
It will scan all Lua files in the current folder and generate SQL commands like this one :
|
||||
|
||||
update maps
|
||||
set mods_hash_md5 = "c50f510b0072cb9467e0d4c43f96fcae"
|
||||
where url_download = "http://assets.kidscode.com/master/test/x.lua";
|
|
@ -549,6 +549,7 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
|
|||
}
|
||||
|
||||
|
||||
#if 0 // :PATCH:
|
||||
LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
|
||||
LoadF lf;
|
||||
int status, readstatus;
|
||||
|
@ -588,6 +589,7 @@ LUALIB_API int luaL_loadfile (lua_State *L, const char *filename) {
|
|||
lua_remove(L, fnameindex);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct LoadS {
|
||||
|
|
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
* Byte-oriented AES-256 implementation.
|
||||
* All lookup tables replaced with 'on the fly' calculations.
|
||||
*
|
||||
* Copyright (c) 2007-2009 Ilya O. Levin, http://www.literatecode.com
|
||||
* Other contributors: Hal Finney
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#define FD(x) (((x) >> 1) ^ (((x) & 1) ? 0x8d : 0))
|
||||
|
||||
|
||||
static unsigned char rj_xtime(unsigned char);
|
||||
static void aes_subBytes(unsigned char *);
|
||||
static void aes_subBytes_inv(unsigned char *);
|
||||
static void aes_addRoundKey(unsigned char *, unsigned char *);
|
||||
static void aes_addRoundKey_cpy(unsigned char *, unsigned char *, unsigned char *);
|
||||
static void aes_shiftRows(unsigned char *);
|
||||
static void aes_shiftRows_inv(unsigned char *);
|
||||
static void aes_mixColumns(unsigned char *);
|
||||
static void aes_mixColumns_inv(unsigned char *);
|
||||
static void aes_expandEncKey(unsigned char *, unsigned char *);
|
||||
static void aes_expandDecKey(unsigned char *, unsigned char *);
|
||||
|
||||
|
||||
typedef struct {
|
||||
unsigned char key[32];
|
||||
unsigned char enckey[32];
|
||||
unsigned char deckey[32];
|
||||
} aes256_context;
|
||||
|
||||
|
||||
static void aes256_init(aes256_context *, unsigned char * key);
|
||||
static void aes256_done(aes256_context *);
|
||||
static void aes256_encrypt_ecb(aes256_context *, unsigned char *plaintext);
|
||||
static void aes256_decrypt_ecb(aes256_context *, unsigned char *cipertext);
|
||||
|
||||
|
||||
static const unsigned char sbox[256] =
|
||||
{
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
|
||||
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
|
||||
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
|
||||
0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
|
||||
0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
|
||||
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
|
||||
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
|
||||
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
|
||||
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
|
||||
0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
|
||||
0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
|
||||
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
|
||||
0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
|
||||
0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
|
||||
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
|
||||
0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
|
||||
0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||
};
|
||||
static const unsigned char sboxinv[256] =
|
||||
{
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
|
||||
0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
|
||||
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
|
||||
0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
|
||||
0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
|
||||
0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
|
||||
0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
|
||||
0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
|
||||
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
|
||||
0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
|
||||
0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
|
||||
0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
|
||||
0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
|
||||
0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
|
||||
0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
|
||||
0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
|
||||
0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||
};
|
||||
|
||||
#define rj_sbox(x) sbox[(x)]
|
||||
#define rj_sbox_inv(x) sboxinv[(x)]
|
||||
|
||||
|
||||
static unsigned char rj_xtime(unsigned char x)
|
||||
{
|
||||
unsigned char y = (unsigned char)(x << 1);
|
||||
return (x & 0x80) ? (y ^ 0x1b) : y;
|
||||
}
|
||||
|
||||
|
||||
static void aes_subBytes(unsigned char *buf)
|
||||
{
|
||||
register unsigned char i = 16;
|
||||
|
||||
while (i--) buf[i] = rj_sbox(buf[i]);
|
||||
}
|
||||
|
||||
|
||||
static void aes_subBytes_inv(unsigned char *buf)
|
||||
{
|
||||
register unsigned char i = 16;
|
||||
|
||||
while (i--) buf[i] = rj_sbox_inv(buf[i]);
|
||||
}
|
||||
|
||||
|
||||
static void aes_addRoundKey(unsigned char *buf, unsigned char *key)
|
||||
{
|
||||
register unsigned char i = 16;
|
||||
|
||||
while (i--) buf[i] ^= key[i];
|
||||
}
|
||||
|
||||
|
||||
static void aes_addRoundKey_cpy(unsigned char *buf, unsigned char *key, unsigned char *cpk)
|
||||
{
|
||||
register unsigned char i = 16;
|
||||
|
||||
while (i--) buf[i] ^= (cpk[i] = key[i]), cpk[16 + i] = key[16 + i];
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void aes_shiftRows(unsigned char *buf)
|
||||
{
|
||||
register unsigned char i, j;
|
||||
|
||||
i = buf[1], buf[1] = buf[5], buf[5] = buf[9], buf[9] = buf[13], buf[13] = i;
|
||||
i = buf[10], buf[10] = buf[2], buf[2] = i;
|
||||
j = buf[3], buf[3] = buf[15], buf[15] = buf[11], buf[11] = buf[7], buf[7] = j;
|
||||
j = buf[14], buf[14] = buf[6], buf[6] = j;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void aes_shiftRows_inv(unsigned char *buf)
|
||||
{
|
||||
register unsigned char i, j;
|
||||
|
||||
i = buf[1], buf[1] = buf[13], buf[13] = buf[9], buf[9] = buf[5], buf[5] = i;
|
||||
i = buf[2], buf[2] = buf[10], buf[10] = i;
|
||||
j = buf[3], buf[3] = buf[7], buf[7] = buf[11], buf[11] = buf[15], buf[15] = j;
|
||||
j = buf[6], buf[6] = buf[14], buf[14] = j;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void aes_mixColumns(unsigned char *buf)
|
||||
{
|
||||
register unsigned char i, a, b, c, d, e;
|
||||
|
||||
for (i = 0; i < 16; i += 4)
|
||||
{
|
||||
a = buf[i];
|
||||
b = buf[i + 1];
|
||||
c = buf[i + 2];
|
||||
d = buf[i + 3];
|
||||
e = a ^ b ^ c ^ d;
|
||||
buf[i] ^= e ^ rj_xtime(a ^ b);
|
||||
buf[i + 1] ^= e ^ rj_xtime(b ^ c);
|
||||
buf[i + 2] ^= e ^ rj_xtime(c ^ d);
|
||||
buf[i + 3] ^= e ^ rj_xtime(d ^ a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void aes_mixColumns_inv(unsigned char *buf)
|
||||
{
|
||||
register unsigned char i, a, b, c, d, e, x, y, z;
|
||||
|
||||
for (i = 0; i < 16; i += 4)
|
||||
{
|
||||
a = buf[i];
|
||||
b = buf[i + 1];
|
||||
c = buf[i + 2];
|
||||
d = buf[i + 3];
|
||||
e = a ^ b ^ c ^ d;
|
||||
z = rj_xtime(e);
|
||||
x = e ^ rj_xtime(rj_xtime(z ^ a ^ c));
|
||||
y = e ^ rj_xtime(rj_xtime(z ^ b ^ d));
|
||||
buf[i] ^= x ^ rj_xtime(a ^ b);
|
||||
buf[i + 1] ^= y ^ rj_xtime(b ^ c);
|
||||
buf[i + 2] ^= x ^ rj_xtime(c ^ d);
|
||||
buf[i + 3] ^= y ^ rj_xtime(d ^ a);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void aes_expandEncKey(unsigned char *k, unsigned char *rc)
|
||||
{
|
||||
register unsigned char i;
|
||||
|
||||
k[0] ^= rj_sbox(k[29]) ^ (*rc);
|
||||
k[1] ^= rj_sbox(k[30]);
|
||||
k[2] ^= rj_sbox(k[31]);
|
||||
k[3] ^= rj_sbox(k[28]);
|
||||
*rc = rj_xtime( *rc);
|
||||
|
||||
for(i = 4; i < 16; i += 4) k[i] ^= k[i - 4], k[i + 1] ^= k[i - 3],
|
||||
k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1];
|
||||
k[16] ^= rj_sbox(k[12]);
|
||||
k[17] ^= rj_sbox(k[13]);
|
||||
k[18] ^= rj_sbox(k[14]);
|
||||
k[19] ^= rj_sbox(k[15]);
|
||||
|
||||
for(i = 20; i < 32; i += 4) k[i] ^= k[i - 4], k[i + 1] ^= k[i - 3],
|
||||
k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1];
|
||||
|
||||
}
|
||||
|
||||
|
||||
void aes_expandDecKey(unsigned char *k, unsigned char *rc)
|
||||
{
|
||||
unsigned char i;
|
||||
|
||||
for(i = 28; i > 16; i -= 4) k[i + 0] ^= k[i - 4], k[i + 1] ^= k[i - 3],
|
||||
k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1];
|
||||
|
||||
k[16] ^= rj_sbox(k[12]);
|
||||
k[17] ^= rj_sbox(k[13]);
|
||||
k[18] ^= rj_sbox(k[14]);
|
||||
k[19] ^= rj_sbox(k[15]);
|
||||
|
||||
for(i = 12; i > 0; i -= 4) k[i + 0] ^= k[i - 4], k[i + 1] ^= k[i - 3],
|
||||
k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1];
|
||||
|
||||
*rc = FD(*rc);
|
||||
k[0] ^= rj_sbox(k[29]) ^ (*rc);
|
||||
k[1] ^= rj_sbox(k[30]);
|
||||
k[2] ^= rj_sbox(k[31]);
|
||||
k[3] ^= rj_sbox(k[28]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void aes256_init(aes256_context *ctx, unsigned char *k)
|
||||
{
|
||||
unsigned char rcon = 1;
|
||||
register unsigned char i;
|
||||
|
||||
for (i = 0; i < sizeof(ctx->key); i++) ctx->enckey[i] = ctx->deckey[i] = k[i];
|
||||
for (i = 8; --i;) aes_expandEncKey(ctx->deckey, &rcon);
|
||||
}
|
||||
|
||||
|
||||
void aes256_done(aes256_context *ctx)
|
||||
{
|
||||
register unsigned char i;
|
||||
|
||||
for (i = 0; i < sizeof(ctx->key); i++)
|
||||
ctx->key[i] = ctx->enckey[i] = ctx->deckey[i] = 0;
|
||||
}
|
||||
|
||||
|
||||
void aes256_encrypt_ecb(aes256_context *ctx, unsigned char *buf)
|
||||
{
|
||||
unsigned char i, rcon;
|
||||
|
||||
aes_addRoundKey_cpy(buf, ctx->enckey, ctx->key);
|
||||
for(i = 1, rcon = 1; i < 14; ++i)
|
||||
{
|
||||
aes_subBytes(buf);
|
||||
aes_shiftRows(buf);
|
||||
aes_mixColumns(buf);
|
||||
if( i & 1 ) aes_addRoundKey( buf, &ctx->key[16]);
|
||||
else aes_expandEncKey(ctx->key, &rcon), aes_addRoundKey(buf, ctx->key);
|
||||
}
|
||||
aes_subBytes(buf);
|
||||
aes_shiftRows(buf);
|
||||
aes_expandEncKey(ctx->key, &rcon);
|
||||
aes_addRoundKey(buf, ctx->key);
|
||||
}
|
||||
|
||||
|
||||
void aes256_decrypt_ecb(aes256_context *ctx, unsigned char *buf)
|
||||
{
|
||||
unsigned char i, rcon;
|
||||
|
||||
aes_addRoundKey_cpy(buf, ctx->deckey, ctx->key);
|
||||
aes_shiftRows_inv(buf);
|
||||
aes_subBytes_inv(buf);
|
||||
|
||||
for (i = 14, rcon = 0x80; --i;)
|
||||
{
|
||||
if( ( i & 1 ) )
|
||||
{
|
||||
aes_expandDecKey(ctx->key, &rcon);
|
||||
aes_addRoundKey(buf, &ctx->key[16]);
|
||||
}
|
||||
else aes_addRoundKey(buf, ctx->key);
|
||||
aes_mixColumns_inv(buf);
|
||||
aes_shiftRows_inv(buf);
|
||||
aes_subBytes_inv(buf);
|
||||
}
|
||||
aes_addRoundKey( buf, ctx->key);
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
// :PATCH:
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "aes.h"
|
||||
#include "encryption_data.h"
|
||||
|
||||
|
||||
#define ENCRYPTION_TAG 0x04030501
|
||||
#define ENCRYPTION_HEADER_SIZE 16
|
||||
#define ENCRYPTION_KEY_SIZE 8
|
||||
#define ENCRYPTION_BUFFER_SIZE 16
|
||||
|
||||
|
||||
char *readText(const char *path, size_t &size)
|
||||
{
|
||||
FILE *file = fopen(path, "rb");
|
||||
if (!file)
|
||||
return NULL;
|
||||
|
||||
if (fseek(file, 0, SEEK_END)) {
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = ftell(file);
|
||||
char *text = new char[size + 1];
|
||||
text[size] = 0;
|
||||
|
||||
if (fseek(file, 0, SEEK_SET)) {
|
||||
fclose(file);
|
||||
delete [] text;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t read_size = fread(text, 1, size, file);
|
||||
fclose(file);
|
||||
|
||||
if (read_size != size) {
|
||||
delete [] text;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
bool writeText(const char *text, const size_t size, const char *path)
|
||||
{
|
||||
FILE *file = fopen(path, "wb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
size_t written_size = fwrite(text, 1, size, file);
|
||||
fclose(file);
|
||||
|
||||
if (written_size != size)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline const char *getFileName(const char *file_path)
|
||||
{
|
||||
const char *file_name = file_path;
|
||||
|
||||
for (int i=0; file_path[i]; ++i) {
|
||||
if (file_path[i] == '/' || file_path[i] == '\\')
|
||||
file_name = file_path + i + 1;
|
||||
}
|
||||
|
||||
return file_name;
|
||||
}
|
||||
|
||||
|
||||
static inline void makeKey(unsigned *key, const char *file_name)
|
||||
{
|
||||
unsigned int file_name_length = strlen(file_name);
|
||||
|
||||
key[0] = ENCRYPTION_KEY_0;
|
||||
key[1] = ENCRYPTION_KEY_1;
|
||||
key[2] = ENCRYPTION_KEY_2;
|
||||
key[3] = ENCRYPTION_KEY_3;
|
||||
key[4] = ENCRYPTION_KEY_4;
|
||||
key[5] = ENCRYPTION_KEY_5;
|
||||
key[6] = ENCRYPTION_KEY_6;
|
||||
key[7] = ENCRYPTION_KEY_7;
|
||||
|
||||
for (unsigned i = 0; i < file_name_length; ++i) {
|
||||
key[i % ENCRYPTION_KEY_SIZE] += file_name[i];
|
||||
}
|
||||
|
||||
key[0] = key[0] + ENCRYPTION_PRIME_7;
|
||||
key[1] = (key[1] ^ key[0] * ENCRYPTION_PRIME_1) + ENCRYPTION_PRIME_0;
|
||||
key[2] = (key[2] ^ key[1] * ENCRYPTION_PRIME_2) + ENCRYPTION_PRIME_1;
|
||||
key[3] = (key[3] ^ key[2] * ENCRYPTION_PRIME_3) + ENCRYPTION_PRIME_2;
|
||||
key[4] = (key[4] ^ key[3] * ENCRYPTION_PRIME_4) + ENCRYPTION_PRIME_3;
|
||||
key[5] = (key[5] ^ key[4] * ENCRYPTION_PRIME_5) + ENCRYPTION_PRIME_4;
|
||||
key[6] = (key[6] ^ key[5] * ENCRYPTION_PRIME_6) + ENCRYPTION_PRIME_5;
|
||||
key[7] = (key[7] ^ key[6] * ENCRYPTION_PRIME_7) + ENCRYPTION_PRIME_6;
|
||||
}
|
||||
|
||||
|
||||
static inline const bool isCryptedText(const char *text, size_t size)
|
||||
{
|
||||
return size >= 4 && *((unsigned *)text) == ENCRYPTION_TAG;
|
||||
}
|
||||
|
||||
|
||||
static inline const char *encryptText(const char *text, size_t &size, const char *file_path)
|
||||
{
|
||||
if (isCryptedText(text, size))
|
||||
return text;
|
||||
|
||||
const char *file_name = getFileName(file_path);
|
||||
|
||||
unsigned decrypted_size = size;
|
||||
unsigned encrypted_size = (((decrypted_size + ENCRYPTION_BUFFER_SIZE - 1) /
|
||||
ENCRYPTION_BUFFER_SIZE) * ENCRYPTION_BUFFER_SIZE);
|
||||
unsigned file_name_size = strlen(file_name) + 1;
|
||||
|
||||
size = ENCRYPTION_HEADER_SIZE + encrypted_size + file_name_size;
|
||||
|
||||
char *encrypted_text = new char[size];
|
||||
|
||||
*((unsigned *)encrypted_text) = ENCRYPTION_TAG;
|
||||
((unsigned *)encrypted_text)[1] = decrypted_size;
|
||||
((unsigned *)encrypted_text)[2] = encrypted_size;
|
||||
((unsigned *)encrypted_text)[3] = file_name_size;
|
||||
memcpy(encrypted_text + ENCRYPTION_HEADER_SIZE + encrypted_size, file_name, file_name_size);
|
||||
|
||||
unsigned key[ENCRYPTION_KEY_SIZE];
|
||||
makeKey(key, file_name);
|
||||
|
||||
unsigned char *input = (unsigned char *)text;
|
||||
unsigned char *output = (unsigned char *)(encrypted_text + ENCRYPTION_HEADER_SIZE);
|
||||
unsigned char buffer[ENCRYPTION_BUFFER_SIZE];
|
||||
|
||||
aes256_context ctx;
|
||||
aes256_init(&ctx, (unsigned char *)key);
|
||||
|
||||
for (unsigned i = 0; i < encrypted_size; i += ENCRYPTION_BUFFER_SIZE) {
|
||||
for (unsigned j = 0; j < ENCRYPTION_BUFFER_SIZE; ++j) {
|
||||
buffer[j] = (i + j < decrypted_size) ? input[i + j] : 0;
|
||||
}
|
||||
|
||||
aes256_encrypt_ecb(&ctx, buffer);
|
||||
|
||||
for (unsigned j = 0; j < ENCRYPTION_BUFFER_SIZE; ++j) {
|
||||
output[i + j] = buffer[j];
|
||||
}
|
||||
}
|
||||
|
||||
aes256_done(&ctx);
|
||||
|
||||
delete[] text;
|
||||
|
||||
return encrypted_text;
|
||||
}
|
||||
|
||||
|
||||
static inline const char *decryptText(const char *text, size_t &size, const char *file_path)
|
||||
{
|
||||
if (!isCryptedText(text, size))
|
||||
return text;
|
||||
|
||||
unsigned decrypted_size = ((unsigned *)text)[ 1 ];
|
||||
unsigned encrypted_size = ((unsigned *)text)[ 2 ];
|
||||
|
||||
const char *file_name = text + ENCRYPTION_HEADER_SIZE + encrypted_size;
|
||||
|
||||
size = decrypted_size;
|
||||
|
||||
char *decrypted_text = new char[size + 1];
|
||||
decrypted_text[size] = 0;
|
||||
|
||||
unsigned key[ENCRYPTION_KEY_SIZE];
|
||||
makeKey(key, file_name);
|
||||
|
||||
unsigned char *input = (unsigned char *)(text + ENCRYPTION_HEADER_SIZE);
|
||||
unsigned char *output = (unsigned char *)decrypted_text;
|
||||
unsigned char buffer[ENCRYPTION_BUFFER_SIZE];
|
||||
|
||||
aes256_context ctx;
|
||||
aes256_init(&ctx, (unsigned char *)key);
|
||||
|
||||
for (unsigned i = 0; i < encrypted_size; i += ENCRYPTION_BUFFER_SIZE) {
|
||||
for (unsigned j = 0; j < ENCRYPTION_BUFFER_SIZE; ++j) {
|
||||
buffer[j] = input[i + j];
|
||||
}
|
||||
|
||||
aes256_decrypt_ecb(&ctx, buffer);
|
||||
|
||||
for (unsigned j = 0; j < ENCRYPTION_BUFFER_SIZE; ++j) {
|
||||
if (i + j < decrypted_size)
|
||||
output[i + j] = buffer[j];
|
||||
}
|
||||
}
|
||||
|
||||
aes256_done(&ctx);
|
||||
|
||||
delete[] text;
|
||||
|
||||
return decrypted_text;
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#define ENCRYPTION_KEY_0 0x01234567
|
||||
#define ENCRYPTION_KEY_1 0x01234567
|
||||
#define ENCRYPTION_KEY_2 0x01234567
|
||||
#define ENCRYPTION_KEY_3 0x01234567
|
||||
#define ENCRYPTION_KEY_4 0x01234567
|
||||
#define ENCRYPTION_KEY_5 0x01234567
|
||||
#define ENCRYPTION_KEY_6 0x01234567
|
||||
#define ENCRYPTION_KEY_7 0x01234567
|
||||
#define ENCRYPTION_PRIME_0 0x01234567
|
||||
#define ENCRYPTION_PRIME_1 0x01234567
|
||||
#define ENCRYPTION_PRIME_2 0x01234567
|
||||
#define ENCRYPTION_PRIME_3 0x01234567
|
||||
#define ENCRYPTION_PRIME_4 0x01234567
|
||||
#define ENCRYPTION_PRIME_5 0x01234567
|
||||
#define ENCRYPTION_PRIME_6 0x01234567
|
||||
#define ENCRYPTION_PRIME_7 0x01234567
|
|
@ -176,12 +176,8 @@ void ScriptApiBase::loadScript(const std::string &script_path)
|
|||
|
||||
int error_handler = PUSH_ERROR_HANDLER(L);
|
||||
|
||||
bool ok;
|
||||
if (m_secure) {
|
||||
ok = ScriptApiSecurity::safeLoadFile(L, script_path.c_str());
|
||||
} else {
|
||||
ok = !luaL_loadfile(L, script_path.c_str());
|
||||
}
|
||||
bool ok = ScriptApiSecurity::safeLoadFile(L, script_path.c_str(), NULL, m_secure); // :PATCH:
|
||||
|
||||
ok = ok && !lua_pcall(L, 0, 0, error_handler);
|
||||
if (!ok) {
|
||||
std::string error_msg = readParam<std::string>(L, -1);
|
||||
|
|
|
@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
#include "server.h"
|
||||
#include "client/client.h"
|
||||
#include "settings.h"
|
||||
#include "encryption.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <string>
|
||||
|
@ -383,7 +384,34 @@ bool ScriptApiSecurity::safeLoadString(lua_State *L, const std::string &code, co
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char *display_name)
|
||||
extern "C"
|
||||
{
|
||||
int luaL_loadfile(lua_State *L, const char *path)
|
||||
{
|
||||
size_t size;
|
||||
const char *buffer = readText(path, size);
|
||||
int ret = 0;
|
||||
|
||||
if (buffer != NULL) {
|
||||
buffer = decryptText(buffer, size, path);
|
||||
ret = luaL_loadbuffer(L, buffer, size, path);
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
int ScriptApiSecurity::loadBuffer(lua_State *L, const char *buffer, size_t size,
|
||||
const char *name)
|
||||
{
|
||||
buffer = decryptText(buffer, size, name);
|
||||
|
||||
return luaL_loadbuffer(L, buffer, size, name);
|
||||
}
|
||||
|
||||
bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char *display_name,
|
||||
const bool secure)
|
||||
{
|
||||
FILE *fp;
|
||||
char *chunk_name;
|
||||
|
@ -405,13 +433,24 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char
|
|||
}
|
||||
|
||||
size_t start = 0;
|
||||
int c = std::getc(fp);
|
||||
if (c == '#') {
|
||||
// Skip the first line
|
||||
while ((c = std::getc(fp)) != EOF && c != '\n') {}
|
||||
if (c == '\n')
|
||||
std::getc(fp);
|
||||
start = std::ftell(fp);
|
||||
|
||||
if (secure && false) { // :PATCH:/
|
||||
int c = std::getc(fp);
|
||||
if (c == '#') {
|
||||
// Skip the first line
|
||||
while ((c = std::getc(fp)) != EOF && c != '\n');
|
||||
if (c == '\n') c = std::getc(fp);
|
||||
start = std::ftell(fp);
|
||||
}
|
||||
|
||||
if (c == LUA_SIGNATURE[0]) {
|
||||
lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
|
||||
std::fclose(fp);
|
||||
if (path) {
|
||||
delete [] chunk_name;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the file
|
||||
|
@ -426,7 +465,11 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char
|
|||
}
|
||||
|
||||
size_t size = std::ftell(fp) - start;
|
||||
std::string code(size, '\0');
|
||||
|
||||
|
||||
char *code = new char[size + 1]; // :PATCH:
|
||||
code[size] = 0; // :PATCH:
|
||||
|
||||
ret = std::fseek(fp, start, SEEK_SET);
|
||||
if (ret) {
|
||||
lua_pushfstring(L, "%s: %s", path, strerror(errno));
|
||||
|
@ -447,10 +490,20 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char
|
|||
return false;
|
||||
}
|
||||
|
||||
bool result = safeLoadString(L, code, chunk_name);
|
||||
if (path)
|
||||
const char *decrypted_code = decryptText(code, size, path); // :PATCH:
|
||||
|
||||
if (loadBuffer(L, decrypted_code, size, chunk_name)) {
|
||||
delete [] decrypted_code;
|
||||
return false;
|
||||
}
|
||||
|
||||
delete [] decrypted_code;
|
||||
|
||||
if (path) {
|
||||
delete [] chunk_name;
|
||||
return result;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -611,7 +664,14 @@ int ScriptApiSecurity::sl_g_load(lua_State *L)
|
|||
code += std::string(buf, len);
|
||||
lua_pop(L, 1); // Pop return value
|
||||
}
|
||||
if (!safeLoadString(L, code, chunk_name)) {
|
||||
|
||||
if (code[0] == LUA_SIGNATURE[0]) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (loadBuffer(L, code.data(), code.size(), chunk_name)) {
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, -2);
|
||||
return 2;
|
||||
|
@ -681,7 +741,13 @@ int ScriptApiSecurity::sl_g_loadstring(lua_State *L)
|
|||
|
||||
if (!safeLoadString(L, code_s, chunk_name)) {
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, -2);
|
||||
lua_pushliteral(L, "Bytecode prohibited when mod security is enabled.");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (loadBuffer(L, code, size, chunk_name)) {
|
||||
lua_pushnil(L);
|
||||
lua_insert(L, lua_gettop(L) - 1);
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
|
@ -797,4 +863,3 @@ int ScriptApiSecurity::sl_os_remove(lua_State *L)
|
|||
lua_call(L, 1, 2);
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,8 +52,12 @@ public:
|
|||
static bool isSecure(lua_State *L);
|
||||
// Loads a string as Lua code safely (doesn't allow bytecode).
|
||||
static bool safeLoadString(lua_State *L, const std::string &code, const char *chunk_name);
|
||||
// Loads a Lua code buffer.
|
||||
static int loadBuffer(lua_State *L, const char *buffer, size_t size,
|
||||
const char *name); // :PATCH:
|
||||
// Loads a file as Lua code safely (doesn't allow bytecode).
|
||||
static bool safeLoadFile(lua_State *L, const char *path, const char *display_name = NULL);
|
||||
static bool safeLoadFile(lua_State *L, const char *path, const char *display_name = NULL,
|
||||
const bool secure = true); // :PATCH:
|
||||
// Checks if mods are allowed to read (and optionally write) to the path
|
||||
static bool checkPath(lua_State *L, const char *path, bool write_required,
|
||||
bool *write_allowed=NULL);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
crypt
|
|
@ -0,0 +1,4 @@
|
|||
cmake_minimum_required (VERSION 2.6)
|
||||
project (crypt)
|
||||
include_directories("../../src/")
|
||||
add_executable(crypt crypt.cpp)
|
|
@ -0,0 +1,107 @@
|
|||
// :PATCH:
|
||||
|
||||
#include <cstddef>
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "encryption.h"
|
||||
|
||||
bool processFile(const char *path, const char option)
|
||||
{
|
||||
bool success = false;
|
||||
char *text;
|
||||
size_t size;
|
||||
|
||||
if (option == 'e') {
|
||||
text = readText(path, size);
|
||||
|
||||
if (text == NULL)
|
||||
return false;
|
||||
|
||||
const char *encrypted_text = encryptText(text, size, path);
|
||||
|
||||
if (encrypted_text != text) {
|
||||
printf("Encrypting file : %s\n", path);
|
||||
success = writeText(encrypted_text, size, path);
|
||||
}
|
||||
|
||||
delete[] encrypted_text;
|
||||
}
|
||||
else if (option == 'd') {
|
||||
text = readText(path, size);
|
||||
|
||||
if (text == NULL)
|
||||
return false;
|
||||
|
||||
const char *decrypted_text = decryptText(text, size, path);
|
||||
|
||||
if (decrypted_text != text) {
|
||||
printf("Decrypting file : %s\n", path);
|
||||
success = writeText(decrypted_text, size, path);
|
||||
}
|
||||
|
||||
delete[] decrypted_text;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
void processFiles(int count, char **paths, char option)
|
||||
{
|
||||
if ( count == 0 ) {
|
||||
size_t size;
|
||||
char *list = readText("CryptList.txt", size);
|
||||
|
||||
if (list == NULL) {
|
||||
puts("*** ERROR : can't read CryptList.txt");
|
||||
return;
|
||||
}
|
||||
|
||||
for (std::string path; *list; ++list) {
|
||||
if (*list == '\n') {
|
||||
if (path.size() > 0)
|
||||
processFile(path.c_str(),option);
|
||||
path = "";
|
||||
}
|
||||
else if (*list != '\r')
|
||||
path += *list;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (!processFile(paths[i], option)) {
|
||||
printf("*** ERROR : can't process file : %s\n", paths[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char option = 0;
|
||||
|
||||
--argc;
|
||||
++argv;
|
||||
|
||||
if (argc > 0 && (!strcmp(argv[0], "-e") || !strcmp(argv[0], "-d"))) {
|
||||
option = argv[0][1];
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
|
||||
if (option)
|
||||
processFiles(argc, argv, option);
|
||||
else {
|
||||
puts("*** ERROR : missing option");
|
||||
puts("Usage :");
|
||||
puts(" crypt -e file1 file2 ... : encrypt these files");
|
||||
puts(" crypt -d file1 file2 ... : decrypt these files");
|
||||
puts(" crypt -e : encrypt the files specified in CryptList.txt");
|
||||
puts(" crypt -d : decrypt the files specified in CryptList.txt");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh
|
||||
set -x
|
||||
cmake .
|
||||
make
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
set -x
|
||||
|
||||
cd ../../../games
|
||||
ls
|
||||
find . -name "*.lua" > CryptList.txt
|
||||
../util/crypt/crypt -d
|
|
@ -0,0 +1,3 @@
|
|||
./inventory.lua
|
||||
./init.lua
|
||||
./test.lua
|
|
@ -0,0 +1,52 @@
|
|||
-- Minetest 0.4 mod: default
|
||||
-- See README.txt for licensing and other information.
|
||||
|
||||
-- The API documentation in here was moved into game_api.txt
|
||||
|
||||
-- Definitions made by this mod that other mods can use too
|
||||
default = {}
|
||||
|
||||
default.LIGHT_MAX = 14
|
||||
|
||||
-- GUI related stuff
|
||||
default.gui_bg = "bgcolor[#080808BB;true]"
|
||||
default.gui_bg_img = "background[5,5;1,1;gui_formbg.png;true]"
|
||||
default.gui_slots = "listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]"
|
||||
|
||||
function default.get_hotbar_bg(x,y)
|
||||
local out = ""
|
||||
for i=0,7,1 do
|
||||
out = out .."image["..x+i..","..y..";1,1;gui_hb_bg.png]"
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
default.gui_survival_form = "size[8,8.5]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"list[current_player;main;0,4.25;8,1;]"..
|
||||
"list[current_player;main;0,5.5;8,3;8]"..
|
||||
"list[current_player;craft;1.75,0.5;3,3;]"..
|
||||
"list[current_player;craftpreview;5.75,1.5;1,1;]"..
|
||||
"image[4.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]"..
|
||||
"listring[current_player;main]"..
|
||||
"listring[current_player;craft]"..
|
||||
default.get_hotbar_bg(0,4.25)
|
||||
|
||||
-- Load files
|
||||
local default_path = minetest.get_modpath("default")
|
||||
|
||||
dofile(default_path.."/functions.lua")
|
||||
dofile(default_path.."/trees.lua")
|
||||
dofile(default_path.."/nodes.lua")
|
||||
dofile(default_path.."/furnace.lua")
|
||||
dofile(default_path.."/torch.lua")
|
||||
dofile(default_path.."/tools.lua")
|
||||
dofile(default_path.."/item_entity.lua")
|
||||
dofile(default_path.."/craftitems.lua")
|
||||
dofile(default_path.."/crafting.lua")
|
||||
dofile(default_path.."/mapgen.lua")
|
||||
dofile(default_path.."/aliases.lua")
|
||||
dofile(default_path.."/legacy.lua")
|
||||
dofile(default_path.."/hud.lua")
|
|
@ -0,0 +1,217 @@
|
|||
local player_inventory = {}
|
||||
|
||||
function creative.init_creative_inventory(player_name)
|
||||
player_inventory[player_name] = {
|
||||
size = 0,
|
||||
filter = "",
|
||||
start_i = 0
|
||||
}
|
||||
|
||||
return player_inventory[player_name]
|
||||
end
|
||||
|
||||
function creative.update_creative_inventory(player_name, tab_content)
|
||||
local creative_list = {}
|
||||
local inv = player_inventory[player_name] or
|
||||
creative.init_creative_inventory(player_name)
|
||||
|
||||
for name, def in pairs(tab_content) do
|
||||
if not (def.groups.not_in_creative_inventory == 1) and
|
||||
def.description and def.description ~= "" and
|
||||
(def.name:find(inv.filter, 1, true) or
|
||||
def.description:lower():find(inv.filter, 1, true)) then
|
||||
creative_list[#creative_list+1] = name
|
||||
end
|
||||
end
|
||||
|
||||
inv.size = #creative_list
|
||||
table.sort(creative_list)
|
||||
return creative_list
|
||||
end
|
||||
|
||||
-- Create the trash field
|
||||
local trash = minetest.create_detached_inventory("creative_trash", {
|
||||
-- Allow the stack to be placed and remove it in on_put()
|
||||
-- This allows the creative inventory to restore the stack
|
||||
allow_put = function(_, _, _, stack)
|
||||
return stack:get_count()
|
||||
end,
|
||||
on_put = function(inv, listname)
|
||||
inv:set_list(listname, {})
|
||||
end,
|
||||
})
|
||||
trash:set_size("main", 1)
|
||||
|
||||
function creative.register_tab(name, title, items)
|
||||
sfinv.register_page("creative:" .. name, {
|
||||
title = title,
|
||||
is_in_nav = function(self, player, context)
|
||||
return creative.is_enabled_for(player:get_player_name())
|
||||
end,
|
||||
|
||||
get = function(self, player, context)
|
||||
local player_name = player:get_player_name()
|
||||
local inv = player_inventory[player_name] or
|
||||
creative.init_creative_inventory(player_name)
|
||||
local ipp = inv.expand and 3*8 or 6*8
|
||||
local start_i = inv.start_i or 0
|
||||
local pagenum = math.floor(start_i / ipp + 1)
|
||||
local inv_items = creative.update_creative_inventory(player_name, items)
|
||||
local pagemax = math.ceil(inv.size / ipp)
|
||||
local offset = inv.expand and 3 or 6
|
||||
|
||||
local formspec =
|
||||
"label[6.2," .. offset .. ".35;" .. minetest.colorize("#FFFF00",
|
||||
tostring(pagenum)) .. " / " .. tostring(pagemax) .. "]" ..
|
||||
"image[4.06," .. offset .. ".4;0.8,0.8;creative_trash_icon.png]" ..
|
||||
"listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]" ..
|
||||
"list[current_player;main;0," .. (offset + 1) .. ".5;8,1;]" ..
|
||||
"list[detached:creative_trash;main;4," .. offset .. ".3;1,1;]" ..
|
||||
"listring[]" ..
|
||||
"button[5.4," .. offset .. ".2;0.8,0.9;creative_prev;<]" ..
|
||||
"button[7.25," .. offset .. ".2;0.8,0.9;creative_next;>]" ..
|
||||
"button[2.1," .. offset .. ".4;0.8,0.5;creative_search;?]" ..
|
||||
"button[2.75," .. offset .. ".4;0.8,0.5;creative_clear;X]" ..
|
||||
"image_button[3.78,8.55;0.45,0.4;creative_" ..
|
||||
(inv.expand and "less" or "more") ..
|
||||
".png;creative_" ..
|
||||
(inv.expand and "less" or "more") ..
|
||||
";;true;false;]" ..
|
||||
"image_button[7.55,8.55;0.45,0.4;creative_clear_inv.png;" ..
|
||||
"creative_clear_inv;;true;false;]" ..
|
||||
"tooltip[creative_search;Search]" ..
|
||||
"tooltip[creative_clear;Reset]" ..
|
||||
"listring[current_player;main]" ..
|
||||
"field_close_on_enter[creative_filter;false]" ..
|
||||
"field[0.3," .. offset .. ".5;2.2,1;creative_filter;;" ..
|
||||
minetest.formspec_escape(inv.filter) .. ";#444444]" ..
|
||||
default.get_hotbar_bg(0, (inv.expand and 4.5 or 7.5)) ..
|
||||
default.gui_bg .. default.gui_bg_img .. default.gui_slots
|
||||
|
||||
if inv.expand then
|
||||
formspec = formspec ..
|
||||
"list[current_player;main;0,5.5;8,3;8]"
|
||||
end
|
||||
|
||||
local first_item = (pagenum - 1) * ipp
|
||||
for i = first_item, first_item + ipp - 1 do
|
||||
local item_name = inv_items[i + 1]
|
||||
if not item_name then break end
|
||||
local X = i % 8
|
||||
local Y = (i % ipp - X) / 8 + 1
|
||||
|
||||
formspec = formspec ..
|
||||
"item_image_button[" .. X .. "," .. (Y - 1) ..
|
||||
";1.1,1.1;" .. item_name .. ";" .. item_name .. "_inv;]"
|
||||
end
|
||||
|
||||
return sfinv.make_formspec(player, context, formspec, false)
|
||||
end,
|
||||
|
||||
on_enter = function(self, player, context)
|
||||
local player_name = player:get_player_name()
|
||||
local inv = player_inventory[player_name]
|
||||
if inv then
|
||||
inv.start_i = 0
|
||||
end
|
||||
end,
|
||||
|
||||
on_player_receive_fields = function(self, player, context, fields)
|
||||
local player_name = player:get_player_name()
|
||||
local inv = player_inventory[player_name]
|
||||
local player_inv = player:get_inventory()
|
||||
local is_mapmaker = minetest.check_player_privs(player_name, "mapmaker")
|
||||
local is_teacher = minetest.check_player_privs(player_name, "teacher")
|
||||
assert(inv)
|
||||
|
||||
if fields.creative_clear then
|
||||
inv.start_i = 0
|
||||
inv.filter = ""
|
||||
creative.update_creative_inventory(player_name, items)
|
||||
sfinv.set_player_inventory_formspec(player, context)
|
||||
|
||||
elseif fields.creative_search or
|
||||
fields.key_enter_field == "creative_filter" then
|
||||
inv.start_i = 0
|
||||
inv.filter = fields.creative_filter:lower()
|
||||
creative.update_creative_inventory(player_name, items)
|
||||
sfinv.set_player_inventory_formspec(player, context)
|
||||
|
||||
elseif fields.creative_more or fields.creative_less then
|
||||
inv.expand = fields.creative_more and true or false
|
||||
sfinv.set_player_inventory_formspec(player, context)
|
||||
|
||||
elseif fields.creative_prev or fields.creative_next then
|
||||
local start_i = inv.start_i or 0
|
||||
local ipp = inv.expand and 3*8 or 6*8
|
||||
|
||||
if fields.creative_prev then
|
||||
start_i = start_i - ipp
|
||||
if start_i < 0 then
|
||||
start_i = inv.size - (inv.size % ipp)
|
||||
if inv.size == start_i then
|
||||
start_i = math.max(0, inv.size - ipp)
|
||||
end
|
||||
end
|
||||
elseif fields.creative_next then
|
||||
start_i = start_i + ipp
|
||||
if start_i >= inv.size then
|
||||
start_i = 0
|
||||
end
|
||||
end
|
||||
|
||||
inv.start_i = start_i
|
||||
sfinv.set_player_inventory_formspec(player, context)
|
||||
|
||||
elseif fields.creative_clear_inv then
|
||||
player_inv:set_list("main", {})
|
||||
|
||||
else for item in pairs(fields) do
|
||||
if item:find(":") then
|
||||
if not is_mapmaker and not is_teacher then
|
||||
minetest.chat_send_player(player_name,
|
||||
minetest.colorize("#FF0000",
|
||||
"ERROR: Privilege 'mapmaker' or 'teacher'" ..
|
||||
" required to get this item"))
|
||||
return
|
||||
end
|
||||
|
||||
local can_add = false
|
||||
for i = 1, 8 do
|
||||
if player_inv:get_stack("main", i):is_empty() then
|
||||
can_add = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if can_add or inv.expand then
|
||||
if item:sub(-4) == "_inv" then
|
||||
item = item:sub(1,-5)
|
||||
end
|
||||
|
||||
local stack = ItemStack(item)
|
||||
player_inv:add_item("main",
|
||||
item .. " " .. stack:get_stack_max())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
creative.update_creative_inventory(
|
||||
player:get_player_name(), minetest.registered_items)
|
||||
end)
|
||||
|
||||
creative.register_tab("all", "Items", minetest.registered_items)
|
||||
|
||||
local old_homepage_name = sfinv.get_homepage_name
|
||||
function sfinv.get_homepage_name(player)
|
||||
if creative.is_enabled_for(player:get_player_name()) then
|
||||
return "creative:all"
|
||||
else
|
||||
return old_homepage_name(player)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
Gallia est omnis divisa in partes tres, quarum unam incolunt Belgae, aliam Aquitani, tertiam qui ipsorum lingua Celtae, nostra Galli appellantur.
|
||||
Hi omnes lingua, institutis, legibus inter se differunt. Gallos ab Aquitanis Garumna flumen, a Belgis Matrona et Sequana dividit.
|
||||
Horum omnium fortissimi sunt Belgae, propterea quod a cultu atque humanitate provinciae longissime absunt.
|
||||
Minimeque ad eos mercatores saepe commeant atque ea quae ad effeminandos animos pertinent important.
|
||||
Proximique sunt Germanis, qui trans Rhenum incolunt, quibuscum continenter bellum gerunt.
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
set -x
|
||||
|
||||
cd ../../../games
|
||||
ls
|
||||
find . -name "*.lua" > CryptList.txt
|
||||
../util/crypt/crypt -e
|
|
@ -0,0 +1,3 @@
|
|||
./inventory.lua
|
||||
./init.lua
|
||||
./test.lua
|
|
@ -0,0 +1,52 @@
|
|||
-- Minetest 0.4 mod: default
|
||||
-- See README.txt for licensing and other information.
|
||||
|
||||
-- The API documentation in here was moved into game_api.txt
|
||||
|
||||
-- Definitions made by this mod that other mods can use too
|
||||
default = {}
|
||||
|
||||
default.LIGHT_MAX = 14
|
||||
|
||||
-- GUI related stuff
|
||||
default.gui_bg = "bgcolor[#080808BB;true]"
|
||||
default.gui_bg_img = "background[5,5;1,1;gui_formbg.png;true]"
|
||||
default.gui_slots = "listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]"
|
||||
|
||||
function default.get_hotbar_bg(x,y)
|
||||
local out = ""
|
||||
for i=0,7,1 do
|
||||
out = out .."image["..x+i..","..y..";1,1;gui_hb_bg.png]"
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
default.gui_survival_form = "size[8,8.5]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"list[current_player;main;0,4.25;8,1;]"..
|
||||
"list[current_player;main;0,5.5;8,3;8]"..
|
||||
"list[current_player;craft;1.75,0.5;3,3;]"..
|
||||
"list[current_player;craftpreview;5.75,1.5;1,1;]"..
|
||||
"image[4.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]"..
|
||||
"listring[current_player;main]"..
|
||||
"listring[current_player;craft]"..
|
||||
default.get_hotbar_bg(0,4.25)
|
||||
|
||||
-- Load files
|
||||
local default_path = minetest.get_modpath("default")
|
||||
|
||||
dofile(default_path.."/functions.lua")
|
||||
dofile(default_path.."/trees.lua")
|
||||
dofile(default_path.."/nodes.lua")
|
||||
dofile(default_path.."/furnace.lua")
|
||||
dofile(default_path.."/torch.lua")
|
||||
dofile(default_path.."/tools.lua")
|
||||
dofile(default_path.."/item_entity.lua")
|
||||
dofile(default_path.."/craftitems.lua")
|
||||
dofile(default_path.."/crafting.lua")
|
||||
dofile(default_path.."/mapgen.lua")
|
||||
dofile(default_path.."/aliases.lua")
|
||||
dofile(default_path.."/legacy.lua")
|
||||
dofile(default_path.."/hud.lua")
|
|
@ -0,0 +1,217 @@
|
|||
local player_inventory = {}
|
||||
|
||||
function creative.init_creative_inventory(player_name)
|
||||
player_inventory[player_name] = {
|
||||
size = 0,
|
||||
filter = "",
|
||||
start_i = 0
|
||||
}
|
||||
|
||||
return player_inventory[player_name]
|
||||
end
|
||||
|
||||
function creative.update_creative_inventory(player_name, tab_content)
|
||||
local creative_list = {}
|
||||
local inv = player_inventory[player_name] or
|
||||
creative.init_creative_inventory(player_name)
|
||||
|
||||
for name, def in pairs(tab_content) do
|
||||
if not (def.groups.not_in_creative_inventory == 1) and
|
||||
def.description and def.description ~= "" and
|
||||
(def.name:find(inv.filter, 1, true) or
|
||||
def.description:lower():find(inv.filter, 1, true)) then
|
||||
creative_list[#creative_list+1] = name
|
||||
end
|
||||
end
|
||||
|
||||
inv.size = #creative_list
|
||||
table.sort(creative_list)
|
||||
return creative_list
|
||||
end
|
||||
|
||||
-- Create the trash field
|
||||
local trash = minetest.create_detached_inventory("creative_trash", {
|
||||
-- Allow the stack to be placed and remove it in on_put()
|
||||
-- This allows the creative inventory to restore the stack
|
||||
allow_put = function(_, _, _, stack)
|
||||
return stack:get_count()
|
||||
end,
|
||||
on_put = function(inv, listname)
|
||||
inv:set_list(listname, {})
|
||||
end,
|
||||
})
|
||||
trash:set_size("main", 1)
|
||||
|
||||
function creative.register_tab(name, title, items)
|
||||
sfinv.register_page("creative:" .. name, {
|
||||
title = title,
|
||||
is_in_nav = function(self, player, context)
|
||||
return creative.is_enabled_for(player:get_player_name())
|
||||
end,
|
||||
|
||||
get = function(self, player, context)
|
||||
local player_name = player:get_player_name()
|
||||
local inv = player_inventory[player_name] or
|
||||
creative.init_creative_inventory(player_name)
|
||||
local ipp = inv.expand and 3*8 or 6*8
|
||||
local start_i = inv.start_i or 0
|
||||
local pagenum = math.floor(start_i / ipp + 1)
|
||||
local inv_items = creative.update_creative_inventory(player_name, items)
|
||||
local pagemax = math.ceil(inv.size / ipp)
|
||||
local offset = inv.expand and 3 or 6
|
||||
|
||||
local formspec =
|
||||
"label[6.2," .. offset .. ".35;" .. minetest.colorize("#FFFF00",
|
||||
tostring(pagenum)) .. " / " .. tostring(pagemax) .. "]" ..
|
||||
"image[4.06," .. offset .. ".4;0.8,0.8;creative_trash_icon.png]" ..
|
||||
"listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]" ..
|
||||
"list[current_player;main;0," .. (offset + 1) .. ".5;8,1;]" ..
|
||||
"list[detached:creative_trash;main;4," .. offset .. ".3;1,1;]" ..
|
||||
"listring[]" ..
|
||||
"button[5.4," .. offset .. ".2;0.8,0.9;creative_prev;<]" ..
|
||||
"button[7.25," .. offset .. ".2;0.8,0.9;creative_next;>]" ..
|
||||
"button[2.1," .. offset .. ".4;0.8,0.5;creative_search;?]" ..
|
||||
"button[2.75," .. offset .. ".4;0.8,0.5;creative_clear;X]" ..
|
||||
"image_button[3.78,8.55;0.45,0.4;creative_" ..
|
||||
(inv.expand and "less" or "more") ..
|
||||
".png;creative_" ..
|
||||
(inv.expand and "less" or "more") ..
|
||||
";;true;false;]" ..
|
||||
"image_button[7.55,8.55;0.45,0.4;creative_clear_inv.png;" ..
|
||||
"creative_clear_inv;;true;false;]" ..
|
||||
"tooltip[creative_search;Search]" ..
|
||||
"tooltip[creative_clear;Reset]" ..
|
||||
"listring[current_player;main]" ..
|
||||
"field_close_on_enter[creative_filter;false]" ..
|
||||
"field[0.3," .. offset .. ".5;2.2,1;creative_filter;;" ..
|
||||
minetest.formspec_escape(inv.filter) .. ";#444444]" ..
|
||||
default.get_hotbar_bg(0, (inv.expand and 4.5 or 7.5)) ..
|
||||
default.gui_bg .. default.gui_bg_img .. default.gui_slots
|
||||
|
||||
if inv.expand then
|
||||
formspec = formspec ..
|
||||
"list[current_player;main;0,5.5;8,3;8]"
|
||||
end
|
||||
|
||||
local first_item = (pagenum - 1) * ipp
|
||||
for i = first_item, first_item + ipp - 1 do
|
||||
local item_name = inv_items[i + 1]
|
||||
if not item_name then break end
|
||||
local X = i % 8
|
||||
local Y = (i % ipp - X) / 8 + 1
|
||||
|
||||
formspec = formspec ..
|
||||
"item_image_button[" .. X .. "," .. (Y - 1) ..
|
||||
";1.1,1.1;" .. item_name .. ";" .. item_name .. "_inv;]"
|
||||
end
|
||||
|
||||
return sfinv.make_formspec(player, context, formspec, false)
|
||||
end,
|
||||
|
||||
on_enter = function(self, player, context)
|
||||
local player_name = player:get_player_name()
|
||||
local inv = player_inventory[player_name]
|
||||
if inv then
|
||||
inv.start_i = 0
|
||||
end
|
||||
end,
|
||||
|
||||
on_player_receive_fields = function(self, player, context, fields)
|
||||
local player_name = player:get_player_name()
|
||||
local inv = player_inventory[player_name]
|
||||
local player_inv = player:get_inventory()
|
||||
local is_mapmaker = minetest.check_player_privs(player_name, "mapmaker")
|
||||
local is_teacher = minetest.check_player_privs(player_name, "teacher")
|
||||
assert(inv)
|
||||
|
||||
if fields.creative_clear then
|
||||
inv.start_i = 0
|
||||
inv.filter = ""
|
||||
creative.update_creative_inventory(player_name, items)
|
||||
sfinv.set_player_inventory_formspec(player, context)
|
||||
|
||||
elseif fields.creative_search or
|
||||
fields.key_enter_field == "creative_filter" then
|
||||
inv.start_i = 0
|
||||
inv.filter = fields.creative_filter:lower()
|
||||
creative.update_creative_inventory(player_name, items)
|
||||
sfinv.set_player_inventory_formspec(player, context)
|
||||
|
||||
elseif fields.creative_more or fields.creative_less then
|
||||
inv.expand = fields.creative_more and true or false
|
||||
sfinv.set_player_inventory_formspec(player, context)
|
||||
|
||||
elseif fields.creative_prev or fields.creative_next then
|
||||
local start_i = inv.start_i or 0
|
||||
local ipp = inv.expand and 3*8 or 6*8
|
||||
|
||||
if fields.creative_prev then
|
||||
start_i = start_i - ipp
|
||||
if start_i < 0 then
|
||||
start_i = inv.size - (inv.size % ipp)
|
||||
if inv.size == start_i then
|
||||
start_i = math.max(0, inv.size - ipp)
|
||||
end
|
||||
end
|
||||
elseif fields.creative_next then
|
||||
start_i = start_i + ipp
|
||||
if start_i >= inv.size then
|
||||
start_i = 0
|
||||
end
|
||||
end
|
||||
|
||||
inv.start_i = start_i
|
||||
sfinv.set_player_inventory_formspec(player, context)
|
||||
|
||||
elseif fields.creative_clear_inv then
|
||||
player_inv:set_list("main", {})
|
||||
|
||||
else for item in pairs(fields) do
|
||||
if item:find(":") then
|
||||
if not is_mapmaker and not is_teacher then
|
||||
minetest.chat_send_player(player_name,
|
||||
minetest.colorize("#FF0000",
|
||||
"ERROR: Privilege 'mapmaker' or 'teacher'" ..
|
||||
" required to get this item"))
|
||||
return
|
||||
end
|
||||
|
||||
local can_add = false
|
||||
for i = 1, 8 do
|
||||
if player_inv:get_stack("main", i):is_empty() then
|
||||
can_add = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if can_add or inv.expand then
|
||||
if item:sub(-4) == "_inv" then
|
||||
item = item:sub(1,-5)
|
||||
end
|
||||
|
||||
local stack = ItemStack(item)
|
||||
player_inv:add_item("main",
|
||||
item .. " " .. stack:get_stack_max())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
creative.update_creative_inventory(
|
||||
player:get_player_name(), minetest.registered_items)
|
||||
end)
|
||||
|
||||
creative.register_tab("all", "Items", minetest.registered_items)
|
||||
|
||||
local old_homepage_name = sfinv.get_homepage_name
|
||||
function sfinv.get_homepage_name(player)
|
||||
if creative.is_enabled_for(player:get_player_name()) then
|
||||
return "creative:all"
|
||||
else
|
||||
return old_homepage_name(player)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
Gallia est omnis divisa in partes tres, quarum unam incolunt Belgae, aliam Aquitani, tertiam qui ipsorum lingua Celtae, nostra Galli appellantur.
|
||||
Hi omnes lingua, institutis, legibus inter se differunt. Gallos ab Aquitanis Garumna flumen, a Belgis Matrona et Sequana dividit.
|
||||
Horum omnium fortissimi sunt Belgae, propterea quod a cultu atque humanitate provinciae longissime absunt.
|
||||
Minimeque ad eos mercatores saepe commeant atque ea quae ad effeminandos animos pertinent important.
|
||||
Proximique sunt Germanis, qui trans Rhenum incolunt, quibuscum continenter bellum gerunt.
|
|
@ -0,0 +1,52 @@
|
|||
-- Minetest 0.4 mod: default
|
||||
-- See README.txt for licensing and other information.
|
||||
|
||||
-- The API documentation in here was moved into game_api.txt
|
||||
|
||||
-- Definitions made by this mod that other mods can use too
|
||||
default = {}
|
||||
|
||||
default.LIGHT_MAX = 14
|
||||
|
||||
-- GUI related stuff
|
||||
default.gui_bg = "bgcolor[#080808BB;true]"
|
||||
default.gui_bg_img = "background[5,5;1,1;gui_formbg.png;true]"
|
||||
default.gui_slots = "listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]"
|
||||
|
||||
function default.get_hotbar_bg(x,y)
|
||||
local out = ""
|
||||
for i=0,7,1 do
|
||||
out = out .."image["..x+i..","..y..";1,1;gui_hb_bg.png]"
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
default.gui_survival_form = "size[8,8.5]"..
|
||||
default.gui_bg..
|
||||
default.gui_bg_img..
|
||||
default.gui_slots..
|
||||
"list[current_player;main;0,4.25;8,1;]"..
|
||||
"list[current_player;main;0,5.5;8,3;8]"..
|
||||
"list[current_player;craft;1.75,0.5;3,3;]"..
|
||||
"list[current_player;craftpreview;5.75,1.5;1,1;]"..
|
||||
"image[4.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]"..
|
||||
"listring[current_player;main]"..
|
||||
"listring[current_player;craft]"..
|
||||
default.get_hotbar_bg(0,4.25)
|
||||
|
||||
-- Load files
|
||||
local default_path = minetest.get_modpath("default")
|
||||
|
||||
dofile(default_path.."/functions.lua")
|
||||
dofile(default_path.."/trees.lua")
|
||||
dofile(default_path.."/nodes.lua")
|
||||
dofile(default_path.."/furnace.lua")
|
||||
dofile(default_path.."/torch.lua")
|
||||
dofile(default_path.."/tools.lua")
|
||||
dofile(default_path.."/item_entity.lua")
|
||||
dofile(default_path.."/craftitems.lua")
|
||||
dofile(default_path.."/crafting.lua")
|
||||
dofile(default_path.."/mapgen.lua")
|
||||
dofile(default_path.."/aliases.lua")
|
||||
dofile(default_path.."/legacy.lua")
|
||||
dofile(default_path.."/hud.lua")
|
|
@ -0,0 +1,217 @@
|
|||
local player_inventory = {}
|
||||
|
||||
function creative.init_creative_inventory(player_name)
|
||||
player_inventory[player_name] = {
|
||||
size = 0,
|
||||
filter = "",
|
||||
start_i = 0
|
||||
}
|
||||
|
||||
return player_inventory[player_name]
|
||||
end
|
||||
|
||||
function creative.update_creative_inventory(player_name, tab_content)
|
||||
local creative_list = {}
|
||||
local inv = player_inventory[player_name] or
|
||||
creative.init_creative_inventory(player_name)
|
||||
|
||||
for name, def in pairs(tab_content) do
|
||||
if not (def.groups.not_in_creative_inventory == 1) and
|
||||
def.description and def.description ~= "" and
|
||||
(def.name:find(inv.filter, 1, true) or
|
||||
def.description:lower():find(inv.filter, 1, true)) then
|
||||
creative_list[#creative_list+1] = name
|
||||
end
|
||||
end
|
||||
|
||||
inv.size = #creative_list
|
||||
table.sort(creative_list)
|
||||
return creative_list
|
||||
end
|
||||
|
||||
-- Create the trash field
|
||||
local trash = minetest.create_detached_inventory("creative_trash", {
|
||||
-- Allow the stack to be placed and remove it in on_put()
|
||||
-- This allows the creative inventory to restore the stack
|
||||
allow_put = function(_, _, _, stack)
|
||||
return stack:get_count()
|
||||
end,
|
||||
on_put = function(inv, listname)
|
||||
inv:set_list(listname, {})
|
||||
end,
|
||||
})
|
||||
trash:set_size("main", 1)
|
||||
|
||||
function creative.register_tab(name, title, items)
|
||||
sfinv.register_page("creative:" .. name, {
|
||||
title = title,
|
||||
is_in_nav = function(self, player, context)
|
||||
return creative.is_enabled_for(player:get_player_name())
|
||||
end,
|
||||
|
||||
get = function(self, player, context)
|
||||
local player_name = player:get_player_name()
|
||||
local inv = player_inventory[player_name] or
|
||||
creative.init_creative_inventory(player_name)
|
||||
local ipp = inv.expand and 3*8 or 6*8
|
||||
local start_i = inv.start_i or 0
|
||||
local pagenum = math.floor(start_i / ipp + 1)
|
||||
local inv_items = creative.update_creative_inventory(player_name, items)
|
||||
local pagemax = math.ceil(inv.size / ipp)
|
||||
local offset = inv.expand and 3 or 6
|
||||
|
||||
local formspec =
|
||||
"label[6.2," .. offset .. ".35;" .. minetest.colorize("#FFFF00",
|
||||
tostring(pagenum)) .. " / " .. tostring(pagemax) .. "]" ..
|
||||
"image[4.06," .. offset .. ".4;0.8,0.8;creative_trash_icon.png]" ..
|
||||
"listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]" ..
|
||||
"list[current_player;main;0," .. (offset + 1) .. ".5;8,1;]" ..
|
||||
"list[detached:creative_trash;main;4," .. offset .. ".3;1,1;]" ..
|
||||
"listring[]" ..
|
||||
"button[5.4," .. offset .. ".2;0.8,0.9;creative_prev;<]" ..
|
||||
"button[7.25," .. offset .. ".2;0.8,0.9;creative_next;>]" ..
|
||||
"button[2.1," .. offset .. ".4;0.8,0.5;creative_search;?]" ..
|
||||
"button[2.75," .. offset .. ".4;0.8,0.5;creative_clear;X]" ..
|
||||
"image_button[3.78,8.55;0.45,0.4;creative_" ..
|
||||
(inv.expand and "less" or "more") ..
|
||||
".png;creative_" ..
|
||||
(inv.expand and "less" or "more") ..
|
||||
";;true;false;]" ..
|
||||
"image_button[7.55,8.55;0.45,0.4;creative_clear_inv.png;" ..
|
||||
"creative_clear_inv;;true;false;]" ..
|
||||
"tooltip[creative_search;Search]" ..
|
||||
"tooltip[creative_clear;Reset]" ..
|
||||
"listring[current_player;main]" ..
|
||||
"field_close_on_enter[creative_filter;false]" ..
|
||||
"field[0.3," .. offset .. ".5;2.2,1;creative_filter;;" ..
|
||||
minetest.formspec_escape(inv.filter) .. ";#444444]" ..
|
||||
default.get_hotbar_bg(0, (inv.expand and 4.5 or 7.5)) ..
|
||||
default.gui_bg .. default.gui_bg_img .. default.gui_slots
|
||||
|
||||
if inv.expand then
|
||||
formspec = formspec ..
|
||||
"list[current_player;main;0,5.5;8,3;8]"
|
||||
end
|
||||
|
||||
local first_item = (pagenum - 1) * ipp
|
||||
for i = first_item, first_item + ipp - 1 do
|
||||
local item_name = inv_items[i + 1]
|
||||
if not item_name then break end
|
||||
local X = i % 8
|
||||
local Y = (i % ipp - X) / 8 + 1
|
||||
|
||||
formspec = formspec ..
|
||||
"item_image_button[" .. X .. "," .. (Y - 1) ..
|
||||
";1.1,1.1;" .. item_name .. ";" .. item_name .. "_inv;]"
|
||||
end
|
||||
|
||||
return sfinv.make_formspec(player, context, formspec, false)
|
||||
end,
|
||||
|
||||
on_enter = function(self, player, context)
|
||||
local player_name = player:get_player_name()
|
||||
local inv = player_inventory[player_name]
|
||||
if inv then
|
||||
inv.start_i = 0
|
||||
end
|
||||
end,
|
||||
|
||||
on_player_receive_fields = function(self, player, context, fields)
|
||||
local player_name = player:get_player_name()
|
||||
local inv = player_inventory[player_name]
|
||||
local player_inv = player:get_inventory()
|
||||
local is_mapmaker = minetest.check_player_privs(player_name, "mapmaker")
|
||||
local is_teacher = minetest.check_player_privs(player_name, "teacher")
|
||||
assert(inv)
|
||||
|
||||
if fields.creative_clear then
|
||||
inv.start_i = 0
|
||||
inv.filter = ""
|
||||
creative.update_creative_inventory(player_name, items)
|
||||
sfinv.set_player_inventory_formspec(player, context)
|
||||
|
||||
elseif fields.creative_search or
|
||||
fields.key_enter_field == "creative_filter" then
|
||||
inv.start_i = 0
|
||||
inv.filter = fields.creative_filter:lower()
|
||||
creative.update_creative_inventory(player_name, items)
|
||||
sfinv.set_player_inventory_formspec(player, context)
|
||||
|
||||
elseif fields.creative_more or fields.creative_less then
|
||||
inv.expand = fields.creative_more and true or false
|
||||
sfinv.set_player_inventory_formspec(player, context)
|
||||
|
||||
elseif fields.creative_prev or fields.creative_next then
|
||||
local start_i = inv.start_i or 0
|
||||
local ipp = inv.expand and 3*8 or 6*8
|
||||
|
||||
if fields.creative_prev then
|
||||
start_i = start_i - ipp
|
||||
if start_i < 0 then
|
||||
start_i = inv.size - (inv.size % ipp)
|
||||
if inv.size == start_i then
|
||||
start_i = math.max(0, inv.size - ipp)
|
||||
end
|
||||
end
|
||||
elseif fields.creative_next then
|
||||
start_i = start_i + ipp
|
||||
if start_i >= inv.size then
|
||||
start_i = 0
|
||||
end
|
||||
end
|
||||
|
||||
inv.start_i = start_i
|
||||
sfinv.set_player_inventory_formspec(player, context)
|
||||
|
||||
elseif fields.creative_clear_inv then
|
||||
player_inv:set_list("main", {})
|
||||
|
||||
else for item in pairs(fields) do
|
||||
if item:find(":") then
|
||||
if not is_mapmaker and not is_teacher then
|
||||
minetest.chat_send_player(player_name,
|
||||
minetest.colorize("#FF0000",
|
||||
"ERROR: Privilege 'mapmaker' or 'teacher'" ..
|
||||
" required to get this item"))
|
||||
return
|
||||
end
|
||||
|
||||
local can_add = false
|
||||
for i = 1, 8 do
|
||||
if player_inv:get_stack("main", i):is_empty() then
|
||||
can_add = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if can_add or inv.expand then
|
||||
if item:sub(-4) == "_inv" then
|
||||
item = item:sub(1,-5)
|
||||
end
|
||||
|
||||
local stack = ItemStack(item)
|
||||
player_inv:add_item("main",
|
||||
item .. " " .. stack:get_stack_max())
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
creative.update_creative_inventory(
|
||||
player:get_player_name(), minetest.registered_items)
|
||||
end)
|
||||
|
||||
creative.register_tab("all", "Items", minetest.registered_items)
|
||||
|
||||
local old_homepage_name = sfinv.get_homepage_name
|
||||
function sfinv.get_homepage_name(player)
|
||||
if creative.is_enabled_for(player:get_player_name()) then
|
||||
return "creative:all"
|
||||
else
|
||||
return old_homepage_name(player)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/sh
|
||||
set -x
|
||||
|
||||
cat *.lua
|
||||
|
||||
mkdir -p encrypted
|
||||
rm encrypted/*.lua
|
||||
cp *.lua encrypted
|
||||
./crypt -e encrypted/*.lua
|
||||
|
||||
mkdir -p decrypted
|
||||
rm decrypted/*.lua
|
||||
cp encrypted/*.lua decrypted
|
||||
./crypt -d decrypted/*.lua
|
||||
cat decrypted/*.lua
|
||||
|
||||
cd encrypted
|
||||
find . -name "*.lua" > CryptList.txt
|
||||
../../crypt -d
|
||||
cat *.lua
|
||||
|
||||
cd ../decrypted
|
||||
find . -name "*.lua" > CryptList.txt
|
||||
../../crypt -e
|
||||
../../crypt -d
|
||||
cat *.lua
|
|
@ -0,0 +1,5 @@
|
|||
Gallia est omnis divisa in partes tres, quarum unam incolunt Belgae, aliam Aquitani, tertiam qui ipsorum lingua Celtae, nostra Galli appellantur.
|
||||
Hi omnes lingua, institutis, legibus inter se differunt. Gallos ab Aquitanis Garumna flumen, a Belgis Matrona et Sequana dividit.
|
||||
Horum omnium fortissimi sunt Belgae, propterea quod a cultu atque humanitate provinciae longissime absunt.
|
||||
Minimeque ad eos mercatores saepe commeant atque ea quae ad effeminandos animos pertinent important.
|
||||
Proximique sunt Germanis, qui trans Rhenum incolunt, quibuscum continenter bellum gerunt.
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
find . -name "*.lua" -exec md5sum '{}' \; \
|
||||
| awk 'BEGIN{FS=" ./";OFS=""}{print "update maps set mods_hash_md5 = \"",$1,"\" where url_download = \"http://assets.kidscode.com/master/",$2,"\";"}'
|
|
@ -0,0 +1 @@
|
|||
-- A
|
|
@ -0,0 +1 @@
|
|||
-- B
|
|
@ -0,0 +1 @@
|
|||
-- X
|
|
@ -0,0 +1,3 @@
|
|||
replace into DATABASE.TABLE(Filename,Signature) values("test/A/a.lua","a3e6c7ee394d4577cf03ae287d5d3c2b");
|
||||
replace into DATABASE.TABLE(Filename,Signature) values("test/B/b.lua","33b057c52767af2ea032048bf4e73b79");
|
||||
replace into DATABASE.TABLE(Filename,Signature) values("test/x.lua","c50f510b0072cb9467e0d4c43f96fcae");
|
Loading…
Reference in New Issue