1
0

Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Tiger Wang 2013-08-16 11:25:53 +01:00
commit cbde4f546a
110 changed files with 32148 additions and 36389 deletions

View File

@ -1,12 +1,29 @@
Code Stuff
----------
* No magic numbers, use named constants like E_ITEM...
* Please use tabs for indentation and spaces for alignment.
* No magic numbers, use named constants:
- E_ITEM_XXX, E_BLOCK_XXX and E_META_XXX for items and blocks
- E_ENTITY_TYPE_XXX for mob types
- dimNether, dimOverworld and dimEnd for world dimension
- gmSurvival, gmCreative, gmAdventure for game modes
- wSunny, wRain, wThunderstorm for weather
- cChunkDef::Width, cChunkDef::Height for chunk dimensions (C++)
- etc.
* Instead of checking for specific value, use Is functions, if available:
- cPlayer:IsGameModeCreative() instead of (cPlayer:GetGameMode() == gmCreative)
* Please use tabs for indentation and spaces for alignment. This means that if it's at line start, it's a tab; if it's in the middle of a line, it's a space
* Alpha-sort stuff that makes sense alpha-sorting - long lists of similar items etc.
* Keep individual functions spaced out by 5 empty lines, this enhances readability and makes navigation in the source file easier.
* Add those extra parentheses to conditions, especially in C++
- "if ((a == 1) && ((b == 2) || (c == 3)))" instead of ambiguous "if (a == 1 && b == 2 || c == 3)"
- This helps prevent mistakes such as "if (a & 1 == 0)"
* White space is free, so use it freely
- "freely" as in "plentifully", not "arbitrarily"
Copyright
---------
Your work should be licensed under the apache license, and you should add yourself to the CONTRIBUTORS file.
Your work should be licensed under the Apache license, and you should add yourself to the CONTRIBUTORS file.
If your work is not licensed under the apache license, then it must be compatible and marked as such.
If your work is not licensed under the Apache license, then it must be compatible and marked as such. Note that only plugins may choose a different license; MC-server's internals need to be single-license.

View File

@ -9,6 +9,8 @@ tigerw
bearbin
Lapayo
rs2k
Duralex
Duralex
mtilden
Luksor
If you feel you have contributed enough to be included in this list, just put in a PR including yourself.
Please add yourself to this list if you contribute to MCServer.

7
ClonePlugins.cmd Normal file
View File

@ -0,0 +1,7 @@
:: ClonePlugins.cmd
:: Clones the base plugins from their respective repos into proper folders (./MCServer/Plugins
git clone https://github.com/mc-server/Core.git ./MCServer/Plugins/Core
git clone https://github.com/mc-server/ProtectionAreas.git ./MCServer/Plugins/ProtectionAreas

View File

@ -1,4 +1,4 @@
Compilation Copyright (c) 1995-2010 by Wei Dai. All rights reserved.
Compilation Copyright (c) 1995-2013 by Wei Dai. All rights reserved.
This copyright applies only to this software distribution package
as a compilation, and does not imply a copyright on any particular
file in the package.
@ -21,42 +21,31 @@ Paulo Baretto - rijndael.cpp, skipjack.cpp, square.cpp
Richard De Moliner - safer.cpp
Matthew Skala - twofish.cpp
Kevin Springle - camellia.cpp, shacal2.cpp, ttmac.cpp, whrlpool.cpp, ripemd.cpp
Ronny Van Keer - sha3.cpp
Permission to use, copy, modify, and distribute this compilation for
any purpose, including commercial applications, is hereby granted
without fee, subject to the following restrictions:
The Crypto++ Library (as a compilation) is currently licensed under the Boost
Software License 1.0 (http://www.boost.org/users/license.html).
1. Any copy or modification of this compilation in any form, except
in object code form as part of an application software, must include
the above copyright notice and this license.
Boost Software License - Version 1.0 - August 17th, 2003
2. Users of this software agree that any modification or extension
they provide to Wei Dai will be considered public domain and not
copyrighted unless it includes an explicit copyright notice.
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
3. Wei Dai makes no warranty or representation that the operation of the
software in this compilation will be error-free, and Wei Dai is under no
obligation to provide any services, by way of maintenance, update, or
otherwise. THE SOFTWARE AND ANY DOCUMENTATION ARE PROVIDED "AS IS"
WITHOUT EXPRESS OR IMPLIED WARRANTY INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. IN NO EVENT WILL WEI DAI OR ANY OTHER CONTRIBUTOR BE LIABLE FOR
DIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
4. Users will not use Wei Dai or any other contributor's name in any
publicity or advertising, without prior written consent in each case.
5. Export of this software from the United States may require a
specific license from the United States Government. It is the
responsibility of any person or organization contemplating export
to obtain such a license before exporting.
6. Certain parts of this software may be protected by patents. It
is the users' responsibility to obtain the appropriate
licenses before using those parts.
If this compilation is used in object code form in an application
software, acknowledgement of the author is not required but would be
appreciated. The contribution of any useful modifications or extensions
to Wei Dai is not required but would also be appreciated.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -1,5 +1,5 @@
Crypto++: a C++ Class Library of Cryptographic Schemes
Version 5.6.2 (in development)
Version 5.6.2 - 2/20/2013
Crypto++ Library is a free C++ class library of cryptographic schemes.
Currently the library contains the following algorithms:
@ -24,7 +24,7 @@ Currently the library contains the following algorithms:
Two-Track-MAC
SHA-1, SHA-2 (SHA-224, SHA-256, SHA-384, and
hash functions SHA-512), Tiger, WHIRLPOOL, RIPEMD-128,
hash functions SHA-512), SHA-3, Tiger, WHIRLPOOL, RIPEMD-128,
RIPEMD-256, RIPEMD-160, RIPEMD-320
RSA, DSA, ElGamal, Nyberg-Rueppel (NR),
@ -441,4 +441,12 @@ the mailing list.
- ported to MSVC 2010, GCC 4.5.1, Sun Studio 12u1, C++Builder 2010, Intel C++ Compiler 11.1
- renamed the MSVC DLL project to "cryptopp" for compatibility with MSVC 2010
5.6.2 - changed license to Boost Software License 1.0
- added SHA-3 (Keccak)
- updated DSA to FIPS 186-3 (see DSA2 class)
- fixed Blowfish minimum keylength to be 4 bytes (32 bits)
- fixed Salsa validation failure when compiling with GCC 4.6
- fixed infinite recursion when on x64, assembly disabled, and no AESNI
- ported to MSVC 2012, GCC 4.7, Clang 3.2, Solaris Studio 12.3, Intel C++ Compiler 13.0
Written by Wei Dai

View File

@ -14,42 +14,42 @@ NAMESPACE_BEGIN(CryptoPP)
template <class T> const T& AbstractGroup<T>::Double(const Element &a) const
{
return Add(a, a);
return this->Add(a, a);
}
template <class T> const T& AbstractGroup<T>::Subtract(const Element &a, const Element &b) const
{
// make copy of a in case Inverse() overwrites it
Element a1(a);
return Add(a1, Inverse(b));
return this->Add(a1, Inverse(b));
}
template <class T> T& AbstractGroup<T>::Accumulate(Element &a, const Element &b) const
{
return a = Add(a, b);
return a = this->Add(a, b);
}
template <class T> T& AbstractGroup<T>::Reduce(Element &a, const Element &b) const
{
return a = Subtract(a, b);
return a = this->Subtract(a, b);
}
template <class T> const T& AbstractRing<T>::Square(const Element &a) const
{
return Multiply(a, a);
return this->Multiply(a, a);
}
template <class T> const T& AbstractRing<T>::Divide(const Element &a, const Element &b) const
{
// make copy of a in case MultiplicativeInverse() overwrites it
Element a1(a);
return Multiply(a1, MultiplicativeInverse(b));
return this->Multiply(a1, this->MultiplicativeInverse(b));
}
template <class T> const T& AbstractEuclideanDomain<T>::Mod(const Element &a, const Element &b) const
{
Element q;
DivisionAlgorithm(result, q, a, b);
this->DivisionAlgorithm(result, q, a, b);
return result;
}
@ -60,7 +60,7 @@ template <class T> const T& AbstractEuclideanDomain<T>::Gcd(const Element &a, co
while (!this->Equal(g[i1], this->Identity()))
{
g[i2] = Mod(g[i0], g[i1]);
g[i2] = this->Mod(g[i0], g[i1]);
unsigned int t = i0; i0 = i1; i1 = i2; i2 = t;
}
@ -74,7 +74,7 @@ template <class T> const typename QuotientRing<T>::Element& QuotientRing<T>::Mul
Element y;
unsigned int i0=0, i1=1, i2=2;
while (!Equal(g[i1], Identity()))
while (!this->Equal(g[i1], this->Identity()))
{
// y = g[i0] / g[i1];
// g[i2] = g[i0] % g[i1];
@ -90,7 +90,7 @@ template <class T> const typename QuotientRing<T>::Element& QuotientRing<T>::Mul
template <class T> T AbstractGroup<T>::ScalarMultiply(const Element &base, const Integer &exponent) const
{
Element result;
SimultaneousMultiply(&result, base, &exponent, 1);
this->SimultaneousMultiply(&result, base, &exponent, 1);
return result;
}
@ -98,7 +98,7 @@ template <class T> T AbstractGroup<T>::CascadeScalarMultiply(const Element &x, c
{
const unsigned expLen = STDMAX(e1.BitCount(), e2.BitCount());
if (expLen==0)
return Identity();
return this->Identity();
const unsigned w = (expLen <= 46 ? 1 : (expLen <= 260 ? 2 : 3));
const unsigned tableSize = 1<<w;
@ -107,11 +107,11 @@ template <class T> T AbstractGroup<T>::CascadeScalarMultiply(const Element &x, c
powerTable[1] = x;
powerTable[tableSize] = y;
if (w==1)
powerTable[3] = Add(x,y);
powerTable[3] = this->Add(x,y);
else
{
powerTable[2] = Double(x);
powerTable[2*tableSize] = Double(y);
powerTable[2] = this->Double(x);
powerTable[2*tableSize] = this->Double(y);
unsigned i, j;
@ -157,12 +157,12 @@ template <class T> T AbstractGroup<T>::CascadeScalarMultiply(const Element &x, c
else
{
while (squaresBefore--)
result = Double(result);
result = this->Double(result);
if (power1 || power2)
Accumulate(result, powerTable[(power2<<w) + power1]);
}
while (squaresAfter--)
result = Double(result);
result = this->Double(result);
power1 = power2 = 0;
}
}

View File

@ -348,7 +348,7 @@ NAMESPACE_END
#define CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS
#endif
#define CRYPTOPP_VERSION 561
#define CRYPTOPP_VERSION 562
// ***************** determine availability of OS features ********************

View File

@ -4,7 +4,7 @@
classes that provide a uniform interface to this library.
*/
/*! \mainpage Crypto++ Library 5.6.1 API Reference
/*! \mainpage Crypto++ Library 5.6.2 API Reference
<dl>
<dt>Abstract Base Classes<dd>
cryptlib.h
@ -25,7 +25,7 @@
<dt>Public Key Cryptosystems<dd>
DLIES, ECIES, LUCES, RSAES, RabinES, LUC_IES
<dt>Public Key Signature Schemes<dd>
DSA, GDSA, ECDSA, NR, ECNR, LUCSS, RSASS, RSASS_ISO, RabinSS, RWSS, ESIGN
DSA2, GDSA, ECDSA, NR, ECNR, LUCSS, RSASS, RSASS_ISO, RabinSS, RWSS, ESIGN
<dt>Key Agreement<dd>
#DH, DH2, #MQV, ECDH, ECMQV, XTR_DH
<dt>Algebraic Structures<dd>

View File

@ -58,62 +58,6 @@ size_t DSAConvertSignatureFormat(byte *buffer, size_t bufferSize, DSASignatureFo
return (size_t)sink.TotalPutLength();
}
bool DSA::GeneratePrimes(const byte *seedIn, unsigned int g, int &counter,
Integer &p, unsigned int L, Integer &q, bool useInputCounterValue)
{
assert(g%8 == 0);
SHA sha;
SecByteBlock seed(seedIn, g/8);
SecByteBlock U(SHA::DIGESTSIZE);
SecByteBlock temp(SHA::DIGESTSIZE);
SecByteBlock W(((L-1)/160+1) * SHA::DIGESTSIZE);
const int n = (L-1) / 160;
const int b = (L-1) % 160;
Integer X;
sha.CalculateDigest(U, seed, g/8);
for (int i=g/8-1, carry=true; i>=0 && carry; i--)
carry=!++seed[i];
sha.CalculateDigest(temp, seed, g/8);
xorbuf(U, temp, SHA::DIGESTSIZE);
U[0] |= 0x80;
U[SHA::DIGESTSIZE-1] |= 1;
q.Decode(U, SHA::DIGESTSIZE);
if (!IsPrime(q))
return false;
int counterEnd = useInputCounterValue ? counter+1 : 4096;
for (int c = 0; c < counterEnd; c++)
{
for (int k=0; k<=n; k++)
{
for (int i=g/8-1, carry=true; i>=0 && carry; i--)
carry=!++seed[i];
if (!useInputCounterValue || c == counter)
sha.CalculateDigest(W+(n-k)*SHA::DIGESTSIZE, seed, g/8);
}
if (!useInputCounterValue || c == counter)
{
W[SHA::DIGESTSIZE - 1 - b/8] |= 0x80;
X.Decode(W + SHA::DIGESTSIZE - 1 - b/8, L/8);
p = X-((X % (2*q))-1);
if (p.GetBit(L-1) && IsPrime(p))
{
counter = c;
return true;
}
}
}
return false;
}
NAMESPACE_END
#endif

View File

@ -30,39 +30,37 @@ void DL_GroupParameters_DSA::GenerateRandom(RandomNumberGenerator &rng, const Na
if (alg.GetValue("Modulus", p) && alg.GetValue("SubgroupGenerator", g))
{
q = alg.GetValueWithDefault("SubgroupOrder", ComputeGroupOrder(p)/2);
Initialize(p, q, g);
}
else
{
int modulusSize = 1024;
int modulusSize = 1024, defaultSubgroupOrderSize;
alg.GetIntValue("ModulusSize", modulusSize) || alg.GetIntValue("KeySize", modulusSize);
if (!DSA::IsValidPrimeLength(modulusSize))
switch (modulusSize)
{
case 1024:
defaultSubgroupOrderSize = 160;
break;
case 2048:
defaultSubgroupOrderSize = 224;
break;
case 3072:
defaultSubgroupOrderSize = 256;
break;
default:
throw InvalidArgument("DSA: not a valid prime length");
}
SecByteBlock seed(SHA::DIGESTSIZE);
Integer h;
int c;
do
{
rng.GenerateBlock(seed, SHA::DIGESTSIZE);
} while (!DSA::GeneratePrimes(seed, SHA::DIGESTSIZE*8, c, p, modulusSize, q));
do
{
h.Randomize(rng, 2, p-2);
g = a_exp_b_mod_c(h, (p-1)/q, p);
} while (g <= 1);
DL_GroupParameters_GFP::GenerateRandom(rng, CombinedNameValuePairs(alg, MakeParameters(Name::SubgroupOrderSize(), defaultSubgroupOrderSize, false)));
}
Initialize(p, q, g);
}
bool DL_GroupParameters_DSA::ValidateGroup(RandomNumberGenerator &rng, unsigned int level) const
{
bool pass = DL_GroupParameters_GFP::ValidateGroup(rng, level);
pass = pass && DSA::IsValidPrimeLength(GetModulus().BitCount());
pass = pass && GetSubgroupOrder().BitCount() == 160;
int pSize = GetModulus().BitCount(), qSize = GetSubgroupOrder().BitCount();
pass = pass && ((pSize==1024 && qSize==160) || (pSize==2048 && qSize==224) || (pSize==2048 && qSize==256) || (pSize==3072 && qSize==256));
return pass;
}

View File

@ -369,51 +369,43 @@ public:
/*! parameters: (ModulusSize), or (Modulus, SubgroupOrder, SubgroupGenerator) */
/*! ModulusSize must be between DSA::MIN_PRIME_LENGTH and DSA::MAX_PRIME_LENGTH, and divisible by DSA::PRIME_LENGTH_MULTIPLE */
void GenerateRandom(RandomNumberGenerator &rng, const NameValuePairs &alg);
static bool CRYPTOPP_API IsValidPrimeLength(unsigned int pbits)
{return pbits >= MIN_PRIME_LENGTH && pbits <= MAX_PRIME_LENGTH && pbits % PRIME_LENGTH_MULTIPLE == 0;}
enum {MIN_PRIME_LENGTH = 1024, MAX_PRIME_LENGTH = 3072, PRIME_LENGTH_MULTIPLE = 1024};
};
struct DSA;
template <class H>
class DSA2;
//! DSA keys
struct DL_Keys_DSA
{
typedef DL_PublicKey_GFP<DL_GroupParameters_DSA> PublicKey;
typedef DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_GFP<DL_GroupParameters_DSA>, DSA> PrivateKey;
typedef DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_GFP<DL_GroupParameters_DSA>, DSA2<SHA> > PrivateKey;
};
//! <a href="http://www.weidai.com/scan-mirror/sig.html#DSA">DSA</a>
struct CRYPTOPP_DLL DSA : public DL_SS<
//! <a href="http://en.wikipedia.org/wiki/Digital_Signature_Algorithm">DSA</a>, as specified in FIPS 186-3
// class named DSA2 instead of DSA for backwards compatibility (DSA was a non-template class)
template <class H>
class DSA2 : public DL_SS<
DL_Keys_DSA,
DL_Algorithm_GDSA<Integer>,
DL_SignatureMessageEncodingMethod_DSA,
SHA,
DSA>
H,
DSA2<H> >
{
static const char * CRYPTOPP_API StaticAlgorithmName() {return "DSA";}
//! Generate DSA primes according to NIST standard
/*! Both seedLength and primeLength are in bits, but seedLength should
be a multiple of 8.
If useInputCounterValue == true, the counter parameter is taken as input, otherwise it's used for output
*/
static bool CRYPTOPP_API GeneratePrimes(const byte *seed, unsigned int seedLength, int &counter,
Integer &p, unsigned int primeLength, Integer &q, bool useInputCounterValue = false);
static bool CRYPTOPP_API IsValidPrimeLength(unsigned int pbits)
{return pbits >= MIN_PRIME_LENGTH && pbits <= MAX_PRIME_LENGTH && pbits % PRIME_LENGTH_MULTIPLE == 0;}
//! FIPS 186-2 Change Notice 1 changed the minimum modulus length to 1024
enum {
#if (DSA_1024_BIT_MODULUS_ONLY)
MIN_PRIME_LENGTH = 1024,
#else
MIN_PRIME_LENGTH = 512,
#endif
MAX_PRIME_LENGTH = 1024, PRIME_LENGTH_MULTIPLE = 64};
public:
static std::string CRYPTOPP_API StaticAlgorithmName() {return "DSA/" + (std::string)H::StaticAlgorithmName();}
};
//! DSA with SHA-1, typedef'd for backwards compatibility
typedef DSA2<SHA> DSA;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PublicKey_GFP<DL_GroupParameters_DSA>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_GFP<DL_GroupParameters_DSA>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_GFP<DL_GroupParameters_DSA>, DSA>;
CRYPTOPP_DLL_TEMPLATE_CLASS DL_PrivateKey_WithSignaturePairwiseConsistencyTest<DL_PrivateKey_GFP<DL_GroupParameters_DSA>, DSA2<SHA> >;
//! the XOR encryption method, for use with DL-based cryptosystems
template <class MAC, bool DHAES_MODE>

View File

@ -141,7 +141,7 @@ const T & Singleton<T, F, instance>::Ref(CRYPTOPP_NOINLINE_DOTDOTDOT) const
// ************** misc functions ***************
#if (!__STDC_WANT_SECURE_LIB__)
#if (!__STDC_WANT_SECURE_LIB__ && !defined(_MEMORY_S_DEFINED))
inline void memcpy_s(void *dest, size_t sizeInBytes, const void *src, size_t count)
{
if (count > sizeInBytes)

View File

@ -83,8 +83,22 @@ void NonblockingRng::GenerateBlock(byte *output, size_t size)
if (!CryptGenRandom(m_Provider.GetProviderHandle(), (DWORD)size, output))
throw OS_RNG_Err("CryptGenRandom");
#else
if (read(m_fd, output, size) != size)
throw OS_RNG_Err("read /dev/urandom");
while (size)
{
ssize_t len = read(m_fd, output, size);
if (len < 0)
{
// /dev/urandom reads CAN give EAGAIN errors! (maybe EINTR as well)
if (errno != EINTR && errno != EAGAIN)
throw OS_RNG_Err("read /dev/urandom");
continue;
}
output += len;
size -= len;
}
#endif
}
@ -119,10 +133,17 @@ void BlockingRng::GenerateBlock(byte *output, size_t size)
while (size)
{
// on some systems /dev/random will block until all bytes
// are available, on others it will returns immediately
// are available, on others it returns immediately
ssize_t len = read(m_fd, output, size);
if (len < 0)
throw OS_RNG_Err("read " CRYPTOPP_BLOCKING_RNG_FILENAME);
{
// /dev/random reads CAN give EAGAIN errors! (maybe EINTR as well)
if (errno != EINTR && errno != EAGAIN)
throw OS_RNG_Err("read " CRYPTOPP_BLOCKING_RNG_FILENAME);
continue;
}
size -= len;
output += len;
if (size)

View File

@ -58,6 +58,7 @@ public:
ByteQueue & operator=(const ByteQueue &rhs);
bool operator==(const ByteQueue &rhs) const;
bool operator!=(const ByteQueue &rhs) const {return !operator==(rhs);}
byte operator[](lword i) const;
void swap(ByteQueue &rhs);

View File

@ -22,6 +22,11 @@ public:
void BERDecode(BufferedTransformation &bt);
void DEREncode(BufferedTransformation &bt) const;
void Save(BufferedTransformation &bt) const
{DEREncode(bt);}
void Load(BufferedTransformation &bt)
{BERDecode(bt);}
Integer ApplyFunction(const Integer &x) const;
Integer PreimageBound() const {return ++(m_n>>1);}
Integer ImageBound() const {return m_n;}
@ -52,6 +57,11 @@ public:
void BERDecode(BufferedTransformation &bt);
void DEREncode(BufferedTransformation &bt) const;
void Save(BufferedTransformation &bt) const
{DEREncode(bt);}
void Load(BufferedTransformation &bt)
{BERDecode(bt);}
Integer CalculateInverse(RandomNumberGenerator &rng, const Integer &x) const;
// GeneratibleCryptoMaterial

View File

@ -76,6 +76,6 @@ bool ValidateECDSA();
bool ValidateESIGN();
CryptoPP::RandomNumberGenerator & GlobalRNG();
bool RunTestDataFile(const char *filename, const CryptoPP::NameValuePairs &overrideParameters=CryptoPP::g_nullNameValuePairs);
bool RunTestDataFile(const char *filename, const CryptoPP::NameValuePairs &overrideParameters=CryptoPP::g_nullNameValuePairs, bool thorough=true);
#endif

View File

@ -12,6 +12,8 @@
# Usage:
# To make a release build, call "make release=1"
# To make a debug build, call "make"
# To make a 32-bit build on 64-bit OS, pass the addm32=1 flag
# To build with clang, you need to add disableasm=1 flag
#
###################################################
@ -98,10 +100,9 @@ endif
################
###################################################
# 32-bit build override in 64-bit build environments
# - so that BearBin doesn't need to modify his makefile after each makefile change :)
################
ifeq ($(addm32),1)
CC_OPTIONS += -m32
CXX_OPTIONS += -m32
@ -110,6 +111,21 @@ endif
###################################################
# Clang doesn't seem to support CryptoPP's assembly mode, disable it for now (CryptoPP 5.6.2)
ifeq ($(disableasm),1)
CC_OPTIONS += -DCRYPTOPP_DISABLE_ASM
CXX_OPTIONS += -DCRYPTOPP_DISABLE_ASM
endif
###################################################
# INCLUDE directories for MCServer
#

2
MCServer/Plugins/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
Core
ProtectionAreas

View File

@ -1,72 +0,0 @@
MCServer Core Plugin
====================
The Core plugin for MCServer provides the default utility commands and also a lot of WebAdmin goodness.
Commands
--------
* /back
* /ban
* /clear
* /downfall
* /give
* /gm
* /groups
* /help
* /i
* /item
* /kill
* /kick
* /locate
* /me
* /motd
* /plugins
* /portal
* /rank
* /regen
* /reload
* /save-all
* /spawn
* /stop
* /time
* /top
* /tp
* /tpa
* /tpaccept
* /unban
* /viewdistance
* /worlds
**Also, console commands:**
* ban
* banlist
* getversion
* help
* list
* listgroups
* numchunks
* players
* rank
* reload
* say
* setversion
* unban
* unload
Contributors
------------
FakeTruth
xoft
tigerw
bearbin
tonibm19
(If you want your name here, please submit a PR after you've done your contributions.)
How to Use
----------
Core should be installed in MCServer by default.

View File

@ -1,10 +0,0 @@
function HandleBackCommand( Split, Player )
if BackCoords[Player:GetName()] == nil then
SendMessageFailure(Player, "No known last position")
return true
else
Player:TeleportToCoords(BackCoords[Player:GetName()].x, BackCoords[Player:GetName()].y, BackCoords[Player:GetName()].z)
SendMessageSuccess(Player, "Teleported back to your last known position")
end
return true
end

View File

@ -1,49 +0,0 @@
function HandleBanCommand( Split, Player )
if( #Split < 2 ) then
SendMessage( Player, "Usage: /ban [Player] <Reason>" )
return true
end
local Reason = cChatColor.Red .. "You have been banned." .. cChatColor.White .. " Did you do something illegal?"
if( #Split > 2 ) then
Reason = table.concat( Split, " ", 3 )
end
if KickPlayer(Split[2], Reason) == false then
BannedPlayersIni:DeleteValue( "Banned", Split[2] )
BannedPlayersIni:SetValueB( "Banned", Split[2], true )
BannedPlayersIni:WriteFile()
SendMessageFailure( Player, "Could not find player, but banned anyway" )
else
BannedPlayersIni:DeleteValue( "Banned", Split[2] )
BannedPlayersIni:SetValueB( "Banned", Split[2], true )
BannedPlayersIni:WriteFile()
SendMessageSuccess( Player, "Successfully kicked and banned player" )
end
return true
end
function HandleUnbanCommand( Split, Player )
if( #Split < 2 ) then
SendMessage( Player, "Usage: /unban [Player]" )
return true
end
if( BannedPlayersIni:GetValueB("Banned", Split[2], false) == false ) then
SendMessageFailure( Player, "Player is not banned!" )
return true
end
BannedPlayersIni:DeleteValue("Banned", Split[2])
BannedPlayersIni:SetValueB("Banned", Split[2], false)
BannedPlayersIni:WriteFile()
LOGINFO( Player:GetName() .. " is unbanning " .. Split[2] )
SendMessageSuccess( Player, "Unbanning " .. Split[2] )
return true
end

View File

@ -1,25 +0,0 @@
function HandleClearCommand( Split, Player )
if (Split[2] == nil) then
SendMessage( Player, "Usage: /clear <player>" )
return true
end
local InventoryCleared = false;
local ClearInventory = function(OtherPlayer)
if (OtherPlayer:GetName() == Split[2]) then
OtherPlayer:GetInventory():Clear()
InventoryCleared = true
end
end
cRoot:Get():FindAndDoWithPlayer(Split[2], ClearInventory);
if (InventoryCleared) then
SendMessageSuccess( Player, "You cleared the inventory of " .. Split[2] )
return true
else
SendMessageFailure( Player, "Player not found" )
return true
end
end

View File

@ -1,338 +0,0 @@
-- Implements things related to console commands
function InitConsoleCommands()
local PluginMgr = cPluginManager:Get();
-- Please keep the list alpha-sorted
PluginMgr:BindConsoleCommand("ban", HandleConsoleBan, " ~ Bans a player by name");
PluginMgr:BindConsoleCommand("banlist ips", HandleConsoleBanList, " - Lists all players banned by IP");
PluginMgr:BindConsoleCommand("banlist", HandleConsoleBanList, " - Lists all players banned by name");
PluginMgr:BindConsoleCommand("getversion", HandleConsoleVersion, " - Gets server version reported to 1.4+ clients");
PluginMgr:BindConsoleCommand("help", HandleConsoleHelp, " - Lists all commands");
PluginMgr:BindConsoleCommand("give", HandleConsoleGive, " - Gives items to the specified player.")
PluginMgr:BindConsoleCommand("list", HandleConsoleList, " - Lists all players in a machine-readable format");
PluginMgr:BindConsoleCommand("listgroups", HandleConsoleListGroups, " - Shows a list of all the groups");
PluginMgr:BindConsoleCommand("numchunks", HandleConsoleNumChunks, " - Shows number of chunks currently loaded");
PluginMgr:BindConsoleCommand("players", HandleConsolePlayers, " - Lists all connected players");
PluginMgr:BindConsoleCommand("rank", HandleConsoleRank, " ~ Add a player to a group");
PluginMgr:BindConsoleCommand("reload", HandleConsoleReload, " - Reloads all plugins");
PluginMgr:BindConsoleCommand("save-all", HandleConsoleSaveAll, " - Saves all chunks");
PluginMgr:BindConsoleCommand("say", HandleConsoleSay, " - Sends a chat message to all players");
PluginMgr:BindConsoleCommand("setversion", HandleConsoleVersion, " ~ Sets server version reported to 1.4+ clients");
PluginMgr:BindConsoleCommand("unban", HandleConsoleUnban, " ~ Unbans a player by name");
PluginMgr:BindConsoleCommand("unload", HandleConsoleUnload, " - Unloads all unused chunks");
end
function HandleConsoleGive(Split)
-- Make sure there are a correct number of arguments.
if #Split ~= 3 and #Split ~= 4 and #Split ~= 5 then
return true, "Usage: give <player> <item> [amount] [meta]"
end
-- Get the item from the arguments and check it's valid.
local Item = cItem()
if #Split == 5 then
local FoundItem = StringToItem(Split[3] .. ":" .. Split[5], Item)
else
local FoundItem = StringToItem(Split[3], Item)
end
if not IsValidItem(Item.m_ItemType) then -- StringToItem does not check if item is valid
FoundItem = false
end
if not FoundItem then
return true, "Invalid item id or name!"
end
-- Work out how many items the user wants.
local ItemAmount = 1
if #Split > 3 then
ItemAmount = tonumber(Split[4])
if ItemAmount == nil or ItemAmount < 1 or ItemAmount > 512 then
return true, "Invalid amount!"
end
end
Item.m_ItemCount = ItemAmount
-- Get the playername from the split.
local playerName = Split[2]
local function giveItems(newPlayer)
local ItemsGiven = newPlayer:GetInventory():AddItem(Item)
if ItemsGiven == ItemAmount then
SendMessageSuccess( newPlayer, "There you go!" )
LOG("Gave " .. newPlayer:GetName() .. " " .. Item.m_ItemCount .. " times " .. Item.m_ItemType .. ":" .. Item.m_ItemDamage)
else
SendMessageFailure( Player, "Not enough space in inventory, only gave " .. ItemsGiven)
return true, "Only " .. Item.m_ItemCount .. " out of " .. ItemsGiven .. "items could be delivered."
end
end
-- Finally give the items to the player.
itemStatus = cRoot:Get():FindAndDoWithPlayer(playerName, giveItems)
-- Check to make sure that giving items was successful.
if not itemStatus then
return true, "There was no player that matched your query."
end
return true
end
function HandleConsoleBan(Split)
if (#Split < 2) then
return true, "Usage: ban [Player] <Reason>";
end
local Reason = cChatColor.Red .. "You have been banned." .. cChatColor.White .. " Did you do something illegal?"
if( #Split > 2 ) then
Reason = table.concat(Split, " ", 3)
end
if KickPlayer(Split[2], Reason) == false then
BannedPlayersIni:DeleteValue("Banned", Split[2])
BannedPlayersIni:SetValueB("Banned", Split[2], true)
BannedPlayersIni:WriteFile()
LOGINFO("Could not find player, but banned anyway" )
else
BannedPlayersIni:DeleteValue("Banned", Split[2])
BannedPlayersIni:SetValueB("Banned", Split[2], true)
BannedPlayersIni:WriteFile()
LOGINFO("Successfully kicked and banned player" )
end
return true
end
function HandleConsoleUnban(Split)
if #Split < 2 then
return true, "Usage: /unban [Player]"
end
if( BannedPlayersIni:GetValueB("Banned", Split[2], false) == false ) then
return true, Split[2] .. " is not banned!"
end
BannedPlayersIni:SetValueB("Banned", Split[2], false, false)
BannedPlayersIni:WriteFile()
local Server = cRoot:Get():GetServer()
return true, "Unbanned " .. Split[2]
end
function HandleConsoleBanList(Split)
if (#Split == 1) then
return true, BanListByName();
end
if (string.lower(Split[2]) == "ips") then
return true, BanListByIPs();
end
return true, "Unknown banlist subcommand";
end
function HandleConsoleHelp(Split)
local Commands = {}; -- {index => {"Command", "HelpString"} }
local MaxLength = 0;
local AddToTable = function(Command, HelpString)
table.insert(Commands, { Command, HelpString });
local CmdLen = Command:len();
if (CmdLen > MaxLength) then
MaxLength = CmdLen;
end
end
cPluginManager:Get():ForEachConsoleCommand(AddToTable);
-- Sort the table:
local CompareCommands = function(a, b)
return a[1] < b[1]; -- compare command strings
end
table.sort(Commands, CompareCommands);
local Out = "";
Out = "'-' denotes no prefix, '~' denotes that a value is required.\n"
for i, Command in ipairs(Commands) do
Out = Out .. Command[1] .. string.rep(" ", MaxLength - Command[1]:len()); -- Align to a table
Out = Out .. Command[2] .. "\n";
end
return true, Out;
end
function HandleConsoleList(Split)
-- Get a list of all players, one playername per line
local Out = "";
cRoot:Get():ForEachWorld(
function (a_World)
a_World:ForEachPlayer(
function (a_Player)
Out = Out .. a_Player:GetName() .. "\n";
end
);
end
);
return true, Out;
end
function HandleConsoleListGroups(Split)
-- Read the groups.ini file:
local GroupsIni = cIniFile("groups.ini");
if (not(GroupsIni:ReadFile())) then
return true, "No groups found";
end
-- Read the groups:
Number = GroupsIni:NumKeys();
Groups = {};
for i = 0, Number do
table.insert(Groups, GroupsIni:KeyName(i))
end
-- Output the groups, concatenated to a string:
local Out = "Groups:\n"
Out = Out .. table.concat(Groups, ", ");
return true, Out;
end
function HandleConsoleNumChunks(Split)
local Output = {};
local AddNumChunks = function(World)
Output[World:GetName()] = World:GetNumChunks();
end;
cRoot:Get():ForEachWorld(AddNumChunks);
local Total = 0;
local Out = "";
for name, num in pairs(Output) do
Out = Out .. " " .. name .. ": " .. num .. " chunks\n";
Total = Total + num;
end
Out = Out .. "Total: " .. Total .. " chunks\n";
return true, Out;
end
function HandleConsolePlayers(Split)
local PlayersInWorlds = {}; -- "WorldName" => [players array]
local AddToTable = function(Player)
local WorldName = Player:GetWorld():GetName();
if (PlayersInWorlds[WorldName] == nil) then
PlayersInWorlds[WorldName] = {};
end
table.insert(PlayersInWorlds[WorldName], Player:GetName() .. " @ " .. Player:GetIP());
end
cRoot:Get():ForEachPlayer(AddToTable);
local Out = "";
for WorldName, Players in pairs(PlayersInWorlds) do
Out = Out .. "World " .. WorldName .. ":\n";
for i, PlayerName in ipairs(Players) do
Out = Out .. " " .. PlayerName .. "\n";
end
end
return true, Out;
end
function HandleConsoleVersion(Split)
if (#Split == 1) then
-- Display current version:
local Version = cRoot:Get():GetPrimaryServerVersion();
return true, "Primary server version: #" .. Version .. ", " .. cRoot:GetProtocolVersionTextFromInt(Version);
end
-- Set new value as the version:
cRoot:Get():SetPrimaryServerVersion(tonumber(Split[2]));
local Version = cRoot:Get():GetPrimaryServerVersion();
return true, "Primary server version is now #" .. Version .. ", " .. cRoot:GetProtocolVersionTextFromInt(Version);
end
function HandleConsoleRank(Split)
if (Split[2] == nil) or (Split[3] == nil) then
return true, "Usage: /rank [Player] [Group]";
end
local Out = "";
-- Read the groups.ini file:
local GroupsIni = cIniFile("groups.ini")
if (not(GroupsIni:ReadFile())) then
Out = "Could not read groups.ini, creating anew!\n"
end
-- Find the group:
if (GroupsIni:FindKey(Split[3]) == -1) then
return true, Out .. "Group does not exist";
end
-- Read the users.ini file:
local UsersIni = cIniFile("users.ini");
if (not(UsersIni:ReadFile())) then
Out = Out .. "Could not read users.ini, creating anew!\n";
end
-- Write the new group value to users.ini:
UsersIni:DeleteKey(Split[2]);
UsersIni:GetValueSet(Split[2], "Groups", Split[3]);
UsersIni:WriteFile();
-- Reload the player's permissions:
cRoot:Get():ForEachWorld(
function (World)
World:ForEachPlayer(
function (Player)
if (Player:GetName() == Split[2]) then
SendMessage( Player, "You were moved to group " .. Split[3] )
Player:LoadPermissionsFromDisk();
end
end
);
end
)
return true, Out .. "Player " .. Split[2] .. " was moved to " .. Split[3];
end
function HandleConsoleReload(Split)
Server = cRoot:Get():GetServer();
Server:SendMessage(cChatColor.Rose .. "[WARNING] " .. cChatColor.White .. "Reloading all plugins!");
cPluginManager:Get():ReloadPlugins();
return true;
end
function HandleConsoleSaveAll(Split)
Server = cRoot:Get():GetServer();
Server:SendMessage(cChatColor.Rose .. "[WARNING] " .. cChatColor.White .. "Saving all chunks!");
cRoot:Get():SaveAllChunks();
return true;
end
function HandleConsoleSay(Split)
table.remove(Split, 1);
local Message = "";
for i, Text in ipairs(Split) do
Message = Message .. " " .. Text;
end
Message = Message:sub(2); -- Cut off the first space
cRoot:Get():GetServer():BroadcastChat(cChatColor.Gold .. "[SERVER] " .. cChatColor.Yellow .. Message);
return true;
end
function HandleConsoleUnload(Split)
local UnloadChunks = function(World)
World:UnloadUnusedChunks();
end
local Out = "Num loaded chunks before: " .. cRoot:Get():GetTotalChunkCount() .. "\n";
cRoot:Get():ForEachWorld(UnloadChunks);
Out = Out .. "Num loaded chunks after: " .. cRoot:Get():GetTotalChunkCount();
return true, Out;
end

View File

@ -1,29 +0,0 @@
function HandleDoCommand( Split, Player )
if #Split < 3 then
SendMessage( "Usage: /do <player> <command> [arguments]" )
return true
end
-- Get the command and arguments.
local newSplit = table.concat( Split, " ", 3 )
local pluginManager = cRoot:Get():GetPluginManager()
pluginManager:ExecuteCommand( Split[2], newSplit )
end
function HandleSudoCommand ( Split, Player )
if #Split < 3 then
SendMessage( "Usage: /sudo <player> <command> [arguments]" )
return true
end
-- Get the command and arguments.
local newSplit = table.concat( Split, " ", 3 )
local pluginManager = cRoot:Get():GetPluginManager()
pluginManager:ForceExecuteCommand( Split[2], newSplit )
end

View File

@ -1,162 +0,0 @@
function SetBackCoordinates( Player )
BackCoords[Player:GetName()] = Vector3i( Player:GetPosX(), Player:GetPosY(), Player:GetPosZ() )
end
function SendMessage(a_Player, a_Message)
if (g_UsePrefixes) then
a_Player:SendMessage(cChatColor.Yellow .. "[INFO] " .. cChatColor.White .. a_Message)
else
a_Player:SendMessage(cChatColor.Yellow .. a_Message)
end
end
function SendMessageSuccess(a_Player, a_Message)
if (g_UsePrefixes) then
a_Player:SendMessage(cChatColor.Green .. "[INFO] " .. cChatColor.White .. a_Message)
else
a_Player:SendMessage(cChatColor.Green .. a_Message)
end
end
function SendMessageFailure(a_Player, a_Message)
if (g_UsePrefixes) then
a_Player:SendMessage(cChatColor.Red .. "[INFO] " .. cChatColor.White .. a_Message)
else
a_Player:SendMessage(cChatColor.Red .. a_Message)
end
end
--- Returns the list of players banned by name, separated by ", "
function BanListByName()
local NumValues = BannedPlayersIni:NumValues("Banned");
local Banned = {};
local KeyID = BannedPlayersIni:FindKey("Banned");
for i = 1, NumValues do
local PlayerName = BannedPlayersIni:ValueName(KeyID, i - 1);
if (BannedPlayersIni:GetValueB("Banned", PlayerName)) then
-- Player listed AND banned
table.insert(Banned, PlayerName);
end
end
return table.concat(Banned, ", ");
end
--- Returns the list of players banned by IP, separated by ", "
function BanListByIPs()
-- TODO: No IP ban implemented yet
return "";
end
--- Kicks a player by name, with the specified reason; returns bool whether found and player's real name
function KickPlayer( PlayerName, Reason )
local RealName = ""
if (Reason == nil) then
Reason = "You have been kicked"
end
local FoundPlayerCallback = function( a_Player )
RealName = a_Player:GetName()
local Server = cRoot:Get():GetServer()
LOGINFO( "'" .. RealName .. "' is being kicked for ( "..Reason..") " )
Server:SendMessage("Kicking " .. RealName)
a_Player:GetClientHandle():Kick(Reason)
end
if not cRoot:Get():FindAndDoWithPlayer( PlayerName, FoundPlayerCallback ) then
-- Could not find player
return false
end
return true, RealName -- Player has been kicked
end
function ReturnColorFromChar( Split, char )
-- Check if the char represents a color. Else return nil.
if char == "0" then
return cChatColor.Black
elseif char == "1" then
return cChatColor.Navy
elseif char == "2" then
return cChatColor.Green
elseif char == "3" then
return cChatColor.Blue
elseif char == "4" then
return cChatColor.Red
elseif char == "5" then
return cChatColor.Purple
elseif char == "6" then
return cChatColor.Gold
elseif char == "7" then
return cChatColor.LightGray
elseif char == "8" then
return cChatColor.Gray
elseif char == "9" then
return cChatColor.DarkPurple
elseif char == "a" then
return cChatColor.LightGreen
elseif char == "b" then
return cChatColor.LightBlue
elseif char == "c" then
return cChatColor.Rose
elseif char == "d" then
return cChatColor.LightPurple
elseif char == "e" then
return cChatColor.Yellow
elseif char == "f" then
return cChatColor.White
elseif char == "k" then
return cChatColor.Random
elseif char == "l" then
return cChatColor.Bold
elseif char == "m" then
return cChatColor.Strikethrough
elseif char == "n" then
return cChatColor.Underlined
elseif char == "o" then
return cChatColor.Italic
elseif char == "r" then
return cChatColor.Plain
end
end
function CheckHardcore(Victim)
if HardCore == "true" then
if Victim:IsPlayer() == true then
local KilledPlayer = tolua.cast(Victim, "cPlayer")
BanPlayer(KilledPlayer:GetName(), "You died, haha. Good game, bro.")
end
end
end
-- Teleports a_SrcPlayer to a player named a_DstPlayerName; if a_TellDst is true, will send a notice to the destination player
function TeleportToPlayer( a_SrcPlayer, a_DstPlayerName, a_TellDst )
local teleport = function(OtherPlayer)
if OtherPlayer == a_SrcPlayer then
-- Asked to teleport to self?
SendMessageFailure( a_SrcPlayer, "Y' can't teleport to yerself!" )
else
SetBackCoordinates( a_SrcPlayer )
a_SrcPlayer:TeleportToEntity( OtherPlayer )
SendMessageSuccess( a_SrcPlayer, "You teleported to " .. OtherPlayer:GetName() .. "!" )
if (a_TellDst) then
SendMessage( OtherPlayer, Player:GetName().." teleported to you!" )
end
end
end
local World = a_SrcPlayer:GetWorld()
if not World:DoWithPlayer(a_DstPlayerName, teleport) then
SendMessageFailure( a_SrcPlayer, "Can't find player " .. a_DstPlayerName)
end
end

View File

@ -1,66 +0,0 @@
function HandleGiveCommand(Split, Player)
-- Make sure there are a correct number of arguments.
if #Split ~= 3 and #Split ~= 4 and #Split ~= 5 then
SendMessage( Player, "Usage: /give <player> <item> [amount] [meta]" )
return true
end
-- Get the item from the arguments and check it's valid.
local Item = cItem()
if #Split == 5 then
local FoundItem = StringToItem( Split[3] .. ":" .. Split[5], Item )
else
local FoundItem = StringToItem( Split[3], Item )
end
if not IsValidItem( Item.m_ItemType ) then -- StringToItem does not check if item is valid
FoundItem = false
end
if not FoundItem then
SendMessageFailure( Player, "Invalid item id or name!" )
return true
end
-- Work out how many items the user wants.
local ItemAmount = 1
if #Split > 3 then
ItemAmount = tonumber( Split[4] )
if ItemAmount == nil or ItemAmount < 1 or ItemAmount > 512 then
SendMessageFailure( Player, "Invalid amount!" )
return true
end
end
Item.m_ItemCount = ItemAmount
-- Get the playername from the split.
local playerName = Split[2]
local function giveItems( newPlayer )
local ItemsGiven = newPlayer:GetInventory():AddItem( Item )
if ItemsGiven == ItemAmount then
SendMessageSuccess( newPlayer, "You were given " .. Item.m_ItemCount .. " of " .. Item.m_ItemType .. "." )
if not newPlayer == Player then
SendMessageSuccess( Player, "Items given!" )
end
LOG("Gave " .. newPlayer:GetName() .. " " .. Item.m_ItemCount .. " times " .. Item.m_ItemType .. ":" .. Item.m_ItemDamage )
else
SendMessageFailure( Player, "Not enough space in inventory, only gave " .. ItemsGiven )
LOG( "Player " .. Player:GetName() .. " asked for " .. Item.m_ItemCount .. " times " .. Item.m_ItemType .. ":" .. Item.m_ItemDamage ..", but only could fit " .. ItemsGiven )
end
return true
end
-- Finally give the items to the player.
itemStatus = cRoot:Get():FindAndDoWithPlayer( playerName, giveItems )
-- Check to make sure that giving items was successful.
if not itemStatus then
SendMessageFailure( Player, "There was no player that matched your query." )
end
return true
end

View File

@ -1,11 +0,0 @@
function HandleChangeGMCommand( Split, Player )
if( #Split ~= 2 ) then
SendMessage( Player, "Usage: /gm [0|1]" )
return true
end
Player:SetGameMode( Split[2] )
return true
end

View File

@ -1,43 +0,0 @@
function HandleHelpCommand( Split, Player )
local PluginManager = cRoot:Get():GetPluginManager()
local LinesPerPage = 8
local CurrentPage = 1
local CurrentLine = 0
local PageRequested = 1
local Output = {}
if (#Split == 2) then
PageRequested = tonumber( Split[2] )
end
local Process = function( Command, Permission, HelpString )
if not (Player:HasPermission(Permission)) then
return false
end
if (HelpString == "") then
return false
end
CurrentLine = CurrentLine + 1
CurrentPage = math.floor( CurrentLine / LinesPerPage ) + 1
if (CurrentPage ~= PageRequested) then
return false
end
table.insert( Output, Command .. HelpString )
end
PluginManager:ForEachCommand( Process )
-- CurrentPage now contains the total number of pages, and Output has the individual help lines to be sent
SendMessage( Player, "Page " .. PageRequested .. " out of " .. CurrentPage .. "." )
SendMessage( Player, "'-' means no prefix, '~' means a value is required." )
for idx, msg in ipairs( Output ) do
SendMessage( Player, msg )
end
return true
end

View File

@ -1,26 +0,0 @@
function HandleItemCommand( Split, Player )
if ((#Split ~= 2) and (#Split ~=3)) then
SendMessage( Player, "Usage: /i <item>[:meta] [amount]" )
return true
end
local itemSplit = StringSplit(Split[2], ":")
local newSplit = {}
newSplit[1] = "/give"
newSplit[2] = Player:GetName()
newSplit[3] = itemSplit[1]
if Split[3] ~= nil then
newSplit[4] = Split[3]
else
newSplit[4] = 1
end
if itemSplit[2] ~= nil then
newSplit[5] = itemSplit[2]
end
HandleGiveCommand( newSplit, Player )
return true
end

View File

@ -1,202 +0,0 @@
-- Based on Fixies plugin v2 by Taugeshtu
-- how much "extra" points are healed per a repair operation (fraction of full health)
BONUS = 0.1
function OnCraftingNoRecipe(Player, Grid, Recipe)
local _do_fix = false
local Items = {}
for x = 0, Grid:GetWidth() - 1 do
for y = 0, Grid:GetHeight() - 1 do
local Item = Grid:GetItem(x, y)
if (Item.m_ItemType ~= E_ITEM_EMPTY) then
table.insert(Items, Item)
end
end
end
if (#Items ~= 2) then
-- Only two items together can be fixed
return false
end
if (Items[1].m_ItemType ~= Items[2].m_ItemType) then
-- Only items of the same type may be fixed
return false
end
if (
(Items[1].m_ItemDamage == 0) or
(Items[2].m_ItemDamage == 0)
)
then
-- Only damaged items may be fixed
return false
end
local _ID = Items[1].m_ItemType
local _least_hp = math.max(Items[1].m_ItemDamage, Items[2].m_ItemDamage)
local _most_hp = math.min(Items[1].m_ItemDamage, Items[2].m_ItemDamage)
local _item_hp = 0
-- TODO: This could be refactored into better code, using an _ID-indexed table for _item_hp
if (
(_ID == E_ITEM_WOODEN_SHOVEL) or
(_ID == E_ITEM_WOODEN_AXE) or
(_ID == E_ITEM_WOODEN_PICKAXE) or
(_ID == E_ITEM_WOODEN_SWORD) or
(_ID == E_ITEM_WOODEN_HOE)
)
then
_item_hp = 60
_do_fix = true
end
if (
(_ID == E_ITEM_STONE_SHOVEL) or
(_ID == E_ITEM_STONE_AXE) or
(_ID == E_ITEM_STONE_PICKAXE) or
(_ID == E_ITEM_STONE_SWORD) or
(_ID == E_ITEM_STONE_HOE)
)
then
_item_hp = 132
_do_fix = true
end
if (
(_ID == E_ITEM_IRON_SHOVEL) or
(_ID == E_ITEM_IRON_AXE) or
(_ID == E_ITEM_IRON_PICKAXE) or
(_ID == E_ITEM_IRON_SWORD) or
(_ID == E_ITEM_IRON_HOE)
)
then
_item_hp = 251
_do_fix = true
end
if (
(_ID == E_ITEM_GOLD_SHOVEL) or
(_ID == E_ITEM_GOLD_AXE) or
(_ID == E_ITEM_GOLD_PICKAXE) or
(_ID == E_ITEM_GOLD_SWORD) or
(_ID == E_ITEM_GOLD_HOE)
)
then
_item_hp = 33
_do_fix = true
end
if (
(_ID == E_ITEM_DIAMOND_SHOVEL) or
(_ID == E_ITEM_DIAMOND_AXE) or
(_ID == E_ITEM_DIAMOND_PICKAXE) or
(_ID == E_ITEM_DIAMOND_SWORD) or
(_ID == E_ITEM_DIAMOND_HOE)
)
then
_item_hp = 1562
_do_fix = true
end
if (_ID == E_ITEM_LEATHER_CAP) then
_item_hp = 56
_do_fix = true
end
if (_ID == E_ITEM_LEATHER_TUNIC) then
_item_hp = 82
_do_fix = true
end
if (_ID == E_ITEM_LEATHER_PANTS) then
_item_hp = 76
_do_fix = true
end
if (_ID == E_ITEM_LEATHER_BOOTS) then
_item_hp = 66
_do_fix = true
end
if (_ID == E_ITEM_CHAIN_HELMET) then
_item_hp = 78
_do_fix = true
end
if (_ID == E_ITEM_CHAIN_CHESTPLATE) then
_item_hp = 114
_do_fix = true
end
if (_ID == E_ITEM_CHAIN_LEGGINGS) then
_item_hp = 106
_do_fix = true
end
if (_ID == E_ITEM_CHAIN_BOOTS) then
_item_hp = 92
_do_fix = true
end
if (_ID == E_ITEM_IRON_HELMET) then
_item_hp = 166
_do_fix = true
end
if (_ID == E_ITEM_IRON_CHESTPLATE) then
_item_hp = 242
_do_fix = true
end
if (_ID == E_ITEM_IRON_LEGGINGS) then
_item_hp = 226
_do_fix = true
end
if (_ID == E_ITEM_IRON_BOOTS) then
_item_hp = 196
_do_fix = true
end
if (_ID == E_ITEM_GOLD_HELMET) then
_item_hp = 78
_do_fix = true
end
if (_ID == E_ITEM_GOLD_CHESTPLATE) then
_item_hp = 114
_do_fix = true
end
if (_ID == E_ITEM_GOLD_LEGGINGS) then
_item_hp = 106
_do_fix = true
end
if (_ID == E_ITEM_GOLD_BOOTS) then
_item_hp = 92
_do_fix = true
end
if (_ID == E_ITEM_DIAMOND_HELMET) then
_item_hp = 364
_do_fix = true
end
if (_ID == E_ITEM_DIAMOND_CHESTPLATE)then
_item_hp = 529
_do_fix = true
end
if (_ID == E_ITEM_DIAMOND_LEGGINGS) then
_item_hp = 496
_do_fix = true
end
if (_ID == E_ITEM_DIAMOND_BOOTS) then
_item_hp = 430
_do_fix = true
end
-- /////////////////////////////////////////////////////
if (_do_fix == true) then
local _hp = _most_hp - (_item_hp - _least_hp) - _item_hp * BONUS
_hp = math.max(_hp, 0)
Recipe:SetResult(_ID, 1, _hp)
Recipe:SetIngredient(Items[1].x, Items[1].y, Items[1]);
Recipe:SetIngredient(Items[2].x, Items[2].y, Items[2]);
return true
end
return false
end

View File

@ -1,19 +0,0 @@
function HandleKickCommand( Split, Player )
if( #Split < 2 ) then
SendMessage( Player, "Usage: /kick [Player] <Reason>" )
return true
end
local Reason = "You have been kicked"
if ( #Split > 2 ) then
Reason = table.concat( Split, " ", 3 )
end
if( KickPlayer( Split[2], Reason ) == false ) then
SendMessageFailure( Player, "Could not find player " .. Split[2] )
end
return true
end

View File

@ -1,34 +0,0 @@
function HandleKillCommand( Split, Player )
if (Split[2] == nil) then
Player:TakeDamage(dtInVoid, nil, 1000, 1000, 0)
return true
end
local HasKilled = false;
local KillPlayer = function(OtherPlayer)
if (OtherPlayer:GetName() == Split[2]) then
if (OtherPlayer:GetGameMode() == 1) then
HasKilled = creative
end
if (OtherPlayer:GetGameMode() == 0) then
OtherPlayer:TakeDamage(dtInVoid, nil, 1000, 1000, 0)
HasKilled = true
end
end
end
cRoot:Get():FindAndDoWithPlayer(Split[2], KillPlayer);
if (HasKilled == creative) then
SendMessageFailure( Player, "Player " .. Split[2] .. " is in creative mode" )
return true
end
if (HasKilled) then
SendMessageSuccess( Player, "Player " .. Split[2] .. " is killed" )
return true
else
SendMessageFailure( Player, "Player not found" )
return true
end
end

View File

@ -1,4 +0,0 @@
function HandleLocateCommand( Split, Player )
SendMessage( Player, string.format("You are at [X:%0.2f Y:%0.2f Z:%0.2f] in world %s", Player:GetPosX(), Player:GetPosY(), Player:GetPosZ(), Player:GetWorld():GetName()) )
return true
end

View File

@ -1,198 +0,0 @@
--COMMENCE VARIABLES
PLUGIN = {}
BannedPlayersIni = {}
WhiteListIni = {}
BackCoords = {}
Messages = {}
Destination = {}
--END VARIABLES
-- Configuration
-- Use prefixes or not.
-- If set to true, messages are prefixed, e. g. "[FATAL]". If false, messages are colored.
g_UsePrefixes = true
--COMMENCE AWESOMENESS!
function Initialize( Plugin )
PLUGIN = Plugin
Plugin:SetName( "Core" )
Plugin:SetVersion( 13 )
--ADD HOOKS
PluginManager = cRoot:Get():GetPluginManager()
PluginManager:AddHook( Plugin, cPluginManager.HOOK_PLAYER_JOINED )
PluginManager:AddHook( Plugin, cPluginManager.HOOK_DISCONNECT )
PluginManager:AddHook( Plugin, cPluginManager.HOOK_PLAYER_BREAKING_BLOCK )
PluginManager:AddHook( Plugin, cPluginManager.HOOK_PLAYER_PLACING_BLOCK )
PluginManager:AddHook( Plugin, cPluginManager.HOOK_LOGIN )
PluginManager:AddHook( Plugin, cPluginManager.HOOK_KILLING )
PluginManager:AddHook( Plugin, cPluginManager.HOOK_CRAFTING_NO_RECIPE )
PluginManager:AddHook( Plugin, cPluginManager.HOOK_CHAT ) -- used in web_chat.lua
PluginManager:AddHook( Plugin, cPluginManager.HOOK_PLAYER_MOVING )
--PLEASE ALPHA SORT http://elmosaukko.com/sort-alphabetically/ THIS LIST
--BIND COMMANDS
PluginManager:BindCommand("/back", "core.back", HandleBackCommand, " - Return to your last position")
PluginManager:BindCommand("/ban", "core.ban", HandleBanCommand, " ~ Ban a player")
PluginManager:BindCommand("/clear", "core.clear", HandleClearCommand, " - Clear the inventory of some player")
PluginManager:BindCommand("/give", "core.give", HandleGiveCommand, " ~ Give someone an item")
PluginManager:BindCommand("/gm", "core.changegm", HandleChangeGMCommand, " ~ Change your gamemode")
PluginManager:BindCommand("/groups", "core.groups", HandleGroupsCommand, " - Shows a list of all the groups")
PluginManager:BindCommand("/help", "core.help", HandleHelpCommand, " ~ Show available commands")
PluginManager:BindCommand("/i", "core.give", HandleItemCommand, "")
PluginManager:BindCommand("/item", "core.give", HandleItemCommand, " - Give yourself an item.")
PluginManager:BindCommand("/kick", "core.kick", HandleKickCommand, " ~ Kick a player")
PluginManager:BindCommand("/kill", "core.kill", HandleKillCommand, " - Kill some player")
PluginManager:BindCommand("/locate", "core.locate", HandleLocateCommand, " - Show your current server coordinates")
PluginManager:BindCommand("/me", "core.me", HandleMeCommand, " ~ Tell what you are doing")
PluginManager:BindCommand("/motd", "core.motd", HandleMOTDCommand, " - Show message of the day")
PluginManager:BindCommand("/msg", "core.tell", HandleTellCommand, "")
PluginManager:BindCommand("/plugins", "core.plugins", HandlePluginsCommand, " - Show list of plugins")
PluginManager:BindCommand("/portal", "core.portal", HandlePortalCommand, " ~ Move to a different world")
PluginManager:BindCommand("/rank", "core.rank", HandleRankCommand, " ~ Add someone to a group")
PluginManager:BindCommand("/regen", "core.regen", HandleRegenCommand, " ~ Regenerates a chunk, current or specified")
PluginManager:BindCommand("/reload", "core.reload", HandleReloadCommand, " - Reload all plugins")
PluginManager:BindCommand("/save-all", "core.save-all", HandleSaveAllCommand, " - Saves all your worlds")
PluginManager:BindCommand("/spawn", "core.spawn", HandleSpawnCommand, " - Return to the spawn")
PluginManager:BindCommand("/stop", "core.stop", HandleStopCommand, " - Stops the server")
PluginManager:BindCommand("/tell", "core.tell", HandleTellCommand, " ~ Send a private message")
PluginManager:BindCommand("/time", "core.time", HandleTimeCommand, " ~ Sets the time of day")
PluginManager:BindCommand("/toggledownfall", "core.toggledownfall", HandleDownfallCommand, " - Toggles the weather")
PluginManager:BindCommand("/top", "core.top", HandleTopCommand, " - Teleport yourself to the top most block")
PluginManager:BindCommand("/tp", "core.teleport", HandleTPCommand, " ~ Teleport yourself to a player")
PluginManager:BindCommand("/tpa", "core.teleport", HandleTPACommand, " ~ Ask to teleport yourself to a player")
PluginManager:BindCommand("/tpaccept", "core.teleport", HandleTPAcceptCommand, " ~ Accept a teleportation request")
PluginManager:BindCommand("/unban", "core.unban", HandleUnbanCommand, " ~ Unban a player")
PluginManager:BindCommand("/viewdistance", "core.viewdistance", HandleViewDistanceCommand, " [".. cClientHandle.MIN_VIEW_DISTANCE .."-".. cClientHandle.MAX_VIEW_DISTANCE .."] - Change your view distance")
PluginManager:BindCommand("/weather", "core.weather", HandleWeatherCommand, " ~ Change world weather")
PluginManager:BindCommand("/worlds", "core.worlds", HandleWorldsCommand, " - Shows a list of all the worlds")
PluginManager:BindCommand("/sudo", "core.sudo", HandleSudoCommand, " - Runs a command as a player, ignoring permissions")
PluginManager:BindCommand("/do", "core.do", HandleDoCommand, " - Runs a command as a player.")
InitConsoleCommands()
--LOAD SETTINGS
IniFile = cIniFile( "settings.ini" )
if IniFile:ReadFile() == true then
HardCore = IniFile:GetValueSet( "GameMode", "Hardcore", "false" )
IniFile:WriteFile()
end
WorldsSpawnProtect = {}
local KeyIdx = IniFile:FindKey( "Worlds" ) --(FIND WHERE 'WORLDS' KEY IS LOCATED)
local NumValues = IniFile:GetNumValues( KeyIdx ) --(HOW MANY VALUES ARE THERE?)
for i = 0, NumValues - 1 do --(FOR EVERY WORLD KEY, TAKING ACCOUNT OF OFF BY ONE ERRORS)
WorldIni = cIniFile( IniFile:GetValue(KeyIdx, i) .. "/world.ini" )
if WorldIni:ReadFile() == true then
WorldsSpawnProtect[IniFile:GetValue(KeyIdx, i)] = WorldIni:GetValueSetI( "SpawnProtect", "ProtectRadius", 10 )
WorldIni:WriteFile()
end
end
WorldsWorldLimit = {}
local KeyIdx = IniFile:FindKey( "Worlds" ) --(FIND WHERE 'WORLDS' KEY IS LOCATED)
local NumValues = IniFile:GetNumValues( KeyIdx ) --(HOW MANY VALUES ARE THERE?)
for i = 0, NumValues - 1 do --(FOR EVERY WORLD KEY, TAKING ACCOUNT OF OFF BY ONE ERRORS)
WorldIni = cIniFile( IniFile:GetValue(KeyIdx, i) .. "/world.ini" )
if WorldIni:ReadFile() == true then
WorldsWorldLimit[IniFile:GetValue(KeyIdx, i)] = WorldIni:GetValueSetI( "WorldLimit", "LimitRadius", 0 )
WorldIni:WriteFile()
end
end
--LOAD WHITELIST
WhiteListIni = cIniFile( Plugin:GetLocalDirectory() .. "/whitelist.ini" )
if WhiteListIni:ReadFile() == true then
if WhiteListIni:GetValueB( "WhiteListSettings", "WhiteListOn", false ) == true then
if WhiteListIni:GetNumValues( "WhiteList" ) > 0 then
LOGINFO( "Core: loaded " .. WhiteListIni:GetNumValues('WhiteList') .. " whitelisted players." )
else
LOGWARN( "WARNING: WhiteList is on, but there are no people in the whitelist!" )
end
end
else
WhiteListIni:SetValueB( "WhiteListSettings", "WhiteListOn", false )
WhiteListIni:SetValue( "WhiteList", "", "" ) -- So it adds an empty header
WhiteListIni:DeleteValue( "WhiteList", "" ) -- And remove the value
WhiteListIni:KeyComment( "WhiteList", "PlayerName=1" )
if WhiteListIni:WriteFile() == false then
LOGWARN( "WARNING: Could not write to whitelist.ini" )
end
end
--LOAD BANNED (BAD LUCK, BRO)
BannedPlayersIni = cIniFile( Plugin:GetLocalDirectory() .. "/banned.ini" )
if BannedPlayersIni:ReadFile() == true then
if BannedPlayersIni:GetNumValues( "Banned" ) > 0 then
LOGINFO( "Core: loaded " .. BannedPlayersIni:GetNumValues("Banned") .. " banned players." )
end
else
BannedPlayersIni:SetValue( "Banned", "", "" ) -- So it adds an empty header
BannedPlayersIni:DeleteValue( "Banned", "" ) -- And remove the value
BannedPlayersIni:KeyComment( "Banned", "PlayerName=1" )
if BannedPlayersIni:WriteFile() == false then
LOGWARN( "WARNING: Could not write to banned.ini" )
end
end
--ADD WEB INTERFACE TABULATES
Plugin:AddWebTab( "Manage Server", HandleRequest_ManageServer )
Plugin:AddWebTab( "Server Settings", HandleRequest_ServerSettings )
Plugin:AddWebTab( "Chat", HandleRequest_Chat )
Plugin:AddWebTab( "Playerlist", HandleRequest_PlayerList )
Plugin:AddWebTab( "Whitelist", HandleRequest_WhiteList )
Plugin:AddWebTab( "Permissions", HandleRequest_Permissions )
Plugin:AddWebTab( "Manage Plugins", HandleRequest_ManagePlugins )
LoadMotd()
LOG( "Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion() )
return true
end
--AWESOMENESS STILL GOING!
--BEGIN SPAWNPROTECT LOGFILE CODE (COURTSEY OF BEARBIN)
function WriteLog( breakPlace, X, Y, Z, player, id, meta )
local logText = {}
table.insert( logText, player )
table.insert( logText, " tried to " )
if breakPlace == 0 then
table.insert( logText, "break " )
else
table.insert( logText, "place " )
end
table.insert( logText, ItemToString(cItem(id, 1, meta)) )
table.insert( logText, " at ")
table.insert( logText, tostring(X) )
table.insert( logText, ", ")
table.insert( logText, tostring(Y) )
table.insert( logText, ", ")
table.insert( logText, tostring(Z) )
table.insert( logText, "." )
LOGINFO( table.concat( logText, '') )
if LOGTOFILE then
local logFile = io.open( Plugin:GetLocalDirectory() .. '/blocks.log', 'a' )
logFile:write( table.concat( logText, '' ) .. "\n" )
logFile:close()
end
return
end
function WarnPlayer( Player )
SendMessageFailure( Player, "Go further from spawn to build" )
return true
end
function OnDisable()
LOG( "Disabled Core!" )
end
--END AWESOMENESS :'(

View File

@ -1,20 +0,0 @@
function HandleMeCommand( Split, Player )
table.remove( Split, 1 )
local Message = ""
for i, Text in ipairs( Split ) do
Message = Message .. " " .. Text
end
if Split[1] == nil then
SendMessage( Player, "Usage: /me <action>" )
return true
end
if Split[1] ~= nil then
cRoot:Get():GetServer():BroadcastChat( Player:GetName() .. "" .. Message )
return true
end
end

View File

@ -1,44 +0,0 @@
function HandleMOTDCommand( Split, Player )
ShowMOTDTo( Player )
return true
end
function LoadMotd()
local File = io.open( "motd.txt", "r" )
-- Check if the file 'motd.txt' exists, else create it.
if not File then
CreateFile = io.open( "motd.txt", "w" )
CreateFile:write("@6Welcome to the MCServer test server!\n@6http://www.mc-server.org/\n@6Type /help for all commands")
CreateFile:close()
else
File:close()
end
for line in io.lines( "motd.txt" ) do
local TempMessage = line
-- Do a for loop that goes to each char in the line.
for I=1, string.len( TempMessage ) do
-- If the char is a '@' then check if the next char represents a color.
if string.sub( TempMessage, I, I ) == "@" then
local Char = string.sub( TempMessage, I + 1, I + 1 )
local Color = ReturnColorFromChar( TempMessage, Char )
-- If the next char represented a color then put the color in the string.
if Color ~= nil then
TempMessage = string.gsub( TempMessage, "@" .. Char, Color )
end
end
end
-- Add the message to the list of messages.
Messages[#Messages + 1] = TempMessage
end
end
function ShowMOTDTo( Player )
for I=1, #Messages do
Player:SendMessage(Messages[I])
end
end

View File

@ -1,119 +0,0 @@
function OnPlayerPlacingBlock(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, CursorY, CursorZ, BlockType)
-- Direction is air check
if (BlockFace == -1) then
return false
end
local PROTECTRADIUS = WorldsSpawnProtect[Player:GetWorld():GetName()];
if not (Player:HasPermission("core.build")) then
return true
else
if not (Player:HasPermission("core.spawnprotect.bypass")) and not (PROTECTRADIUS == 0) then
local World = Player:GetWorld()
local xcoord = World:GetSpawnX()
local ycoord = World:GetSpawnY()
local zcoord = World:GetSpawnZ()
if not ((BlockX <= (xcoord + PROTECTRADIUS)) and (BlockX >= (xcoord - PROTECTRADIUS))) then
return false -- Not in spawn area.
end
if not ((BlockY <= (ycoord + PROTECTRADIUS)) and (BlockY >= (ycoord - PROTECTRADIUS))) then
return false -- Not in spawn area.
end
if not ((BlockZ <= (zcoord + PROTECTRADIUS)) and (BlockZ >= (zcoord - PROTECTRADIUS))) then
return false -- Not in spawn area.
end
--WriteLog(1, BlockX, BlockY, BlockZ, Player:GetName(), id, meta)
WarnPlayer(Player)
return true
else
if BlockType == "50" or BlockType == "76" then
local X = BlockX
local Y = BlockY
local Z = BlockZ
X, Y, Z = AddFaceDirection(X, Y, Z, BlockFace)
if (Y >= 256 or Y < 0) then
return true
end
local CheckCollision = function(Player)
-- drop the decimals, we only care about the full block X,Y,Z
local PlayerX = math.floor(Player:GetPosX(), 0)
local PlayerY = math.floor(Player:GetPosY(), 0)
local PlayerZ = math.floor(Player:GetPosZ(), 0)
local collision = false
if ((BlockFace == BLOCK_FACE_TOP) and (PlayerY == BlockY - 2) and (PlayerX == BlockX) and (PlayerZ == BlockZ)) then
collision = true
end
if ((BlockFace == BLOCK_FACE_BOTTOM) and (PlayerY == BlockY + 1) and (PlayerX == BlockX) and (PlayerZ == BlockZ)) then
collision = true
end
if ((BlockFace == BLOCK_FACE_NORTH) and (PlayerX == BlockX) and (PlayerZ == BlockZ - 1)) then
if ((PlayerY == BlockY) or (PlayerY + 1 == BlockY)) then collision = true end
end
if ((BlockFace == BLOCK_FACE_SOUTH) and (PlayerX == BlockX) and (PlayerZ == BlockZ + 1)) then
if ((PlayerY == BlockY) or (PlayerY + 1 == BlockY)) then collision = true end
end
if ((BlockFace == BLOCK_FACE_WEST) and (PlayerX == BlockX - 1) and (PlayerZ == BlockZ)) then
if ((PlayerY == BlockY) or (PlayerY + 1 == BlockY)) then collision = true end
end
if ((BlockFace == BLOCK_FACE_EAST) and (PlayerX == BlockX + 1) and (PlayerZ == BlockZ)) then
if ((PlayerY == BlockY) or (PlayerY + 1 == BlockY)) then collision = true end
end
return collision
end
if (Player:GetWorld():ForEachPlayer(CheckCollision) == false) then
return true
end
end
end
end
return false
end
function OnPlayerBreakingBlock(Player, BlockX, BlockY, BlockZ, BlockFace, Status, OldBlockType, OldBlockMeta)
-- dont check if the direction is in the air
if (BlockFace ~= -1) then
local PROTECTRADIUS = WorldsSpawnProtect[Player:GetWorld():GetName()];
if not (Player:HasPermission("core.build")) then
return true
else
if not (Player:HasPermission("core.spawnprotect.bypass")) and not (PROTECTRADIUS == 0) then
local World = Player:GetWorld()
local xcoord = World:GetSpawnX()
local ycoord = World:GetSpawnY()
local zcoord = World:GetSpawnZ()
if not ((BlockX <= (xcoord + PROTECTRADIUS)) and (BlockX >= (xcoord - PROTECTRADIUS))) then
return false -- Not in spawn area.
end
if not ((BlockY <= (ycoord + PROTECTRADIUS)) and (BlockY >= (ycoord - PROTECTRADIUS))) then
return false -- Not in spawn area.
end
if not ((BlockZ <= (zcoord + PROTECTRADIUS)) and (BlockZ >= (zcoord - PROTECTRADIUS))) then
return false -- Not in spawn area.
end
--WriteLog(0, BlockX, BlockY, BlockZ, Player:GetName(), id, meta)
WarnPlayer(Player)
return true
end
end
end
return false
end

View File

@ -1,56 +0,0 @@
function OnKilling(Victim, Killer)
if Victim:IsPlayer() then
SetBackCoordinates( Victim )
Server = cRoot:Get():GetServer()
if Killer == nil then
if Victim:GetWorld():GetBlock(Victim:GetPosX(), Victim:GetPosY(), Victim:GetPosZ()) == 10 or Victim:GetWorld():GetBlock(Victim:GetPosX(), Victim:GetPosY(), Victim:GetPosZ()) == 11 then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " tried to swim in lava (and failed)" )
CheckHardcore(Victim)
return false
end
if Victim:IsOnFire() then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was burnt to a cinder" )
CheckHardcore(Victim)
return false
end
else
if Killer:IsPlayer() then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was terminated by " .. Killer:GetName() )
CheckHardcore(Victim)
return false
elseif Killer:IsMob() then
if Killer:IsA("cZombie") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was eaten by a zombie")
elseif Killer:IsA("cSkeleton") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was shot by a skeleton" )
elseif Killer:IsA("cCreeper") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was blown up by a creeper")
elseif Killer:IsA("cSpider") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was ripped apart by a giant spider")
elseif Killer:IsA("cCaveSpider") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was poisoned by a giant cave spider")
elseif Killer:IsA("cBlaze") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was flamed by a blaze")
elseif Killer:IsA("cEnderman") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was " .. cChatColor.Random .. " by an enderman")
elseif Killer:IsA("cSilverfish") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " encountered an unexpectedly fatal silverfish attack")
elseif Killer:IsA("cSlime") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was absorbed and digested by a slime")
elseif Killer:IsA("cWitch") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was enchanted (to death) by a witch")
elseif Killer:IsA("cZombiepigman") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was slain by a zombie pigman")
elseif Killer:IsA("cMagmacube") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was incinerated by a magmacube")
elseif Killer:IsA("cWolf") then
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " was savaged by a wolf")
end
CheckHardcore(Victim)
return false
end
end
Server:SendMessage( cChatColor.Red .. "[FATALITY] " .. cChatColor.White .. Victim:GetName() .. " died of mysterious circumstances")
CheckHardcore(Victim)
end
end

View File

@ -1,24 +0,0 @@
function OnPlayerJoined(Player)
--if( BannedPlayersIni:GetValueB("Banned", Player:GetName(), false) == true ) then
-- LOGINFO( Player:GetName() .. " tried to join, but is banned!" )
-- KickPlayer(Player:GetName(), cChatColor.Red .. "You are banned!" )
-- return true
--elseif( WhiteListIni:GetValueB("WhiteListSettings", "WhiteListOn", false ) == true ) then
-- if( WhiteListIni:GetValueB("WhiteList", Player:GetName(), false ) == false ) then
-- LOGINFO( Player:GetName() .. " tried to join, but is not whitelisted!" )
-- KickPlayer(Player:GetName(), cChatColor.Red .. "You are not whitelisted!" )
-- end
--else
ShowMOTDTo( Player )
local Server = cRoot:Get():GetServer()
Server:SendMessage(cChatColor.Yellow .. "[JOIN] " .. cChatColor.White .. Player:GetName() .. " has joined the game" )
return false
--end
end
function OnDisconnect(Player, Reason)
local Server = cRoot:Get():GetServer()
Server:SendMessage(cChatColor.Yellow .. "[LEAVE] " .. cChatColor.White .. Player:GetName() .. " has left the game" )
LOG("Player " .. Player:GetName() .. " has left the game.")
return true
end

View File

@ -1,17 +0,0 @@
function OnLogin(Client, ProtocolVersion, Username)
if( Username ~= "" ) then
if( BannedPlayersIni:GetValueB("Banned", Username, false) == true ) then
LOGINFO( Username .. " tried to join, but is banned!")
return true -- Player is banned, return true to deny access
end
if( WhiteListIni:GetValueB("WhiteListSettings", "WhiteListOn", false ) == true ) then
if( WhiteListIni:GetValueB("WhiteList", Username, false ) == false ) then -- not on whitelist
local Server = cRoot:Get():GetServer()
Server:SendMessage( Username .. " tried to join, but is not on the whitelist." )
LOGINFO( Username .. " tried to join, but is not on the whitelist." )
return true -- Deny access to the server
end
end
end
return false
end

View File

@ -1,17 +0,0 @@
function HandlePluginsCommand( Split, Player )
local PluginManager = cRoot:Get():GetPluginManager()
local PluginList = PluginManager:GetAllPlugins()
local PluginTable = {}
for k, Plugin in pairs( PluginList ) do
if Plugin then
table.insert( PluginTable, Plugin:GetName() )
end
end
SendMessage( Player, "There are " .. #PluginTable .. " loaded plugins" )
SendMessage( Player, table.concat( PluginTable , " " ) )
return true
end

View File

@ -1,41 +0,0 @@
function HandlePortalCommand( Split, Player )
if( #Split ~= 2 ) then
SendMessage( Player, "Usage: /portal [WorldName]" )
return true
end
if( Player:MoveToWorld(Split[2]) == false ) then
SendMessageFailure( Player, "Could not move to world " .. Split[2] .. "!" )
return true
end
SendMessageSuccess( Player, "Moved successfully to '" .. Split[2] .. "'! :D" )
return true
end
function HandleWorldsCommand( Split, Player )
local SettingsIni = cIniFile("settings.ini")
if SettingsIni:ReadFile() == false then
SendMessageFailure( Player, "No worlds found" )
end
Number = SettingsIni:NumValues("Worlds") - 1
Worlds = {}
for i=0, SettingsIni:GetNumKeys() - 1 do
if SettingsIni:GetKeyName(i) == "Worlds" then
Key = i
break
end
end
for i=0, Number do
table.insert( Worlds, SettingsIni:GetValue( Key, i ) )
end
SendMessage( Player, "Found " .. #Worlds .. " worlds" )
SendMessage( Player, table.concat( Worlds, ", " ) )
return true
end

View File

@ -1,63 +0,0 @@
function HandleRankCommand( Split, Player )
if Split[2] == nil or Split[3] == nil then
SendMessage( Player, "Usage: /rank [Player] [Group]" )
return true
end
local GroupsIni = cIniFile( "groups.ini" )
if GroupsIni:ReadFile() == false then
LOG( "Could not read groups.ini!" )
end
if GroupsIni:FindKey(Split[3]) == -1 then
SendMessageFailure( Player, "Group does not exist" )
return true
end
local UsersIni = cIniFile("users.ini")
if UsersIni:ReadFile() == false then
LOG( "Could not read users.ini!" )
end
UsersIni:DeleteKey( Split[2] )
UsersIni:GetValueSet( Split[2], "Groups", Split[3] )
UsersIni:WriteFile()
local loopPlayers = function( Player )
if Player:GetName() == Split[2] then
SendMessageSuccess( Player, "You were moved to group " .. Split[3] )
Player:LoadPermissionsFromDisk()
end
end
local loopWorlds = function ( World )
World:ForEachPlayer( loopPlayers )
end
cRoot:Get():ForEachWorld( loopWorlds )
SendMessageSuccess( Player, "Player " .. Split[2] .. " Was moved to " .. Split[3] )
return true
end
function HandleGroupsCommand( Split, Player )
local GroupsIni = cIniFile( "groups.ini" )
if GroupsIni:ReadFile() == false then
SendMessageFailure( Player, "No groups found" )
end
Number = GroupsIni:NumKeys() - 1
Groups = {}
for i=0, Number do
table.insert( Groups, GroupsIni:KeyName( i ) )
end
SendMessage( Player, "Found " .. #Groups .. " groups" )
SendMessage( Player, table.concat( Groups, " " ) )
return true
end

View File

@ -1,20 +0,0 @@
function HandleRegenCommand(Split, Player)
if #Split == 2 or #Split > 3 then
SendMessage( Player, "Usage: '/regeneratechunk' or '/regeneratechunk [X] [Z]'" )
return true
end
local X = Player:GetChunkX()
local Z = Player:GetChunkZ()
if #Split == 3 then
X = Split[2]
Z = Split[3]
end
SendMessageSuccess( Player, "Regenerating chunk ["..X..", "..Z.."]")
Player:GetWorld():RegenerateChunk(X, Z)
return true
end

View File

@ -1,28 +0,0 @@
function HandleSaveAllCommand( Split, Player )
cRoot:Get():SaveAllChunks()
local Server = cRoot:Get():GetServer()
Server:SendMessage(cChatColor.Rose .. "[WARNING] " .. cChatColor.White .. "Saving all worlds!")
return true
end
function HandleStopCommand( Split, Player )
Server = cRoot:Get():GetServer()
local Server = cRoot:Get():GetServer()
Server:SendMessage(cChatColor.Red .. "[WARNING] " .. cChatColor.White .. "Server is terminating!" )
cRoot:Get():QueueExecuteConsoleCommand("stop")
return true
end
function HandleReloadCommand( Split, Player )
Server = cRoot:Get():GetServer()
local Server = cRoot:Get():GetServer()
Server:SendMessage(cChatColor.Rose .. "[WARNING] " .. cChatColor.White .. "Reloading all plugins!" )
cRoot:Get():GetPluginManager():ReloadPlugins()
return true
end

View File

@ -1,9 +0,0 @@
function HandleSpawnCommand(Split, Player)
World = Player:GetWorld()
SetBackCoordinates(Player)
Player:TeleportToCoords(World:GetSpawnX(), World:GetSpawnY(), World:GetSpawnZ())
SendMessageSuccess( Player, "Returned to world spawn" )
return true
end

View File

@ -1,74 +0,0 @@
function HandleTPCommand(a_Split, a_Player)
if #a_Split == 2 or #a_Split == 3 then
-- Teleport to player specified in a_Split[2], tell them unless a_Split[3] equals "-h":
TeleportToPlayer( a_Player, a_Split[2], (a_Split[3] ~= "-h") )
return true
elseif #a_Split == 4 then
-- Teleport to XYZ coords specified in a_Split[2, 3, 4]:
SetBackCoordinates(a_Player)
a_Player:TeleportToCoords( a_Split[2], a_Split[3], a_Split[4] )
SendMessageSuccess( a_Player, "You teleported to [X:" .. a_Split[2] .. " Y:" .. a_Split[3] .. " Z:" .. a_Split[4] .. "]" )
return true
else
SendMessage( a_Player, "Usage: /tp [PlayerName] (-h) or /tp [X Y Z]" )
return true
end
end
function HandleTPACommand( Split, Player )
if Split[2] == nil then
SendMessage( Player, "Usage: /tpa [Player]" )
return true
end
local loopPlayer = function( OtherPlayer )
if OtherPlayer:GetName() == Split[2] then
SendMessage( OtherPlayer, Player:GetName() .. " send a teleport request" )
SendMessageSuccess( Player, "You send a teleport request to " .. OtherPlayer:GetName() )
Destination[OtherPlayer:GetName()] = Player:GetName()
end
end
local loopWorlds = function( World )
World:ForEachPlayer( loopPlayer )
end
cRoot:Get():ForEachWorld( loopWorlds )
return true
end
function HandleTPAcceptCommand( Split, Player )
if Destination[Player:GetName()] == nil then
SendMessageFailure( Player, "Nobody has send you a teleport request" )
return true
end
local loopPlayer = function( OtherPlayer )
if Destination[Player:GetName()] == OtherPlayer:GetName() then
if OtherPlayer:GetWorld():GetName() ~= Player:GetWorld():GetName() then
OtherPlayer:MoveToWorld( Player:GetWorld():GetName() )
end
OtherPlayer:TeleportToEntity( Player )
SendMessage( Player, OtherPlayer:GetName() .. " teleported to you" )
SendMessageSuccess( OtherPlayer, "You teleported to " .. Player:GetName() )
Destination[Player:GetName()] = nil
end
end
local loopWorlds = function( World )
World:ForEachPlayer( loopPlayer )
end
cRoot:Get():ForEachWorld( loopWorlds )
return true
end

View File

@ -1,37 +0,0 @@
function HandleTellCommand(Split, Player, OtherPlayer)
if (Split[2] == nil) or (Split[3] == nil) then
Player:SendMessage(cChatColor.Yellow .. "[INFO] " .. "Usage: /tell [playername] [message]")
return true
end
local SendMessage = function(OtherPlayer)
Sender = Player:GetName()
Reciever = Split[2]
if (OtherPlayer:GetName() == Split[2]) then
Server = cRoot:Get():GetServer()
FullMsg = ""
for i,v in ipairs(Split) do
if(i>2) then
if(FullMsg == "") then
FullMsg = v
else
FullMsg = FullMsg .. " " .. v
end
end
end
Player:SendMessage(cChatColor.Green .. "[INFO] " .. "Message to player " .. Reciever .. " sent!" )
OtherPlayer:SendMessage(cChatColor.Orange .. "[MSG: " .. Sender .. " ] " .. FullMsg )
else
Player:SendMessage(cChatColor.Red .. 'Player "' ..Split[2].. '" not found')
end
end
cRoot:Get():ForEachPlayer(SendMessage)
return true;
end

View File

@ -1,26 +0,0 @@
function HandleTimeCommand( Split, Player )
if Split[2] == nil then
SendMessage( Player, "Usage: /time [Day/Night/Set/Add]" )
return true
end
local Server = cRoot:Get():GetServer()
if string.upper( Split[2] ) == "DAY" then
Player:GetWorld():SetTimeOfDay( 0 )
Server:SendMessage(cChatColor.Green .. "[INFO] " .. cChatColor.White .. "Time was set to daytime" )
elseif string.upper( Split[2] ) == "NIGHT" then
Player:GetWorld():SetTimeOfDay( 12000 + 1000 )
Server:SendMessage( cChatColor.Green .. "[INFO] " .. cChatColor.White .. "Time was set to night time" )
elseif string.upper( Split[2] ) == "SET" and tonumber( Split[3] ) ~= nil then
Player:GetWorld():SetTimeOfDay( tonumber(Split[3]) )
Server:SendMessage( cChatColor.Green .. "[INFO] " .. cChatColor.White .. "Time was set to " .. Split[3] )
elseif string.upper( Split[2] ) == "ADD" and tonumber( Split[3] ) ~= nil then
Player:GetWorld():SetTimeOfDay( Player:GetWorld():GetTimeOfDay() + Split[3] )
Server:SendMessage( cChatColor.Green .. "[INFO] " .. cChatColor.White .. Split[3] .. "Was added to the time" )
else
SendMessage( Player, "Usage: /time [Day/Night/Set/Add]" )
end
return true
end

View File

@ -1,13 +0,0 @@
function HandleTopCommand( Split, Player )
local World = Player:GetWorld()
local PlayerPos = Player:GetPosition()
local Height = World:GetHeight( math.floor( PlayerPos.x ), math.floor( PlayerPos.z ) )
SetBackCoordinates( Player )
Player:TeleportToCoords( PlayerPos.x, Height+1, PlayerPos.z )
SendMessageSuccess( Player, "Teleported to the topmost block" )
return true
end

View File

@ -1,12 +0,0 @@
function HandleViewDistanceCommand( Split, Player )
if( #Split ~= 2 ) then
SendMessage( Player, "Usage: /viewdistance [".. cClientHandle.MIN_VIEW_DISTANCE .."-".. cClientHandle.MAX_VIEW_DISTANCE .."]" )
return true
end
Player:GetClientHandle():SetViewDistance( Split[2] )
SendMessageSuccess( Player, "Your view distance has been set to " .. Player:GetClientHandle():GetViewDistance() )
return true
end

View File

@ -1,33 +0,0 @@
function HandleWeatherCommand(Split, Player)
if #Split ~= 2 then
SendMessage( Player, "Usage: /weather [clear/rain/thunder]" )
return true
end
if (Split[2] == "clear") then
Player:GetWorld():SetWeather(0)
SendMessageSuccess( Player, "Downfall stopped" )
elseif (Split[2] == "rain") then
Player:GetWorld():SetWeather(1)
SendMessageSuccess( Player, "Let it rain!" )
elseif (Split[2] == "thunder") then
Player:GetWorld():SetWeather(2)
SendMessageSuccess( Player, "Thundery showers activate!")
end
return true
end
function HandleDownfallCommand( Split, Player )
World = Player:GetWorld()
if World:GetWeather() == 0 then
World:SetWeather(1)
else
World:SetWeather(0)
end
SendMessageSuccess( Player, "Downfall Toggled")
end

View File

@ -1,157 +0,0 @@
local CHAT_HISTORY = 50
local LastMessageID = 0
local JavaScript = [[
<script type="text/javascript">
function createXHR()
{
var request = false;
try {
request = new ActiveXObject('Msxml2.XMLHTTP');
}
catch (err2) {
try {
request = new ActiveXObject('Microsoft.XMLHTTP');
}
catch (err3) {
try {
request = new XMLHttpRequest();
}
catch (err1) {
request = false;
}
}
}
return request;
}
function OpenPage( url, postParams, callback )
{
var xhr = createXHR();
xhr.onreadystatechange=function()
{
if (xhr.readyState == 4)
{
callback( xhr )
}
};
xhr.open( (postParams!=null)?"POST":"GET", url , true);
if( postParams != null )
{
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
xhr.send(postParams);
}
function LoadPageInto( url, postParams, storage )
{
OpenPage( url, postParams, function( xhr )
{
var ScrollBottom = storage.scrollTop + storage.offsetHeight;
var bAutoScroll = (ScrollBottom >= storage.scrollHeight); // Detect whether we scrolled to the bottom of the div
results = xhr.responseText.split("<<divider>>");
if( results[2] != LastMessageID ) return; // Check if this message was meant for us
LastMessageID = results[1];
if( results[0] != "" )
{
storage.innerHTML += results[0];
if( bAutoScroll == true )
{
storage.scrollTop = storage.scrollHeight;
}
}
} );
return false;
}
function SendChatMessage()
{
var MessageContainer = document.getElementById('ChatMessage');
if( MessageContainer.value == "" ) return;
var postParams = "ChatMessage=" + MessageContainer.value;
OpenPage( "/~webadmin/Core/Chat/", postParams, function( xhr )
{
RefreshChat();
} );
MessageContainer.value = "";
}
function RefreshChat()
{
var postParams = "JustChat=true&LastMessageID=" + LastMessageID;
LoadPageInto("/~webadmin/Core/Chat/", postParams, document.getElementById('ChatDiv'));
}
setInterval(RefreshChat, 1000);
window.onload = RefreshChat;
var LastMessageID = 0;
</script>
]]
local ChatLogMessages = {}
function AddMessage( PlayerName, Message )
LastMessageID = LastMessageID + 1
table.insert( ChatLogMessages, { name = PlayerName, message = Message, id = LastMessageID } )
while( #ChatLogMessages > CHAT_HISTORY ) do
table.remove( ChatLogMessages, 1 )
end
end
function OnChat( Player, Message )
AddMessage( Player:GetName(), Message )
end
function HandleRequest_Chat( Request )
if( Request.PostParams["JustChat"] ~= nil ) then
local LastIdx = 0
if( Request.PostParams["LastMessageID"] ~= nil ) then LastIdx = tonumber( Request.PostParams["LastMessageID"] ) end
local Content = ""
for key, value in pairs(ChatLogMessages) do
if( value.id > LastIdx ) then
Content = Content .. "[" .. value.name .. "]: " .. value.message .. "<br>"
end
end
Content = Content .. "<<divider>>" .. LastMessageID .. "<<divider>>" .. LastIdx
return Content
end
if( Request.PostParams["ChatMessage"] ~= nil ) then
if( Request.PostParams["ChatMessage"] == "/help" ) then
Commands = "Available commands"
AddMessage(Commands, "<br>" .. "/help, /reload" )
return Commands
elseif( Request.PostParams["ChatMessage"] == "/reload" ) then
Server = cRoot:Get():GetServer()
Server:SendMessage( cChatColor.Green .. "Reloading all plugins." )
AddMessage("Reloading all plugins", "")
cRoot:Get():GetPluginManager():ReloadPlugins()
return ""
else
cmd = Request.PostParams["ChatMessage"]
if string.sub(cmd,1,string.len("/")) == "/" then
AddMessage('Unknown Command "' .. Request.PostParams["ChatMessage"] .. '"', "")
return ""
end
end
local Message = "[WebAdmin]: " .. Request.PostParams["ChatMessage"]
cRoot:Get():GetServer():SendMessage( Message )
AddMessage("WebAdmin", Request.PostParams["ChatMessage"] )
return ""
end
local Content = JavaScript
Content = Content .. [[
<div style="font-family: Courier; border: 1px solid #DDD; padding: 10px; width: 97%; height: 200px; overflow: scroll;" id="ChatDiv"></div>
<input type="text" id="ChatMessage" onKeyPress="if (event.keyCode == 13) { SendChatMessage(); }"><input type="submit" value="Submit" onClick="SendChatMessage();">
]]
return Content
end

View File

@ -1,157 +0,0 @@
local function Button_RemovePlugin( Name, Index )
return "<form method='POST'><input type='hidden' name='PluginName' value='"..Name.."'><input type='hidden' name='PluginIndex' value='"..Index.."'><input type='submit' name='RemovePlugin' value='Remove'></form>"
end
local function Button_EnablePlugin( Name )
return [[<form method="POST"><input type="hidden" name="PluginName", value="]].. Name ..[["><input type="submit" name="EnablePlugin" value="Enable"></form>]]
end
local function Button_DisablePlugin( Name )
return [[<form method="POST"><input type="hidden" name="PluginName", value="]].. Name ..[["><input type="submit" name="DisablePlugin" value="Disable"></form>]]
end
local function FindPluginID( SettingsIni, PluginName )
local KeyIdx = SettingsIni:FindKey("Plugins")
local NumValues = SettingsIni:GetNumValues( KeyIdx )
for i = 0, NumValues-1 do
LOGINFO( SettingsIni:GetValue(KeyIdx, i) )
if( SettingsIni:GetValue(KeyIdx, i) == PluginName ) then
return i
end
end
return nil
end
local function RemovePluginFromIni( SettingsIni, PluginName )
local KeyIdx = SettingsIni:FindKey("Plugins")
local PluginIdx = FindPluginID( SettingsIni, PluginName )
if( PluginIdx == nil ) then
LOGINFO("Got nil! NOOOO")
return false
end
local Name = SettingsIni:GetValue( KeyIdx, PluginIdx )
if( Name ~= PluginName ) then
LOGINFO("not the same name T_T '" .. Name .. "' '" .. PluginName .. "'")
end
if( (Name == PluginName) and (SettingsIni:DeleteValueByID( KeyIdx, PluginIdx ) == true) ) then
return SettingsIni:WriteFile()
end
return false
end
local function AddPluginToIni( SettingsIni, PluginName )
RemovePluginFromIni( SettingsIni, PluginName ) -- Make sure there are no duplicates
if( SettingsIni:SetValue("Plugins", "Plugin", PluginName, true ) == true ) then
return SettingsIni:WriteFile()
end
return false
end
local function HandlePluginListChanges( Request, SettingsIni )
local Content = ""
if( Request.PostParams["EnablePlugin"] ~= nil
and Request.PostParams["PluginName"] ~= nil ) then
local PluginName = Request.PostParams["PluginName"]
local PM = cRoot:Get():GetPluginManager()
if( PM:LoadPlugin( PluginName ) == false ) then
Content = "Could not enable '".. PluginName .."'!"
end
if( AddPluginToIni( SettingsIni, PluginName ) == true ) then
Content = "Enabled plugin '".. PluginName .."'"
else
Content = "Enabled plugin '".. PluginName .."' but could not add it to settings.ini"
end
elseif( Request.PostParams["DisablePlugin"] ~= nil
and Request.PostParams["PluginName"] ~= nil ) then
local PluginName = Request.PostParams["PluginName"]
local PM = cRoot:Get():GetPluginManager()
PM:DisablePlugin( PluginName )
if( RemovePluginFromIni( SettingsIni, PluginName ) == true ) then
Content = "Disabled plugin '".. PluginName .."'"
else
Content = "Disabled plugin '".. PluginName .."' but could not remove it from settings.ini"
end
end
if( #Content > 0 ) then
return "<p><font color='red'><strong>INFO: " .. Content .. "</strong></font></p>"
else
return ""
end
end
function HandleRequest_ManagePlugins( Request )
local Content = ""
if( Request.PostParams["reload"] ~= nil ) then
Content = Content .. "<head><meta http-equiv=\"refresh\" content=\"2;\"></head>"
Content = Content .. "<p>Reloading plugins... This can take a while depending on the plugins you're using.</p>"
cRoot:Get():GetPluginManager():ReloadPlugins()
return Content
end
local SettingsIni = cIniFile("settings.ini")
if( SettingsIni:ReadFile() == true ) then
Content = Content .. HandlePluginListChanges( Request, SettingsIni )
else
Content = Content .. "Cannot find/modify settings.ini"
end
local PluginManager = cRoot:Get():GetPluginManager()
PluginManager:FindPlugins() -- Refreshes the plugin list
local PluginList = PluginManager:GetAllPlugins()
Content = Content .. "<h4>Currently installed plugins</h4>"
Content = Content .. "<table>"
ActivePluginsName = {}
ActivePluginVersion = {}
InactivePlugins = {}
for k, Plugin in pairs(PluginList) do
if( Plugin ) then
table.insert( ActivePluginsName, k )
table.insert( ActivePluginVersion, Plugin:GetVersion() )
else
table.insert( InactivePlugins, k )
end
end
table.sort( ActivePluginsName )
table.sort( InactivePlugins )
for i = 1, #ActivePluginsName do
Content = Content .. "<tr><td>".. ActivePluginsName[i] .."</td>"
Content = Content .. "<td>" .. ActivePluginsName[i] .. " V. " .. ActivePluginVersion[i] .. "</td><td>" .. Button_DisablePlugin(ActivePluginsName[i]) .. "</td>"
Content = Content .. "</tr>"
end
for i = 1, #InactivePlugins do
Content = Content .. "<tr><td>".. InactivePlugins[i] .."</td>"
Content = Content .. "<td></td><td>" .. Button_EnablePlugin(InactivePlugins[i]) .. "</td>"
Content = Content .. "</tr>"
end
Content = Content .. "</table>"
Content = Content .. "<h4>Reload</h4>"
Content = Content .. "<form method='POST'>"
Content = Content .. "<p>Click the reload button to reload all plugins according to <strong>settings.ini</strong>!"
Content = Content .. "<input type='submit' name='reload' value='Reload!'></p>"
Content = Content .. "</form>"
return Content
end

View File

@ -1,35 +0,0 @@
function HandleRequest_ManageServer( Request )
local Content = ""
if (Request.PostParams["RestartServer"] ~= nil) then
cRoot:Get():QueueExecuteConsoleCommand("restart");
elseif (Request.PostParams["ReloadServer"] ~= nil) then
cRoot:Get():GetPluginManager():ReloadPlugins();
elseif (Request.PostParams["StopServer"] ~= nil) then
cRoot:Get():QueueExecuteConsoleCommand("stop");
elseif (Request.PostParams["WorldSaveAllChunks"] ~= nil) then
cRoot:Get():GetWorld(Request.PostParams["WorldSaveAllChunks"]):SaveAllChunks();
end
Content = Content .. [[
<form method="POST">
<table>
<th colspan="2">Manage Server</th>
<tr><td><input type="submit" value="Restart Server" name="RestartServer"> restart the server</td></tr> <br />
<tr><td><input type="submit" value="Reload Server" name="ReloadServer"> reload the server</td></tr> <br />
<tr><td><input type="submit" value="Stop Server" name="StopServer"> stop the server</td></tr> <br />
</th>
</table>
<table>
<th colspan="2">Manage Worlds</th>
]]
local LoopWorlds = function( World )
Content = Content .. [[
<tr><td><input type="submit" value="]] .. World:GetName() .. [[" name="WorldSaveAllChunks"> Save all the chunks of world ]] .. World:GetName() .. [[</td></tr> <br />
]]
end
cRoot:Get():ForEachWorld( LoopWorlds )
Content = Content .. "</th></table>"
return Content
end

View File

@ -1,134 +0,0 @@
local function HTML_Option( value, text, selected )
if( selected == true ) then
return [[<option value="]] .. value .. [[" selected>]] .. text .. [[</option>]]
else
return [[<option value="]] .. value .. [[">]] .. text .. [[</option>"]]
end
end
local function ShowUsersTable()
local Content = "<h4>Users</h4>"
local NumUsers = UsersIni:GetNumKeys()
Content = Content .. "<table>"
if( NumUsers > 0 ) then
Content = Content .. "<tr><th></th><th>User</th><th>Groups</th></tr>"
for i=0, NumUsers-1 do
local UserName = UsersIni:GetKeyName( i )
Content = Content .. "<tr>"
Content = Content .. "<td style='width: 10px;'>" .. i .. ".</td>"
Content = Content .. "<td>" .. UserName .. "</td>"
Content = Content .. "<td>"
Content = Content .. UsersIni:GetValue( UserName, "Groups", "-" )
Content = Content .. "</td>"
Content = Content .. "</tr>"
end
else
Content = Content .. "<tr><td>None</td></tr>"
end
Content = Content .. "</table>"
return Content
end
local function ShowGroupsTable()
local Content = "<h4>Groups</h4>"
local NumGroups = GroupsIni:GetNumKeys()
Content = Content .. "<table>"
if( NumGroups > 0 ) then
Content = Content .. "<tr><th></th><th>Name</th><th>Permissions</th><th>Color</th></tr>"
for i=0, NumGroups-1 do
local GroupName = GroupsIni:GetKeyName( i )
Content = Content .. "<tr>"
Content = Content .. "<td style='width: 10px;'>" .. i .. ".</td>"
Content = Content .. "<td>" .. GroupName .. "</td>"
Content = Content .. "<td>"
Content = Content .. GroupsIni:GetValue( GroupName, "Permissions", "-" )
Content = Content .. "</td>"
Content = Content .. "<td>"
Content = Content .. GroupsIni:GetValue( GroupName, "Color", "-" )
Content = Content .. "</td>"
Content = Content .. "</tr>"
end
else
Content = Content .. "<tr><td>None</td></tr>"
end
Content = Content .. "</table>"
return Content
end
local function HTML_Select_Group( name, defaultValue )
Groups = ""
for I=0, GroupsIni:GetNumKeys() - 1 do
Groups = Groups ..
HTML_Option(GroupsIni:KeyName(I), GroupsIni:KeyName(I), defaultValue == GroupsIni:KeyName(I) )
end
return [[<select name="]] .. name .. [[">]] .. Groups .. [[</select>]]
end
local function AddPlayers( Request )
local Content = "<h4>Add or change Players</h4>"
if( Request.PostParams["AddPlayerToGroup"] ~= nil ) then
if Request.PostParams["AddPlayer"] ~= "" then
if Request.PostParams["AddGroups"] ~= "" then
if GroupsIni:FindKey(Request.PostParams["AddGroup"]) == -1 then
return "Group does not exist"
end
UsersIni:DeleteKey(Request.PostParams["AddPlayer"])
UsersIni:GetValueSet(Request.PostParams["AddPlayer"], "Groups", Request.PostParams["AddGroup"])
UsersIni:WriteFile()
local loopPlayers = function( Player )
if Player:GetName() == Request.PostParams["AddPlayer"] then
SendMessageSuccess( Player, "You were moved to group " .. Request.PostParams["AddGroup"] )
Player:LoadPermissionsFromDisk()
end
end
local loopWorlds = function ( World )
World:ForEachPlayer( loopPlayers )
end
cRoot:Get():ForEachWorld( loopWorlds )
end
end
end
Content = Content .. [[
<form method="POST">
<table>
<tr><td style="width: 20%;">Player:</td>
<td><input type="text" name="AddPlayer" value=""></td></tr><br>
<tr><td style="width: 20%;">Group:</td>
<td>]] .. HTML_Select_Group("AddGroup", GroupsIni:KeyName(0) ) .. [[</td></tr>
</table>
<input type="submit" value="Add Player" name="AddPlayerToGroup">]]
return Content
end
function HandleRequest_Permissions( Request )
GroupsIni = cIniFile("groups.ini")
if( GroupsIni:ReadFile() == false ) then
return "Could not read groups.ini!"
end
UsersIni = cIniFile("users.ini")
if( UsersIni:ReadFile() == false ) then
return "Could not read users.ini!"
end
local Content = ""
Content = Content .. AddPlayers( Request )
Content = Content .. ShowGroupsTable()
Content = Content .. ShowUsersTable()
return Content
end

View File

@ -1,38 +0,0 @@
function HandleRequest_PlayerList( Request )
local World = cRoot:Get():GetDefaultWorld()
local Content = ""
if( Request.Params["playerlist-kick"] ~= nil ) then
local KickPlayerName = Request.Params["playerlist-kick"]
local FoundPlayerCallback = function( Player )
if( Player:GetName() == KickPlayerName ) then
Player:GetClientHandle():Kick("You were kicked from the game!")
Content = Content .. "<p>" .. KickPlayerName .. " has been kicked from the game!</p>"
end
end
if( World:DoWithPlayer( KickPlayerName, FoundPlayerCallback ) == false ) then
Content = Content .. "<p>Could not find player " .. KickPlayerName .. " !</p>"
end
end
Content = Content .. "<p>Connected Players: <b>" .. World:GetNumPlayers() .. "</b></p>"
Content = Content .. "<table>"
local PlayerNum = 0
local AddPlayerToTable = function( Player )
PlayerNum = PlayerNum + 1
Content = Content .. "<tr>"
Content = Content .. "<td style='width: 10px;'>" .. PlayerNum .. ".</td>"
Content = Content .. "<td>" .. Player:GetName() .. "</td>"
Content = Content .. "<td><a href='?playerlist-kick=" .. Player:GetName() .. "'>Kick</a></td>"
Content = Content .. "</tr>"
end
cRoot:Get():ForEachPlayer( AddPlayerToTable )
if( PlayerNum == 0 ) then
Content = Content .. "<tr><td>None</td></tr>"
end
Content = Content .. "</table>"
Content = Content .. "<br>"
return Content
end

View File

@ -1,920 +0,0 @@
-- Some HTML helper functions
local function HTML_Option( value, text, selected )
if( selected == true ) then
return [[<option value="]] .. value .. [[" selected>]] .. text .. [[</option>]]
else
return [[<option value="]] .. value .. [[">]] .. text .. [[</option>"]]
end
end
local function HTML_Select_On_Off( name, defaultValue )
return [[<select name="]] .. name .. [[">]]
.. HTML_Option("1", "On", defaultValue == 1 )
.. HTML_Option("0", "Off", defaultValue == 0 )
.. [[</select>]]
end
local function HTML_Select_Version( name, defaultValue )
return [[<select name="]] .. name .. [[">]]
.. HTML_Option("0", "Latest Version", defaultValue == 0 )
.. HTML_Option("61", "1.5.2", defaultValue == 1 )
.. HTML_Option("60", "1.5.0", defaultValue == 2 )
.. HTML_Option("49", "1.4.5", defaultValue == 3 )
.. HTML_Option("47", "1.4.2", defaultValue == 4 )
.. HTML_Option("39", "1.3.2", defaultValue == 5 )
.. HTML_Option("29", "1.2.5", defaultValue == 6 )
.. [[</select>]]
end
local function ShowGeneralSettings( Request )
local Content = ""
local InfoMsg = nil
local SettingsIni = cIniFile("settings.ini")
if( SettingsIni:ReadFile() == false ) then
InfoMsg = "<b style=\"color: red;\">ERROR: Could not read settings.ini!</b>"
end
if( Request.PostParams["general_submit"] ~= nil ) then
SettingsIni:SetValue("Server", "Description",Request.PostParams["Server_Description"],false )
if( tonumber( Request.PostParams["Server_MaxPlayers"] ) ~= nil ) then
SettingsIni:SetValue("Server", "MaxPlayers", Request.PostParams["Server_MaxPlayers"], false )
end
if( tonumber( Request.PostParams["Server_Port"] ) ~= nil ) then
if( tonumber( Request.PostParams["Server_Port"] ) > 0 ) then
SettingsIni:SetValue("Server", "Port", Request.PostParams["Server_Port"], false )
end
end
if( tonumber( Request.PostParams["Server_PortsIPv6"] ) ~= nil ) then
SettingsIni:SetValue("Server", "PortsIPv6", Request.PostParams["Server_PortsIPv6"], false )
end
if( tonumber( Request.PostParams["Server_Version"] ) ~= nil ) then
SettingsIni:SetValue("Server", "PrimaryServerVersion", Request.PostParams["Server_Version"], false )
end
if( tonumber( Request.PostParams["Authentication_Authenticate"] ) ~= nil ) then
SettingsIni:SetValue("Authentication", "Authenticate", Request.PostParams["Authentication_Authenticate"], false )
end
if( SettingsIni:WriteFile() == false ) then
InfoMsg = [[<b style="color: red;">ERROR: Could not write to settings.ini!</b>]]
else
InfoMsg = [[<b style="color: green;">INFO: Successfully saved changes to settings.ini</b>]]
end
end
Content = Content .. [[
<form method="POST">
<h4>General Settings</h4>]]
if( InfoMsg ~= nil ) then
Content = Content .. "<p>" .. InfoMsg .. "</p>"
end
Content = Content .. [[
<table>
<th colspan="2">Server</th>
<tr><td style="width: 50%;">Description:</td>
<td><input type="text" name="Server_Description" value="]] .. SettingsIni:GetValue("Server", "Description") .. [["></td></tr>
<tr><td>Max Players:</td>
<td><input type="text" name="Server_MaxPlayers" value="]] .. SettingsIni:GetValue("Server", "MaxPlayers") .. [["></td></tr>
<tr><td>Port:</td>
<td><input type="text" name="Server_Port" value="]] .. SettingsIni:GetValue("Server", "Port") .. [["></td></tr>
<tr><td>PortsIPv6:</td>
<td><input type="text" name="Server_PortsIPv6" value="]] .. SettingsIni:GetValue("Server", "PortsIPv6") .. [["></td></tr>
<tr><td>Shown Version:</td>
<td>]] .. HTML_Select_Version("Server_Version", SettingsIni:GetValueI("Server", "PrimaryServerVersion") ) .. [[</td></tr>
</table><br />
<table>
<th colspan="2">Authentication</th>
<tr><td style="width: 50%;">Authenticate:</td>
<td>]] .. HTML_Select_On_Off("Authentication_Authenticate", SettingsIni:GetValueI("Authentication", "Authenticate") ) .. [[</td></tr>
</table><br />
<input type="submit" value="Save Settings" name="general_submit"> WARNING: Any changes made here might require a server restart in order to be applied!
</form>]]
return Content
end
local function ShowMonstersSettings( Request )
local Content = ""
local InfoMsg = nil
local SettingsIni = cIniFile("settings.ini")
if( SettingsIni:ReadFile() == false ) then
InfoMsg = "<b style=\"color: red;\">ERROR: Could not read settings.ini!</b>"
end
if( Request.PostParams["monsters_submit"] ~= nil ) then
if( tonumber( Request.PostParams["Monsters_AnimalsOn"] ) ~= nil ) then
SettingsIni:SetValue("Monsters", "AnimalsOn", Request.PostParams["Monsters_AnimalsOn"], false )
end
if( tonumber( Request.PostParams["Monsters_AnimalSpawnInterval"] ) ~= nil ) then
SettingsIni:SetValue("Monsters", "AnimalSpawnInterval", Request.PostParams["Monsters_AnimalSpawnInterval"], false )
end
SettingsIni:SetValue("Monsters", "Types", Request.PostParams["Monsters_Types"], false )
if( SettingsIni:WriteFile() == false ) then
InfoMsg = "<b style=\"color: red;\">ERROR: Could not write to settings.ini!</b>"
else
InfoMsg = "<b style=\"color: green;\">INFO: Successfully saved changes to settings.ini</b>"
end
end
Content = Content .. "<form method=\"POST\">"
Content = Content .. "<h4>Monsters Settings</h4>"
if( InfoMsg ~= nil ) then
Content = Content .. "<p>" .. InfoMsg .. "</p>"
end
Content = Content .. [[
<table>
<th colspan="2">Monsters</th>
<tr><td style="width: 50%;">Animals On:</td>
<td>]] .. HTML_Select_On_Off("Monsters_AnimalsOn", SettingsIni:GetValueI("Monsters", "AnimalsOn") ) .. [[</td></tr>
<tr><td>Animal Spawn Interval:</td>
<td><input type="text" name="Monsters_AnimalSpawnInterval" value="]] .. SettingsIni:GetValue("Monsters", "AnimalSpawnInterval") .. [["></td></tr>
<tr><td>Monster Types:</td>
<td><input type="text" name="Monsters_Types" value="]] .. SettingsIni:GetValue("Monsters", "Types") .. [["></td></tr>
</table><br />
<input type="submit" value="Save Settings" name="monsters_submit"> WARNING: Any changes made here might require a server restart in order to be applied!
</form>]]
return Content
end
local function ShowWorldsSettings( Request )
local Content = ""
local InfoMsg = nil
local bSaveIni = false
local SettingsIni = cIniFile("settings.ini")
if( SettingsIni:ReadFile() == false ) then
InfoMsg = [[<b style="color: red;">ERROR: Could not read settings.ini!</b>]]
end
if( Request.PostParams["RemoveWorld"] ~= nil ) then
Content = Content .. Request.PostParams["RemoveWorld"]
local WorldIdx = string.sub( Request.PostParams["RemoveWorld"], string.len("Remove ") )
local KeyIdx = SettingsIni:FindKey("Worlds")
local WorldName = SettingsIni:GetValue( KeyIdx, WorldIdx )
if( SettingsIni:DeleteValueByID( KeyIdx, WorldIdx ) == true ) then
InfoMsg = "<b style=\"color: green;\">INFO: Successfully removed world " .. WorldName .. "!</b><br />"
bSaveIni = true
end
end
if( Request.PostParams["AddWorld"] ~= nil ) then
if( Request.PostParams["WorldName"] ~= nil and Request.PostParams["WorldName"] ~= "" ) then
SettingsIni:SetValue("Worlds", "World", Request.PostParams["WorldName"], true )
InfoMsg = "<b style=\"color: green;\">INFO: Successfully added world " .. Request.PostParams["WorldName"] .. "!</b><br />"
bSaveIni = true
end
end
if( Request.PostParams["worlds_submit"] ~= nil ) then
SettingsIni:SetValue("Worlds", "DefaultWorld", Request.PostParams["Worlds_DefaultWorld"], false )
if( Request.PostParams["Worlds_World"] ~= nil ) then
SettingsIni:SetValue("Worlds", "World", Request.PostParams["Worlds_World"], true )
end
bSaveIni = true
end
if( bSaveIni == true ) then
if( InfoMsg == nil ) then InfoMsg = "" end
if( SettingsIni:WriteFile() == false ) then
InfoMsg = InfoMsg .. "<b style=\"color: red;\">ERROR: Could not write to settings.ini!</b>"
else
InfoMsg = InfoMsg .. "<b style=\"color: green;\">INFO: Successfully saved changes to settings.ini</b>"
end
end
Content = Content .. "<h4>Worlds Settings</h4>"
if( InfoMsg ~= nil ) then
Content = Content .. "<p>" .. InfoMsg .. "</p>"
end
Content = Content .. [[
<form method="POST">
<table>
<th colspan="2">Worlds</th>
<tr><td style="width: 50%;">Default World:</td>
<td><input type="Submit" name="Worlds_DefaultWorld" value="]] .. SettingsIni:GetValue("Worlds", "DefaultWorld") .. [["></td></tr>]]
local KeyIdx = SettingsIni:FindKey("Worlds")
local NumValues = SettingsIni:GetNumValues( KeyIdx )
for i = 0, NumValues-1 do
local ValueName = SettingsIni:GetValueName(KeyIdx, i )
if( ValueName == "World" ) then
local WorldName = SettingsIni:GetValue(KeyIdx, i)
Content = Content .. [[
<tr><td>]] .. ValueName .. [[:</td><td><div style="width: 100px; display: inline-block;">]] .. WorldName .. [[</div><input type="submit" value="Remove ]] .. i .. [[" name="RemoveWorld"></td></tr>]]
end
end
Content = Content .. [[
<tr><td>Add World:</td>
<td><input type='text' name='WorldName'><input type='submit' name='AddWorld' value='Add World'></td></tr>
</table><br />
<input type="submit" value="Save Settings" name="worlds_submit"> WARNING: Any changes made here might require a server restart in order to be applied!
</form>]]
return Content
end
local function SelectWorldButton( WorldName )
return "<form method='POST'><input type='hidden' name='WorldName' value='"..WorldName.."'><input type='submit' name='SelectWorld' value='Select'></form>"
end
local function HTML_Select_Dimension( name, defaultValue )
return [[<select name="]] .. name .. [[">]]
.. HTML_Option("0", "Overworld", defaultValue == 0 )
.. HTML_Option("-1", "Nether", defaultValue == 1 )
.. HTML_Option("1", "The End", defaultValue == 2 )
.. [[</select>]]
end
local function HTML_Select_Scheme( name, defaultValue )
return [[<select name="]] .. name .. [[">]]
.. HTML_Option("Default", "Default", defaultValue == "Default" )
.. HTML_Option("Forgetful", "Forgetful", defaultValue == "Forgetful" )
.. HTML_Option("Compact", "Compact", defaultValue == "Compact" )
.. [[</select>]]
end
local function HTML_Select_GameMode( name, defaultValue )
return [[<select name="]] .. name .. [[">]]
.. HTML_Option("0", "Survival", defaultValue == 0 )
.. HTML_Option("1", "Creative", defaultValue == 1 )
.. HTML_Option("2", "Adventure", defaultValue == 2 )
.. [[</select>]]
end
local function HTML_Select_Simulator( name, defaultValue )
return [[<select name="]] .. name .. [[">]]
.. HTML_Option("Floody", "Floody", defaultValue == 0 )
.. HTML_Option("Noop", "Noop", defaultValue == 1 )
.. HTML_Option("Vaporize", "Vaporize", defaultValue == 2 )
.. [[</select>]]
end
local function HTML_Select_BiomeGen( name, defaultValue )
return [[<select name="]] .. name .. [[">]]
.. HTML_Option("MultiStepMap", "MultiStepMap", defaultValue == "MultiStepMap" )
.. HTML_Option("DistortedVoronoi", "DistortedVoronoi", defaultValue == "DistortedVoronoi" )
.. HTML_Option("Voronoi", "Voronoi", defaultValue == "Voronoi" )
.. HTML_Option("CheckerBoard", "CheckerBoard", defaultValue == "CheckerBoard" )
.. HTML_Option("Constant", "Constant", defaultValue == "Constant" )
.. [[</select>]]
end
local function HTML_Select_HeightGen( name, defaultValue )
return [[<select name="]] .. name .. [[">]]
.. HTML_Option("Noise3D", "Noise3D", defaultValue == "Noise3D" )
.. HTML_Option("Biomal", "Biomal", defaultValue == "Biomal" )
.. HTML_Option("Classic", "Classic", defaultValue == "Classic" )
.. HTML_Option("Flat", "Flat", defaultValue == "Flat" )
.. [[</select>]]
end
local function HTML_Select_CompositionGen( name, defaultValue )
return [[<select name="]] .. name .. [[">]]
.. HTML_Option("Noise3D", "Noise3D", defaultValue == "Noise3D" )
.. HTML_Option("Biomal", "Biomal", defaultValue == "Biomal" )
.. HTML_Option("Classic", "Classic", defaultValue == "Classic" )
.. HTML_Option("SameBlock", "SameBlock", defaultValue == "SameBlock" )
.. HTML_Option("DebugBiomes", "DebugBiomes", defaultValue == "DebugBiomes" )
.. [[</select>]]
end
local function HTML_Select_Generator( name, defaultValue )
return [[<select name="]] .. name .. [[">]]
.. HTML_Option("Composable", "Composable", defaultValue == "Composable" )
.. [[</select>]]
end
local function HTML_Select_Biome( name, defaultValue )
return [[<select name="]] .. name .. [[">]]
.. HTML_Option("Ocean", "Ocean", defaultValue == "Ocean" )
.. HTML_Option("Plains", "Plains", defaultValue == "Plains" )
.. HTML_Option("Extreme Hills", "Extreme Hills", defaultValue == "Extreme Hills" )
.. HTML_Option("Forest", "Forest", defaultValue == "Forest" )
.. HTML_Option("Taiga", "Taiga", defaultValue == "Taiga" )
.. HTML_Option("Swampland", "Swampland", defaultValue == "Swampland" )
.. HTML_Option("River", "River", defaultValue == "River" )
.. HTML_Option("Hell", "Hell", defaultValue == "Hell" )
.. HTML_Option("Sky", "Sky", defaultValue == "Sky" )
.. HTML_Option("FrozenOcean", "FrozenOcean", defaultValue == "FrozenOcean" )
.. HTML_Option("FrozenRiver", "FrozenRiver", defaultValue == "FrozenRiver" )
.. HTML_Option("Ice Plains", "Ice Plains", defaultValue == "Ice Plains" )
.. HTML_Option("Ice Mountains", "Ice Mountains", defaultValue == "Ice Mountains" )
.. HTML_Option("MushroomIsland", "MushroomIsland", defaultValue == "MushroomIsland" )
.. HTML_Option("MushroomIslandShore", "MushroomIslandShore", defaultValue == "MushroomIslandShore" )
.. HTML_Option("Beach", "Beach", defaultValue == "Beach" )
.. HTML_Option("DesertHills", "DesertHills", defaultValue == "DesertHills" )
.. HTML_Option("ForestHills", "ForestHills", defaultValue == "ForestHills" )
.. HTML_Option("TaigaHills", "TaigaHills", defaultValue == "TaigaHills" )
.. HTML_Option("Extreme Hills Edge", "Extreme Hills Edge", defaultValue == "Extreme Hills Edge" )
.. HTML_Option("Jungle", "Jungle", defaultValue == "Jungle" )
.. HTML_Option("JungleHills", "JungleHills", defaultValue == "JungleHills" )
.. [[</select>]]
end
function ShowWorldSettings( Request )
local Content = ""
local InfoMsg = nil
local SettingsIni = cIniFile("settings.ini")
if( SettingsIni:ReadFile() == false ) then
InfoMsg = [[<b style="color: red;">ERROR: Could not read settings.ini!</b>]]
end
if (Request.PostParams["SelectWorld"] ~= nil and Request.PostParams["WorldName"] ~= nil) then -- World is selected!
WORLD = Request.PostParams["WorldName"]
SelectedWorld = cRoot:Get():GetWorld(WORLD)
elseif SelectedWorld == nil then
WORLD = SettingsIni:GetValue("Worlds", "DefaultWorld")
SelectedWorld = cRoot:Get():GetWorld( WORLD )
end
local WorldIni = cIniFile(SelectedWorld:GetName() .. "/world.ini")
WorldIni:ReadFile()
if (Request.PostParams["world_submit"]) ~= nil then
if( tonumber( Request.PostParams["World_Dimension"] ) ~= nil ) then
WorldIni:DeleteValue( "General", "Dimension" )
WorldIni:SetValue( "General", "Dimension", Request.PostParams["World_Dimension"] )
end
if( tonumber( Request.PostParams["World_Schema"] ) ~= nil ) then
WorldIni:DeleteValue( "General", "Schema" )
WorldIni:SetValue( "General", "Schema", Request.PostParams["World_Schema"] )
end
if( tonumber( Request.PostParams["World_SpawnX"] ) ~= nil ) then
WorldIni:DeleteValue( "SpawnPosition", "X" )
WorldIni:SetValue( "SpawnPosition", "X", Request.PostParams["World_SpawnX"] )
end
if( tonumber( Request.PostParams["World_SpawnY"] ) ~= nil ) then
WorldIni:DeleteValue( "SpawnPosition", "Y" )
WorldIni:SetValue( "SpawnPosition", "Y", Request.PostParams["World_SpawnY"] )
end
if( tonumber( Request.PostParams["World_SpawnZ"] ) ~= nil ) then
WorldIni:DeleteValue( "SpawnPosition", "Z" )
WorldIni:SetValue( "SpawnPosition", "Z", Request.PostParams["World_SpawnZ"] )
end
if( tonumber( Request.PostParams["LimitWorldWidth"] ) ~= nil ) then
WorldIni:DeleteValue( "WorldLimit", "LimitRadius" )
WorldIni:SetValue( "WorldLimit", "LimitRadius", Request.PostParams["LimitWorldWidth"] )
end
if( tonumber( Request.PostParams["World_Seed"] ) ~= nil ) then
WorldIni:DeleteValue( "Seed", "Seed" )
WorldIni:SetValue( "Seed", "Seed", Request.PostParams["World_Seed"] )
end
if( tonumber( Request.PostParams["World_PVP"] ) ~= nil ) then
WorldIni:DeleteValue( "PVP", "Enabled" )
WorldIni:SetValue( "PVP", "Enabled", Request.PostParams["World_PVP"] )
end
if( tonumber( Request.PostParams["World_GameMode"] ) ~= nil ) then
WorldIni:DeleteValue( "GameMode", "GameMode" )
WorldIni:SetValue( "GameMode", "GameMode", Request.PostParams["World_GameMode"] )
end
if( tonumber( Request.PostParams["World_DeepSnow"] ) ~= nil ) then
WorldIni:DeleteValue( "Physics", "DeepSnow" )
WorldIni:SetValue( "Physics", "DeepSnow", Request.PostParams["World_DeepSnow"] )
end
if( tonumber( Request.PostParams["World_SandInstantFall"] ) ~= nil ) then
WorldIni:DeleteValue( "Physics", "SandInstantFall" )
WorldIni:SetValue( "Physics", "SandInstantFall", Request.PostParams["World_SandInstantFall"] )
end
if( tonumber( Request.PostParams["World_WaterSimulator"] ) ~= nil ) then
WorldIni:DeleteValue( "Physics", "WaterSimulator" )
WorldIni:SetValue( "Physics", "WaterSimulator", Request.PostParams["World_WaterSimulator"] )
end
if( tonumber( Request.PostParams["World_LavaSimulator"] ) ~= nil ) then
WorldIni:DeleteValue( "Physics", "LavaSimulator" )
WorldIni:SetValue( "Physics", "LavaSimulator", Request.PostParams["World_LavaSimulator"] )
end
if( tonumber( Request.PostParams["World_MaxSugarcaneHeight"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "MaxSugarcaneHeight" )
WorldIni:SetValue( "Plants", "MaxSugarcaneHeight", Request.PostParams["World_MaxSugarcaneHeight"] )
end
if( tonumber( Request.PostParams["World_MaxCactusHeight"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "MaxCactusHeight" )
WorldIni:SetValue( "Plants", "MaxCactusHeight", Request.PostParams["World_MaxCactusHeight"] )
end
if( tonumber( Request.PostParams["World_CarrotsBonemealable"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "IsCarrotsBonemealable" )
WorldIni:SetValue( "Plants", "IsCarrotsBonemealable", Request.PostParams["World_CarrotsBonemealable"] )
end
if( tonumber( Request.PostParams["World_CropsBonemealable"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "IsCropsBonemealable" )
WorldIni:SetValue( "Plants", "IsCropsBonemealable", Request.PostParams["World_CropsBonemealable"] )
end
if( tonumber( Request.PostParams["World_GrassBonemealable"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "IsGrassBonemealable" )
WorldIni:SetValue( "Plants", "IsGrassBonemealable", Request.PostParams["World_GrassBonemealable"] )
end
if( tonumber( Request.PostParams["World_SaplingBonemealable"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "IsSaplingBonemealable" )
WorldIni:SetValue( "Plants", "IsSaplingBonemealable", Request.PostParams["World_SaplingBonemealable"] )
end
if( tonumber( Request.PostParams["World_MelonStemBonemealable"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "IsMelonStemBonemealable" )
WorldIni:SetValue( "Plants", "IsMelonStemBonemealable", Request.PostParams["World_MelonStemBonemealable"] )
end
if( tonumber( Request.PostParams["World_MelonBonemealable"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "IsMelonBonemealable" )
WorldIni:SetValue( "Plants", "IsMelonBonemealable", Request.PostParams["World_MelonBonemealable"] )
end
if( tonumber( Request.PostParams["World_PotatoesBonemealable"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "IsPotatoesBonemealable" )
WorldIni:SetValue( "Plants", "IsPotatoesBonemealable", Request.PostParams["World_PotatoesBonemealable"] )
end
if( tonumber( Request.PostParams["World_PumpkinStemBonemealable"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "IsPumpkinStemBonemealable" )
WorldIni:SetValue( "Plants", "IsPumpkinStemBonemealable", Request.PostParams["World_PumpkinStemBonemealable"] )
end
if( tonumber( Request.PostParams["World_PumpkinBonemealable"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "IsPumpkinBonemealable" )
WorldIni:SetValue( "Plants", "IsPumpkinBonemealable", Request.PostParams["World_PumpkinBonemealable"] )
end
if( tonumber( Request.PostParams["World_SugarCaneBonemealable"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "IsSugarCaneBonemealable" )
WorldIni:SetValue( "Plants", "IsSugarCaneBonemealable", Request.PostParams["World_SugarCaneBonemealable"] )
end
if( tonumber( Request.PostParams["World_CactusBonemealable"] ) ~= nil ) then
WorldIni:DeleteValue( "Plants", "IsCactusBonemealable" )
WorldIni:SetValue( "Plants", "IsCactusBonemealable", Request.PostParams["World_CactusBonemealable"] )
end
if( ( Request.PostParams["World_BiomeGen"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "BiomeGen" )
WorldIni:SetValue( "Generator", "BiomeGen", Request.PostParams["World_BiomeGen"] )
end
if( ( Request.PostParams["World_Biome"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "ConstantBiome" )
WorldIni:SetValue( "Generator", "ConstantBiome", Request.PostParams["World_Biome"] )
end
if( ( Request.PostParams["World_MultiStepMapOceanCellSize"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "MultiStepMapOceanCellSize" )
WorldIni:SetValue( "Generator", "MultiStepMapOceanCellSize", Request.PostParams["World_MultiStepMapOceanCellSize"] )
end
if( ( Request.PostParams["World_MultiStepMapMushroomIslandSize"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "MultiStepMapMushroomIslandSize" )
WorldIni:SetValue( "Generator", "MultiStepMapMushroomIslandSize", Request.PostParams["World_MultiStepMapMushroomIslandSize"] )
end
if( ( Request.PostParams["World_MultiStepMapRiverCellSize"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "MultiStepMapRiverCellSize" )
WorldIni:SetValue( "Generator", "MultiStepMapRiverCellSize", Request.PostParams["World_MultiStepMapRiverCellSize"] )
end
if( ( Request.PostParams["World_MultiStepMapRiverWidth"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "MultiStepMapRiverWidth" )
WorldIni:SetValue( "Generator", "MultiStepMapRiverWidth", Request.PostParams["World_MultiStepMapRiverWidth"] )
end
if( ( Request.PostParams["World_MultiStepMapLandBiomeSize"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "MultiStepMapLandBiomeSize" )
WorldIni:SetValue( "Generator", "MultiStepMapLandBiomeSize", Request.PostParams["World_MultiStepMapLandBiomeSize"] )
end
if( ( Request.PostParams["World_DistortedVoronoiCellSize"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "DistortedVoronoiCellSize" )
WorldIni:SetValue( "Generator", "DistortedVoronoiCellSize", Request.PostParams["World_DistortedVoronoiCellSize"] )
end
if( ( Request.PostParams["World_DistortedVoronoiBiomes"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "DistortedVoronoiBiomes" )
WorldIni:SetValue( "Generator", "DistortedVoronoiBiomes", Request.PostParams["World_DistortedVoronoiBiomes"] )
end
if( ( Request.PostParams["World_VoronoiCellSize"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "VoronoiCellSize" )
WorldIni:SetValue( "Generator", "VoronoiCellSize", Request.PostParams["World_VoronoiCellSize"] )
end
if( ( Request.PostParams["World_VoronoiBiomesdVoronoiBiomes"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "VoronoiBiomes" )
WorldIni:SetValue( "Generator", "VoronoiBiomes", Request.PostParams["World_VoronoiBiomes"] )
end
if( ( Request.PostParams["World_CheckerBoardBiomes"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "CheckerBoardBiomes" )
WorldIni:SetValue( "Generator", "CheckerBoardBiomes", Request.PostParams["World_CheckerBoardBiomes"] )
end
if( ( Request.PostParams["World_CheckerBoardBiomeSize"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "CheckerBoardBiomeSize" )
WorldIni:SetValue( "Generator", "CheckerBoardBiomeSize", Request.PostParams["World_CheckerBoardBiomeSize"] )
end
if( ( Request.PostParams["World_HeightGen"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "HeightGen" )
WorldIni:SetValue( "Generator", "HeightGen", Request.PostParams["World_HeightGen"] )
end
if( ( Request.PostParams["World_FlatHeight"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "FlatHeight" )
WorldIni:SetValue( "Generator", "FlatHeight", Request.PostParams["World_FlatHeight"] )
end
if( ( Request.PostParams["World_CompositionGen"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "CompositionGen" )
WorldIni:SetValue( "Generator", "CompositionGen", Request.PostParams["World_CompositionGen"] )
end
if( ( Request.PostParams["World_Noise3DSeaLevel"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "Noise3DSeaLevel" )
WorldIni:SetValue( "Generator", "Noise3DSeaLevel", Request.PostParams["World_Noise3DSeaLevel"] )
end
if( ( Request.PostParams["World_Noise3DHeightAmplification"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "Noise3DHeightAmplification" )
WorldIni:SetValue( "Generator", "Noise3DHeightAmplification", Request.PostParams["World_Noise3DHeightAmplification"] )
end
if( ( Request.PostParams["World_Noise3DMidPoint"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "Noise3DMidPoint" )
WorldIni:SetValue( "Generator", "Noise3DMidPoint", Request.PostParams["World_Noise3DMidPoint"] )
end
if( ( Request.PostParams["World_Noise3DFrequencyX"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "Noise3DFrequencyX" )
WorldIni:SetValue( "Generator", "Noise3DFrequencyX", Request.PostParams["World_Noise3DFrequencyX"] )
end
if( ( Request.PostParams["World_Noise3DFrequencyY"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "Noise3DFrequencyY" )
WorldIni:SetValue( "Generator", "Noise3DFrequencyY", Request.PostParams["World_Noise3DFrequencyY"] )
end
if( ( Request.PostParams["World_Noise3DFrequencyZ"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "Noise3DFrequencyZ" )
WorldIni:SetValue( "Generator", "Noise3DFrequencyZ", Request.PostParams["World_Noise3DFrequencyZ"] )
end
if( ( Request.PostParams["World_Noise3DAirThreshold"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "Noise3DAirThreshold" )
WorldIni:SetValue( "Generator", "Noise3DAirThreshold", Request.PostParams["World_Noise3DAirThreshold"] )
end
if( ( Request.PostParams["World_ClassicSeaLevel"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "ClassicSeaLevel" )
WorldIni:SetValue( "Generator", "ClassicSeaLevel", Request.PostParams["World_ClassicSeaLevel"] )
end
if( ( Request.PostParams["World_ClassicBeachHeight"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "ClassicBeachHeight" )
WorldIni:SetValue( "Generator", "ClassicBeachHeight", Request.PostParams["World_ClassicBeachHeight"] )
end
if( ( Request.PostParams["World_ClassicBeachDepth"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "ClassicBeachDepth" )
WorldIni:SetValue( "Generator", "ClassicBeachDepth", Request.PostParams["World_ClassicBeachDepth"] )
end
if( ( Request.PostParams["World_ClassicBlockTop"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "ClassicBlockTop" )
WorldIni:SetValue( "Generator", "ClassicBlockTop", Request.PostParams["World_ClassicBlockTop"] )
end
if( ( Request.PostParams["World_ClassicBlockMiddle"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "ClassicBlockMiddle" )
WorldIni:SetValue( "Generator", "ClassicBlockMiddle", Request.PostParams["World_ClassicBlockMiddle"] )
end
if( ( Request.PostParams["World_ClassicBlockBottom"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "ClassicBlockBottom" )
WorldIni:SetValue( "Generator", "ClassicBlockBottom", Request.PostParams["World_ClassicBlockBottom"] )
end
if( ( Request.PostParams["World_ClassicBlockBeach"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "ClassicBlockBeach" )
WorldIni:SetValue( "Generator", "ClassicBlockBeach", Request.PostParams["World_ClassicBlockBeach"] )
end
if( ( Request.PostParams["World_ClassicBlockBeachBottom"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "ClassicBlockBeachBottom" )
WorldIni:SetValue( "Generator", "ClassicBlockBeachBottom", Request.PostParams["World_ClassicBlockBeachBottom"] )
end
if( ( Request.PostParams["World_ClassicBlockSea"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "ClassicBlockSea" )
WorldIni:SetValue( "Generator", "ClassicBlockSea", Request.PostParams["World_ClassicBlockSea"] )
end
if( ( Request.PostParams["World_SameBlockType"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "SameBlockType" )
WorldIni:SetValue( "Generator", "SameBlockType", Request.PostParams["World_SameBlockType"] )
end
if( ( Request.PostParams["World_SameBlockBedrocked"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "SameBlockBedrocked" )
WorldIni:SetValue( "Generator", "SameBlockBedrocked", Request.PostParams["World_SameBlockBedrocked"] )
end
if( ( Request.PostParams["World_Structures"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "Structures" )
WorldIni:SetValue( "Generator", "Structures", Request.PostParams["World_Structures"] )
end
if( ( Request.PostParams["World_Finishers"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "Finishers" )
WorldIni:SetValue( "Generator", "Finishers", Request.PostParams["World_Finishers"] )
end
if( ( Request.PostParams["World_Generator"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "Generator" )
WorldIni:SetValue( "Generator", "Generator", Request.PostParams["World_Generator"] )
end
if( ( Request.PostParams["World_MineShaftsGridSize"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "MineShaftsGridSize" )
WorldIni:SetValue( "Generator", "MineShaftsGridSize", Request.PostParams["World_MineShaftsGridSize"] )
end
if( ( Request.PostParams["World_MineShaftsMaxSystemSize"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "MineShaftsMaxSystemSize" )
WorldIni:SetValue( "Generator", "MineShaftsMaxSystemSize", Request.PostParams["World_MineShaftsMaxSystemSize"] )
end
if( ( Request.PostParams["World_MineShaftsChanceCorridor"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "MineShaftsChanceCorridor" )
WorldIni:SetValue( "Generator", "MineShaftsChanceCorridor", Request.PostParams["World_MineShaftsChanceCorridor"] )
end
if( ( Request.PostParams["World_MineShaftsChanceCrossing"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "MineShaftsChanceCrossing" )
WorldIni:SetValue( "Generator", "MineShaftsChanceCrossing", Request.PostParams["World_MineShaftsChanceCrossing"] )
end
if( ( Request.PostParams["World_MineShaftsChanceStaircase"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "MineShaftsChanceStaircase" )
WorldIni:SetValue( "Generator", "MineShaftsChanceStaircase", Request.PostParams["World_MineShaftsChanceStaircase"] )
end
if( ( Request.PostParams["World_LavaLakesProbability"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "LavaLakesProbability" )
WorldIni:SetValue( "Generator", "LavaLakesProbability", Request.PostParams["World_LavaLakesProbability"] )
end
if( ( Request.PostParams["World_WaterLakesProbability"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "WaterLakesProbability" )
WorldIni:SetValue( "Generator", "WaterLakesProbability", Request.PostParams["World_WaterLakesProbability"] )
end
if( ( Request.PostParams["World_BottomLavaLevel"] ) ~= nil ) then
WorldIni:DeleteValue( "Generator", "BottomLavaLevel" )
WorldIni:SetValue( "Generator", "BottomLavaLevel", Request.PostParams["World_BottomLavaLevel"] )
end
WorldIni:WriteFile()
end
Content = Content .. "<h4>World for operations: " .. WORLD .. "</h4>"
Content = Content .. "<table>"
local WorldNum = 0
local AddWorldToTable = function(World)
WorldNum = WorldNum + 1
Content = Content .. "<tr>"
Content = Content .. "<td style='width: 10px;'>" .. WorldNum .. ".</td>"
Content = Content .. "<td>" .. World:GetName() .. "</td>"
Content = Content .. "<td>" .. SelectWorldButton(World:GetName()) .. "</td>"
Content = Content .. "</tr>"
end
cRoot:Get():ForEachWorld(AddWorldToTable)
Content = Content .. "</table>"
Content = Content .. [[<table>
<form method="POST">
<br />
<th colspan="2">General</th>
<tr><td>Dimension:</td>
<td>]] .. HTML_Select_Dimension("World_Dimension", WorldIni:GetValueI("General", "Dimension") ) .. [[</td></tr>
</table>
<br />
<table>
<th colspan="2">Storage</th>
<tr><td>Schema:</td>
<td>]] .. HTML_Select_Scheme("World_Schema", WorldIni:GetValueI("Storage", "Schema") ) .. [[</td></tr>
</table>
<br />
<table>
<th colspan="2">Spawn Position</th>
<tr><td>X:</td>
<td><input type="text" name="World_SpawnX" value="]] .. WorldIni:GetValue("SpawnPosition", "X") .. [["></td></tr>
<tr><td>Y:</td>
<td><input type="text" name="World_SpawnY" value="]] .. WorldIni:GetValue("SpawnPosition", "Y") .. [["></td></tr>
<tr><td>Z:</td>
<td><input type="text" name="World_SpawnZ" value="]] .. WorldIni:GetValue("SpawnPosition", "Z") .. [["></td></tr>
</table>
<br />
<table>
<th colspan="2">LimitWorld</th>
<tr><td>Max chunks from spawn (0 to disable):</td>
<td><input type="text" name="LimitWorldWidth" value="]] .. WorldIni:GetValue("WorldLimit", "LimitRadius") .. [["></td></tr>
</table><br />
<table>
<th colspan="2">Seed</th>
<tr><td>Seed:</td>
<td><input type="text" name="World_Seed" value="]] .. WorldIni:GetValue("Seed", "Seed") .. [["></td></tr>
</table>
<br />
<table>
<th colspan="2">PVP</th>
<tr><td style="width: 50%;">PVP:</td>
<td>]] .. HTML_Select_On_Off("World_PVP", WorldIni:GetValueI("PVP", "Enabled") ) .. [[</td></tr>
</table>
<br />
<table>
<th colspan="2">GameMode</th>
<tr><td style="width: 50%;">GameMode:</td>
<td>]] .. HTML_Select_GameMode("World_GameMode", WorldIni:GetValueI("GameMode", "GameMode") ) .. [[</td></tr>
</table>
<br />
<table>
<th colspan="2">Physics</th>
<tr><td style="width: 50%;">DeepSnow:</td>
<td>]] .. HTML_Select_On_Off("World_DeepSnow", WorldIni:GetValueI("Physics", "DeepSnow") ) .. [[</td></tr>
<tr><td style="width: 50%;">SandInstantFall:</td>
<td>]] .. HTML_Select_On_Off("World_SandInstantFall", WorldIni:GetValueI("Physics", "SandInstantFall") ) .. [[</td></tr>
<tr><td style="width: 50%;">WaterSimulator:</td>
<td>]] .. HTML_Select_Simulator("World_WaterSimulator", WorldIni:GetValue("Physics", "WaterSimulator") ) .. [[</td></tr>
<tr><td style="width: 50%;">LavaSimulator:</td>
<td>]] .. HTML_Select_Simulator("World_LavaSimulator", WorldIni:GetValue("Physics", "LavaSimulator") ) .. [[</td></tr>
</table>
<br />
<table>
<th colspan="2">Plants</th>
<tr><td>MaxCactusHeight:</td>
<td><input type="text" name="World_MaxCactusHeight" value="]] .. WorldIni:GetValue("Plants", "MaxCactusHeight") .. [["></td></tr>
<tr><td>MaxSugarcaneHeigh:</td>
<td><input type="text" name="World_MaxSugarcaneHeight" value="]] .. WorldIni:GetValue("Plants", "MaxSugarcaneHeight") .. [["></td></tr>
<tr><td style="width: 50%;">CarrotsBonemealable:</td>
<td>]] .. HTML_Select_On_Off("World_CarrotsBonemealable", WorldIni:GetValueI("Plants", "IsCarrotsBonemealable") ) .. [[</td></tr>
<tr><td style="width: 50%;">CropsBonemealable:</td>
<td>]] .. HTML_Select_On_Off("World_CropsBonemealable", WorldIni:GetValueI("Plants", "IsCropsBonemealable") ) .. [[</td></tr>
<tr><td style="width: 50%;">GrassBonemealabl:</td>
<td>]] .. HTML_Select_On_Off("World_GrassBonemealable", WorldIni:GetValueI("Plants", "IsGrassBonemealable") ) .. [[</td></tr>
<tr><td style="width: 50%;">SaplingBonemealable:</td>
<td>]] .. HTML_Select_On_Off("World_SaplingBonemealable", WorldIni:GetValueI("Plants", "IsSaplingBonemealable") ) .. [[</td></tr>
<tr><td style="width: 50%;">MelonStemBonemealable:</td>
<td>]] .. HTML_Select_On_Off("World_MelonStemBonemealable", WorldIni:GetValueI("Plants", "IsMelonStemBonemealable") ) .. [[</td></tr>
<tr><td style="width: 50%;">MelonBonemealable:</td>
<td>]] .. HTML_Select_On_Off("World_MelonBonemealable", WorldIni:GetValueI("Plants", "IsMelonBonemealable") ) .. [[</td></tr>
<tr><td style="width: 50%;">PotatoesBonemealable:</td>
<td>]] .. HTML_Select_On_Off("World_PotatoesBonemealable", WorldIni:GetValueI("Plants", "IsPotatoesBonemealable") ) .. [[</td></tr>
<tr><td style="width: 50%;">PumpkinStemBonemealable:</td>
<td>]] .. HTML_Select_On_Off("World_PumpkinStemBonemealable", WorldIni:GetValueI("Plants", "IsPumpkinStemBonemealable") ) .. [[</td></tr>
<tr><td style="width: 50%;">PumpkinBonemealable:</td>
<td>]] .. HTML_Select_On_Off("World_PumpkinBonemealable", WorldIni:GetValueI("Plants", "IsPumpkinBonemealable") ) .. [[</td></tr>
<tr><td style="width: 50%;">SugarcaneBonemealabl:</td>
<td>]] .. HTML_Select_On_Off("World_SugarcaneBonemealable", WorldIni:GetValueI("Plants", "IsSugarcaneBonemealable") ) .. [[</td></tr>
<tr><td style="width: 50%;">CactusBonemealable:</td>
<td>]] .. HTML_Select_On_Off("World_CactusBonemealable", WorldIni:GetValueI("Plants", "IsCactusBonemealable") ) .. [[</td></tr>
</table>
<br />
<table>
<th colspan="2">Generator</th>
<tr><td style="width: 50%;">BiomeGen:</td>
<td>]] .. HTML_Select_BiomeGen("World_BiomeGen", WorldIni:GetValue("Generator", "BiomeGen") ) .. [[</td></tr>
<tr><td style="width: 50%;">HeightGen:</td>
<td>]] .. HTML_Select_HeightGen("World_HeightGen", WorldIni:GetValue("Generator", "HeightGen") ) .. [[</td></tr>
<tr><td style="width: 50%;">CompositionGen:</td>
<td>]] .. HTML_Select_CompositionGen("World_CompositionGen", WorldIni:GetValue("Generator", "CompositionGen") ) .. [[</td></tr>
<tr><td>Structures:</td>
<td><input type="text" size="50" name="World_Structures" value="]] .. WorldIni:GetValue("Generator", "Structures") .. [["></td></tr>
<tr><td>Finishers:</td>
<td><input type="text" size="50" name="World_Finishers" value="]] .. WorldIni:GetValue("Generator", "Finishers") .. [["></td></tr>
<tr><td style="width: 50%;">Generator:</td>
<td>]] .. HTML_Select_Generator("World_Generator", WorldIni:GetValue("Generator", "Generator") ) .. [[</td></tr>
</table>
<br />
<table>
<th colspan="1">Finetuning</th><br />
</table>
<table>
]]
if WorldIni:GetValue( "Generator", "BiomeGen" ) == "Constant" then
Content = Content .. [[
<th colspan="2">Biome Generator</th>
<tr><td style="width: 50%;">ConstantBiome:</td>
<td>]] .. HTML_Select_Biome( "World_Biome", WorldIni:GetValue("Generator", "ConstantBiome" ) ) .. [[</td></tr>]]
elseif WorldIni:GetValue( "Generator", "BiomeGen" ) == "MultiStepMap" then
Content = Content .. [[
<th colspan="2">Biome Generator</th>
<tr><td>MultiStepMapOceanCellSize:</td>
<td><input type="text" name="World_MultiStepMapOceanCellSize" value="]] .. WorldIni:GetValue("Generator", "MultiStepMapOceanCellSize") .. [["></td></tr>
<tr><td>MultiStepMapOceanCellSize:</td>
<td><input type="text" name="World_MultiStepMapMushroomIslandSize" value="]] .. WorldIni:GetValue("Generator", "MultiStepMapMushroomIslandSize") .. [["></td></tr>
<tr><td>MultiStepMapOceanCellSize:</td>
<td><input type="text" name="World_MultiStepMapRiverCellSize" value="]] .. WorldIni:GetValue("Generator", "MultiStepMapRiverCellSize") .. [["></td></tr>
<tr><td>MultiStepMapOceanCellSize:</td>
<td><input type="text" name="World_MultiStepMapRiverWidth" value="]] .. WorldIni:GetValue("Generator", "MultiStepMapRiverWidth") .. [["></td></tr>
<tr><td>MultiStepMapOceanCellSize:</td>
<td><input type="text" name="World_MultiStepMapLandBiomeSize" value="]] .. WorldIni:GetValue("Generator", "MultiStepMapLandBiomeSize") .. [["></td></tr>]]
elseif WorldIni:GetValue( "Generator", "BiomeGen" ) == "DistortedVoronoi" then
Content = Content .. [[
<th colspan="2">Biome Generator</th>
<tr><td>DistortedVoronoiCellSize:</td>
<td><input type="text" name="World_DistortedVoronoiCellSize" value="]] .. WorldIni:GetValue("Generator", "DistortedVoronoiCellSize") .. [["></td></tr>
<tr><td>DistortedVoronoiBiomes:</td>
<td><input type="text" name="World_DistortedVoronoiBiomes" value="]] .. WorldIni:GetValue("Generator", "DistortedVoronoiBiomes") .. [["></td></tr>]]
elseif WorldIni:GetValue( "Generator", "BiomeGen" ) == "Voronoi" then
Content = Content .. [[
<th colspan="2">Biome Generator</th>
<tr><td>VoronoiCellSize:</td>
<td><input type="text" name="World_VoronoiCellSize" value="]] .. WorldIni:GetValue("Generator", "VoronoiCellSize") .. [["></td></tr>
<tr><td>VoronoiBiomes:</td>
<td><input type="text" name="World_VoronoiBiomes" value="]] .. WorldIni:GetValue("Generator", "VoronoiBiomes") .. [["></td></tr>]]
elseif WorldIni:GetValue( "Generator", "BiomeGen" ) == "CheckerBoard" then
Content = Content .. [[
<th colspan="2">Biome Generator</th>
<tr><td>CheckerBoardBiomes:</td>
<td><input type="text" name="World_CheckerBoardBiomes" value="]] .. WorldIni:GetValue("Generator", "CheckerBoardBiomes") .. [["></td></tr>
<tr><td>CheckerBoardBiomeSize:</td>
<td><input type="text" name="World_CheckerBoardBiomeSize" value="]] .. WorldIni:GetValue("Generator", "CheckerBoardBiomeSize") .. [["></td></tr>]]
end
if WorldIni:GetValue( "Generator", "CompositionGen" ) == "Noise3D" then
Content = Content .. [[
<th colspan="2">Composition Generator</th>
<tr><td>Noise3DSeaLevel:</td>
<td><input type="text" name="World_Noise3DSeaLevel" value="]] .. WorldIni:GetValue("Generator", "Noise3DSeaLevel") .. [["></td></tr>
<tr><td>Noise3DHeightAmplification:</td>
<td><input type="text" name="World_Noise3DHeightAmplification" value="]] .. WorldIni:GetValue("Generator", "Noise3DHeightAmplification") .. [["></td></tr>
<tr><td>Noise3DMidPoint:</td>
<td><input type="text" name="World_Noise3DMidPoint" value="]] .. WorldIni:GetValue("Generator", "Noise3DMidPoint") .. [["></td></tr>
<tr><td>Noise3DFrequencyX:</td>
<td><input type="text" name="World_Noise3DFrequencyX" value="]] .. WorldIni:GetValue("Generator", "Noise3DFrequencyX") .. [["></td></tr>
<tr><td>Noise3DFrequencyY:</td>
<td><input type="text" name="World_Noise3DFrequencyY" value="]] .. WorldIni:GetValue("Generator", "Noise3DFrequencyY") .. [["></td></tr>
<tr><td>Noise3DFrequencyZ:</td>
<td><input type="text" name="World_Noise3DFrequencyZ" value="]] .. WorldIni:GetValue("Generator", "Noise3DFrequencyZ") .. [["></td></tr>
<tr><td>Noise3DAirThreshold:</td>
<td><input type="text" name="World_Noise3DAirThreshold" value="]] .. WorldIni:GetValue("Generator", "Noise3DAirThreshold") .. [["></td></tr>]]
elseif WorldIni:GetValue( "Generator", "CompositionGen" ) == "Classic" then
Content = Content .. [[
<th colspan="2">Composition Generator</th>
<tr><td>ClassicSeaLevel:</td>
<td><input type="text" name="World_ClassicSeaLevel" value="]] .. WorldIni:GetValue("Generator", "ClassicSeaLevel") .. [["></td></tr>
<tr><td>ClassicBeachHeight:</td>
<td><input type="text" name="World_ClassicBeachHeight" value="]] .. WorldIni:GetValue("Generator", "ClassicBeachHeight") .. [["></td></tr>
<tr><td>ClassicBeachDepth:</td>
<td><input type="text" name="World_ClassicBeachDepth" value="]] .. WorldIni:GetValue("Generator", "ClassicBeachDepth") .. [["></td></tr>
<tr><td>ClassicBlockTop:</td>
<td><input type="text" name="World_ClassicBlockTop" value="]] .. WorldIni:GetValue("Generator", "ClassicBlockTop") .. [["></td></tr>
<tr><td>ClassicBlockMiddle:</td>
<td><input type="text" name="World_ClassicBlockMiddle" value="]] .. WorldIni:GetValue("Generator", "ClassicBlockMiddle") .. [["></td></tr>
<tr><td>ClassicBlockBottom:</td>
<td><input type="text" name="World_ClassicBlockBottom" value="]] .. WorldIni:GetValue("Generator", "ClassicBlockBottom") .. [["></td></tr>
<tr><td>ClassicBlockBeach:</td>
<td><input type="text" name="World_ClassicBlockBeach" value="]] .. WorldIni:GetValue("Generator", "ClassicBlockBeach") .. [["></td></tr>
<tr><td>ClassicBlockBeachBottom:</td>
<td><input type="text" name="World_ClassicBlockBeachBottom" value="]] .. WorldIni:GetValue("Generator", "ClassicBlockBeachBottom") .. [["></td></tr>
<tr><td>ClassicBlockSea:</td>
<td><input type="text" name="World_ClassicBlockSea" value="]] .. WorldIni:GetValue("Generator", "ClassicBlockSea") .. [["></td></tr>]]
elseif WorldIni:GetValue( "Generator", "CompositionGen" ) == "SameBlock" then
Content = Content .. [[
<th colspan="2">Composition Generator</th>
<tr><td>SameBlockType:</td>
<td><input type="text" name="World_SameBlockType" value="]] .. WorldIni:GetValue("Generator", "SameBlockType") .. [["></td></tr>
<tr><td>SameBlockBedrocked:</td>
<td><input type="text" name="World_SameBlockBedrocked" value="]] .. WorldIni:GetValue("Generator", "SameBlockBedrocked") .. [["></td></tr>]]
end
if WorldIni:GetValue( "Generator", "HeightGen" ) == "Flat" then
Content = Content .. [[
<th colspan="2">Height Generator</th>
<tr><td>FlatHeight:</td>
<td><input type="text" name="World_FlatHeight" value="]] .. WorldIni:GetValue("Generator", "FlatHeight") .. [["></td></tr>]]
end
if string.find( WorldIni:GetValue( "Generator", "Structures" ), "MineShafts" ) ~= nil then
Content = Content .. [[
<th colspan="2">MineShafts</th>
<tr><td>MineShaftsGridSize:</td>
<td><input type="text" name="World_MineShaftsGridSize" value="]] .. WorldIni:GetValue("Generator", "MineShaftsGridSize") .. [["></td></tr>
<tr><td>MineShaftsMaxSystemSize:</td>
<td><input type="text" name="World_MineShaftsMaxSystemSize" value="]] .. WorldIni:GetValue("Generator", "MineShaftsMaxSystemSize") .. [["></td></tr>
<tr><td>MineShaftsChanceCorridor:</td>
<td><input type="text" name="World_MineShaftsChanceCorridor" value="]] .. WorldIni:GetValue("Generator", "MineShaftsChanceCorridor") .. [["></td></tr>
<tr><td>MineShaftsChanceCrossing:</td>
<td><input type="text" name="World_MineShaftsChanceCrossing" value="]] .. WorldIni:GetValue("Generator", "MineShaftsChanceCrossing") .. [["></td></tr>
<tr><td>MineShaftsChanceStaircase:</td>
<td><input type="text" name="World_MineShaftsChanceStaircase" value="]] .. WorldIni:GetValue("Generator", "MineShaftsChanceStaircase") .. [["></td></tr>]]
end
if string.find( WorldIni:GetValue( "Generator", "Structures" ), "LavaLakes" ) ~= nil then
Content = Content .. [[
<th colspan="2">LavaLakes</th>
<tr><td>LavaLakesProbability:</td>
<td><input type="text" name="World_LavaLakesProbability" value="]] .. WorldIni:GetValue("Generator", "LavaLakesProbability") .. [["></td></tr>]]
end
if string.find( WorldIni:GetValue( "Generator", "Structures" ), "WaterLakes" ) ~= nil then
Content = Content .. [[
<th colspan="2">WaterLakes</th>
<tr><td>WaterLakesProbability:</td>
<td><input type="text" name="World_WaterLakesProbability" value="]] .. WorldIni:GetValue("Generator", "WaterLakesProbability") .. [["></td></tr>]]
end
if string.find( WorldIni:GetValue( "Generator", "Finishers" ), "BottomLava" ) ~= nil then
Content = Content .. [[
<th colspan="2">BottomLavaLevel</th>
<tr><td>BottomLavaLevel:</td>
<td><input type="text" name="World_BottomLavaLevel" value="]] .. WorldIni:GetValue("Generator", "BottomLavaLevel") .. [["></td></tr>]]
end
Content = Content .. [[</table>]]
Content = Content .. [[ <br />
<input type="submit" value="Save Settings" name="world_submit"> </form>WARNING: Any changes made here might require a server restart in order to be applied!
</form>]]
return Content
end
function HandleRequest_ServerSettings( Request )
local Content = ""
Content = Content .. [[
<p><b>Server Settings</b></p>
<table>
<tr>
<td><a href="?tab=General">General</a></td>
<td><a href="?tab=Monsters">Monsters</a></td>
<td><a href="?tab=Worlds">Worlds</a></td>
<td><a href="?tab=World">World</a></td>
</tr>
</table>
<br />]]
if( Request.Params["tab"] == "Monsters" ) then
Content = Content .. ShowMonstersSettings( Request )
elseif( Request.Params["tab"] == "Worlds" ) then
Content = Content .. ShowWorldsSettings( Request )
elseif( Request.Params["tab"] == "World" ) then
Content = Content .. ShowWorldSettings( Request )
else
Content = Content .. ShowGeneralSettings( Request ) -- Default to general settings
end
return Content
end

View File

@ -1,79 +0,0 @@
local function HTMLDeleteButton( name )
return "<form method=\"POST\"><input type=\"hidden\" name=\"whitelist-delete\" value=\"".. name .."\"><input type=\"submit\" value=\"Remove from whitelist\"></form>"
end
function HandleRequest_WhiteList( Request )
local UpdateMessage = ""
if( Request.PostParams["whitelist-add"] ~= nil ) then
local PlayerName = Request.PostParams["whitelist-add"]
if( WhiteListIni:GetValueB("WhiteList", PlayerName, false) == true ) then
UpdateMessage = "<b>".. PlayerName.."</b> is already on the whitelist"
else
WhiteListIni:SetValueB("WhiteList", PlayerName, true )
UpdateMessage = "Added <b>" .. PlayerName .. "</b> to whitelist."
WhiteListIni:WriteFile()
end
elseif( Request.PostParams["whitelist-delete"] ~= nil ) then
local PlayerName = Request.PostParams["whitelist-delete"]
WhiteListIni:DeleteValue( "WhiteList", PlayerName )
UpdateMessage = "Removed <b>" .. PlayerName .. "</b> from whitelist."
WhiteListIni:WriteFile()
elseif( Request.PostParams["whitelist-reload"] ~= nil ) then
WhiteListIni:Erase() -- Empty entire loaded ini first, otherwise weird shit goes down
WhiteListIni:ReadFile()
UpdateMessage = "Loaded from disk"
elseif( Request.Params["whitelist-setenable"] ~= nil ) then
local Enabled = Request.Params["whitelist-setenable"]
local CreateNewValue = false
if( WhiteListIni:FindValue( WhiteListIni:FindKey("WhiteListSettings"), "WhiteListOn" ) == cIniFile.noID ) then -- Find out whether the value is in the ini
CreateNewValue = true
end
if( Enabled == "1" ) then
WhiteListIni:SetValueB("WhiteListSettings", "WhiteListOn", true, CreateNewValue )
else
WhiteListIni:SetValueB("WhiteListSettings", "WhiteListOn", false, CreateNewValue )
end
WhiteListIni:WriteFile()
end
local Content = ""
local WhiteListEnabled = WhiteListIni:GetValueB("WhiteListSettings", "WhiteListOn", false)
if( WhiteListEnabled == false ) then
Content = Content .. "<p>Whitelist is currently disabled! Click <a href='?whitelist-setenable=1'>here</a> to enable.</p>"
end
Content = Content .. "<h4>Whitelisted players</h4>"
Content = Content .. "<table>"
local KeyNum = WhiteListIni:FindKey("WhiteList")
local NumValues = WhiteListIni:GetNumValues(KeyNum)
if( NumValues > 0 ) then
for Num = 0, NumValues-1 do
if( WhiteListIni:GetValue(KeyNum, Num, "0") == "1" ) then
local PlayerName = WhiteListIni:GetValueName(KeyNum, Num )
Content = Content .. "<tr><td>" .. PlayerName .. "</td><td>" .. HTMLDeleteButton( PlayerName ) .. "</td></tr>"
end
end
else
Content = Content .. "<tr><td>None</td></tr>"
end
Content = Content .. "</table>"
Content = Content .. "<br><h4>Add player to whitelist</h4>"
Content = Content .. "<form method=\"POST\">"
Content = Content .. "<input type=\"text\" name=\"whitelist-add\"><input type=\"submit\" value=\"Add player\">"
Content = Content .. "</form>"
Content = Content .. "<form method=\"POST\">"
Content = Content .. "<input type=\"submit\" name=\"whitelist-reload\" value=\"Reload from disk\">"
Content = Content .. "</form>"
Content = Content .. "<br>"..UpdateMessage
if( WhiteListEnabled == true ) then
Content = Content .. "<br><br><p>Whitelist is currently enabled, click <a href='?whitelist-setenable=0'>here</a> to disable.</p>"
end
return Content
end

View File

@ -1,22 +0,0 @@
function OnPlayerMoving( Player )
LimitWorldWidth = WorldsWorldLimit[Player:GetWorld():GetName()]
if LimitWorldWidth > 0 then
local World = Player:GetWorld()
local SpawnX = math.floor(World:GetSpawnX() / 16)
local SpawnZ = math.floor(World:GetSpawnZ() / 16)
local X = math.floor(Player:GetPosX() / 16)
local Z = math.floor(Player:GetPosZ() / 16)
if ( (SpawnX + LimitWorldWidth - 1) < X ) then
Player:TeleportToCoords(Player:GetPosX() - 1, Player:GetPosY(), Player:GetPosZ())
end
if ( (SpawnX - LimitWorldWidth + 1) > X ) then
Player:TeleportToCoords(Player:GetPosX() + 1, Player:GetPosY(), Player:GetPosZ())
end
if ( (SpawnZ + LimitWorldWidth - 1) < Z ) then
Player:TeleportToCoords(Player:GetPosX(), Player:GetPosY(), Player:GetPosZ() - 1)
end
if ( (SpawnZ - LimitWorldWidth + 1) > Z ) then
Player:TeleportToCoords(Player:GetPosX(), Player:GetPosY(), Player:GetPosZ() + 1)
end
end
end

View File

@ -1,322 +0,0 @@
-- CommandHandlers.lua
-- Defines the individual command handlers
function InitializeCommandHandlers()
local PlgMgr = cRoot:Get():GetPluginManager();
for idx, Cmd in ipairs(CommandReg()) do
PlgMgr:BindCommand(Cmd[2], Cmd[3], Cmd[1], Cmd[4]);
end
end
--- Handles the ProtAdd command
function HandleAddArea(a_Split, a_Player)
-- Command syntax: ProtAdd username1 [username2] [username3] ...
if (#a_Split < 2) then
a_Player:SendMessage(g_Msgs.ErrExpectedListOfUsernames);
return true;
end
-- Get the cuboid that the player had selected
local CmdState = GetCommandStateForPlayer(a_Player);
if (CmdState == nil) then
a_Player:SendMessage(g_Msgs.ErrCmdStateNilAddArea);
return true;
end
local Cuboid = CmdState:GetCurrentCuboid();
if (Cuboid == nil) then
a_Player:SendMessage(g_Msgs.ErrNoAreaWanded);
return true;
end
-- Put all allowed players into a table:
AllowedNames = {};
for i = 2, #a_Split do
table.insert(AllowedNames, a_Split[i]);
end
-- Add the area to the storage
local AreaID = g_Storage:AddArea(Cuboid, a_Player:GetWorld():GetName(), a_Player:GetName(), AllowedNames);
a_Player:SendMessage(string.format(g_Msgs.AreaAdded, AreaID));
-- Reload all currently logged in players
ReloadAllPlayersInWorld(a_Player:GetWorld():GetName());
return true;
end
function HandleAddAreaCoords(a_Split, a_Player)
-- Command syntax: ProtAddCoords x1 z1 x2 z2 username1 [username2] [username3] ...
if (#a_Split < 6) then
a_Player:SendMessage(g_Msgs.ErrExpectedCoordsUsernames);
return true;
end
-- Convert the coords to a cCuboid
local x1, z1 = tonumber(a_Split[2]), tonumber(a_Split[3]);
local x2, z2 = tonumber(a_Split[4]), tonumber(a_Split[5]);
if ((x1 == nil) or (z1 == nil) or (x2 == nil) or (z2 == nil)) then
a_Player:SendMessage(g_Msgs.ErrParseCoords);
return true;
end
local Cuboid = cCuboid(x1, 0, z1, x2, 255, z1);
Cuboid:Sort();
-- Put all allowed players into a table:
AllowedNames = {};
for i = 6, #a_Split do
table.insert(AllowedNames, a_Split[i]);
end
-- Add the area to the storage
local AreaID = g_Storage:AddArea(Cuboid, a_Player:GetWorld():GetName(), a_Player:GetName(), AllowedNames);
a_Player:SendMessage(string.format(g_Msgs.AreaAdded, AreaID));
-- Reload all currently logged in players
ReloadAllPlayersInWorld(a_Player:GetWorld():GetName());
return true;
end
function HandleAddAreaUser(a_Split, a_Player)
-- Command syntax: ProtAddUser AreaID username1 [username2] [username3] ...
if (#a_Split < 3) then
a_Player:SendMessage(g_Msgs.ErrExpectedAreaIDUsernames);
return true;
end
-- Put all allowed players into a table:
AllowedNames = {};
for i = 3, #a_Split do
table.insert(AllowedNames, a_Split[i]);
end
-- Add the area to the storage
if (not(g_Storage:AddAreaUsers(
tonumber(a_Split[2]), a_Player:GetWorld():GetName(), a_Player:GetName(), AllowedNames))
) then
LOGWARNING("g_Storage:AddAreaUsers failed");
a_Player:SendMessage(g_Msgs.ErrDBFailAddUsers);
return true;
end
if (#AllowedNames == 0) then
a_Player:SendMessage(g_Msgs.AllUsersAlreadyAllowed);
else
a_Player:SendMessage(string.format(g_Msgs.UsersAdded, table.concat(AllowedNames, ", ")));
end
-- Reload all currently logged in players
ReloadAllPlayersInWorld(a_Player:GetWorld():GetName());
return true;
end
function HandleDelArea(a_Split, a_Player)
-- Command syntax: ProtDelArea AreaID
if (#a_Split ~= 2) then
a_Player:SendMessage(g_Msgs.ErrExpectedAreaID);
return true;
end
-- Parse the AreaID
local AreaID = tonumber(a_Split[2]);
if (AreaID == nil) then
a_Player:SendMessage(g_Msgs.ErrParseAreaID);
return true;
end
-- Delete the area
g_Storage:DelArea(a_Player:GetWorld():GetName(), AreaID);
a_Player:SendMessage(string.format(g_Msgs.AreaDeleted, AreaID));
-- Reload all currently logged in players
ReloadAllPlayersInWorld(a_Player:GetWorld():GetName());
return true;
end
function HandleGiveWand(a_Split, a_Player)
local NumGiven = a_Player:GetInventory():AddItem(cConfig:GetWandItem());
if (NumGiven == 1) then
a_Player:SendMessage(g_Msgs.WandGiven);
else
a_Player:SendMessage(g_Msgs.ErrNoSpaceForWand);
end
return true;
end
function HandleListAreas(a_Split, a_Player)
-- Command syntax: ProtListAreas [x, z]
local x, z;
if (#a_Split == 1) then
-- Get the last "wanded" coord
local CmdState = GetCommandStateForPlayer(a_Player);
if (CmdState == nil) then
a_Player:SendMessage(g_Msgs.ErrCmdStateNilListAreas);
return true;
end
x, z = CmdState:GetLastCoords();
if ((x == nil) or (z == nil)) then
a_Player:SendMessage(g_Msgs.ErrListNotWanded);
return true;
end
elseif (#a_Split == 3) then
-- Parse the coords from the command params
x = tonumber(a_Split[2]);
z = tonumber(a_Split[3]);
if ((x == nil) or (z == nil)) then
a_Player:SendMessage(g_Msgs.ErrParseCoordsListAreas);
return true;
end
else
-- Wrong number of params, report back to the user
a_Player:SendMessage(g_Msgs.ErrSyntaxErrorListAreas);
return true;
end
a_Player:SendMessage(string.format(g_Msgs.ListAreasHeader, x, z));
-- List areas intersecting the coords
local PlayerName = a_Player:GetName();
local WorldName = a_Player:GetWorld():GetName();
g_Storage:ForEachArea(x, z, WorldName,
function(AreaID, MinX, MinZ, MaxX, MaxZ, CreatorName)
local Coords = string.format("%s: {%d, %d} - {%d, %d} ", AreaID, MinX, MinZ, MaxX, MaxZ);
local Allowance;
if (g_Storage:IsAreaAllowed(AreaID, PlayerName, WorldName)) then
Allowance = g_Msgs.AreaAllowed;
else
Allowance = g_Msgs.AreaNotAllowed;
end
a_Player:SendMessage(string.format(g_Msgs.ListAreasRow, Coords, Allowance, CreatorName));
end
);
a_Player:SendMessage(g_Msgs.ListAreasFooter);
return true;
end
--- Lists all allowed users for a particular area
function HandleListUsers(a_Split, a_Player)
-- Command syntax: ProtListUsers AreaID
if (#a_Split ~= 2) then
a_Player:SendMessage(g_Msgs.ErrExpectedAreaID);
end
-- Get the general info about the area
local AreaID = a_Split[2];
local WorldName = a_Player:GetWorld():GetName();
local MinX, MinZ, MaxX, MaxZ, CreatorName = g_Storage:GetArea(AreaID, WorldName);
if (MinX == nil) then
a_Player:SendMessage(string.format(g_Msgs.ErrNoSuchArea, AreaID));
return true;
end
-- Send the header
a_Player:SendMessage(string.format(g_Msgs.ListUsersHeader, AreaID, MinX, MinZ, MaxX, MaxZ, CreatorName));
-- List and count the allowed users
local NumUsers = 0;
g_Storage:ForEachUserInArea(AreaID, WorldName,
function(UserName)
a_Player:SendMessage(string.format(g_Msgs.ListUsersRow, UserName));
NumUsers = NumUsers + 1;
end
);
-- Send the footer
a_Player:SendMessage(string.format(g_Msgs.ListUsersFooter, AreaID, NumUsers));
return true;
end
function HandleRemoveUser(a_Split, a_Player)
-- Command syntax: ProtRemUser AreaID UserName
if (#a_Split ~= 3) then
a_Player:SendMessage(g_Msgs.ErrExpectedAreaIDUserName);
return true;
end
-- Parse the AreaID
local AreaID = tonumber(a_Split[2]);
if (AreaID == nil) then
a_Player:SendMessage(g_Msgs.ErrParseAreaID);
return true;
end
-- Remove the user from the DB
local UserName = a_Split[3];
g_Storage:RemoveUser(AreaID, UserName, a_Player:GetWorld():GetName());
-- Send confirmation
a_Player:SendMessage(string.format(g_Msgs.RemovedUser, UserName, AreaID));
-- Reload all currently logged in players
ReloadAllPlayersInWorld(a_Player:GetWorld():GetName());
return true;
end
function HandleRemoveUserAll(a_Split, a_Player)
-- Command syntax: ProtRemUserAll UserName
if (#a_Split ~= 2) then
a_Player:SendMessage(g_Msgs.ErrExpectedUserName);
return true;
end
-- Remove the user from the DB
g_Storage:RemoveUserAll(a_Split[2], a_Player:GetWorld():GetName());
-- Send confirmation
a_Player:SendMessage(string.format(g_Msgs.RemovedUserAll, UserName));
-- Reload all currently logged in players
ReloadAllPlayersInWorld(a_Player:GetWorld():GetName());
return true;
end

View File

@ -1,121 +0,0 @@
-- CommandState.lua
-- Implements the cCommandState class representing a command state for each VIP player
--[[
The command state holds internal info, such as the coords they selected using the wand
The command state needs to be held in a per-entity manner, so that we can support multiple logins
from the same account (just for the fun of it)
The OOP class implementation follows the PiL 16.1
Also, a global table g_CommandStates is the map of PlayerEntityID -> cCommandState
--]]
cCommandState = {
-- Default coords
m_Coords1 = {x = 0, z = 0}; -- lclk coords
m_Coords2 = {x = 0, z = 0}; -- rclk coords
m_LastCoords = 0; -- When Coords1 or Coords2 is set, this gets set to 1 or 2, signifying the last changed set of coords
m_HasCoords1 = false; -- Set to true when m_Coords1 has been set by the user
m_HasCoords2 = false; -- Set to true when m_Coords2 has been set by the user
};
g_CommandStates = {};
function cCommandState:new(obj)
obj = obj or {};
setmetatable(obj, self);
self.__index = self;
return obj;
end
--- Returns the current coord pair as a cCuboid object
function cCommandState:GetCurrentCuboid()
if (not(self.m_HasCoords1) or not(self.m_HasCoords2)) then
-- Some of the coords haven't been set yet
return nil;
end
local res = cCuboid(
self.m_Coords1.x, 0, self.m_Coords1.z,
self.m_Coords2.x, 255, self.m_Coords2.z
);
res:Sort();
return res;
end
--- Returns the x, z coords that were the set last,
-- That is, either m_Coords1 or m_Coords2, based on m_LastCoords member
-- Returns nothing if no coords were set yet
function cCommandState:GetLastCoords()
if (self.m_LastCoords == 0) then
-- No coords have been set yet
return;
elseif (self.m_LastCoords == 1) then
return self.m_Coords1.x, self.m_Coords1.z;
elseif (self.m_LastCoords == 2) then
return self.m_Coords2.x, self.m_Coords2.z;
else
LOGWARNING(PluginPrefix .. "cCommandState is in an unexpected state, m_LastCoords == " .. self.m_LastCoords);
return;
end
end
--- Sets the first set of coords (upon rclk with a wand)
function cCommandState:SetCoords1(a_BlockX, a_BlockZ)
self.m_Coords1.x = a_BlockX;
self.m_Coords1.z = a_BlockZ;
self.m_LastCoords = 1;
self.m_HasCoords1 = true;
end
--- Sets the second set of coords (upon lclk with a wand)
function cCommandState:SetCoords2(a_BlockX, a_BlockZ)
self.m_Coords2.x = a_BlockX;
self.m_Coords2.z = a_BlockZ;
self.m_LastCoords = 2;
self.m_HasCoords2 = true;
end
--- Returns the cCommandState for the specified player; creates one if not existant
function GetCommandStateForPlayer(a_Player)
local res = g_CommandStates[a_Player:GetUniqueID()];
if (res == nil) then
res = cCommandState:new();
g_CommandStates[a_Player:GetUniqueID()] = res;
end
return res;
end;

View File

@ -1,55 +0,0 @@
-- Config.lua
-- Implements the cConfig class that holds the general plugin configuration
cConfig = {
m_Wand = cItem(E_ITEM_STICK, 1, 1); -- The item to be used as the selection wand
m_AllowInteractNoArea = true; -- If there's no area, is a player allowed to build / dig?
};
--- Initializes the cConfig object, loads the configuration from an INI file
function InitializeConfig()
local ini = cIniFile("ProtectionAreas.ini");
if (not(ini:ReadFile())) then
LOGINFO(PluginPrefix .. "Cannot read ProtectionAreas.ini, all plugin configuration is set to defaults");
end
local WandItem = cItem();
if (
StringToItem(ini:GetValueSet("ProtectionAreas", "WandItem", ItemToString(cConfig.m_Wand)), WandItem) and
IsValidItem(WandItem.m_ItemType)
) then
cConfig.m_Wand = WandItem;
end
cConfig.m_AllowInteractNoArea = ini:GetValueSetB("ProtectionAreas", "AllowInteractNoArea", cConfig.m_AllowInteractNoArea);
ini:WriteFile();
end
--- Returns true if a_Item is the wand tool item
function cConfig:IsWand(a_Item)
return (
(a_Item.m_ItemType == self.m_Wand.m_ItemType) and
(a_Item.m_ItemDamage == self.m_Wand.m_ItemDamage)
);
end
--- Returns the wand tool item as a cItem object
function cConfig:GetWandItem()
return self.m_Wand;
end

View File

@ -1,76 +0,0 @@
-- CurrentLng.lua
-- This file provides all the translatable strings
-- The expectation is that the translators will create copies of this file, translate the texts and then the users will overwrite this file with a specific language version
-- Note that the individual languages must not have ".lua" extension, otherwise MCServer will load them and the plugin won't work!
-- Individual commands, and their help strings. Don't touch the first symbol on each line!
-- This needs to be implemented as a function, because it references other functions which might not yet be loaded while Lua is processing the globals
function CommandReg()
return {
-- Handler function | Command | Permission | Help text
{HandleAddArea, "/ProtAdd", "Prot.Add", "<UserNames> - Adds a new protected area"},
{HandleAddAreaCoords, "/ProtAddCoords", "Prot.Add", "<x1> <z1> <x2> <z2> <UserNames> - Adds a new protected area by coords"},
{HandleAddAreaUser, "/ProtAddUser", "Prot.AddUser", "<AreaID> <UserNames> - Adds new users to an existing protected area"},
{HandleDelArea, "/ProtDelID", "Prot.Del", "<AreaID> - Deletes a protected area by ID"},
{HandleGiveWand, "/ProtWand", "Prot.Wand", " - Gives you the wand used for protection"},
{HandleListAreas, "/ProtList", "Prot.List", "[<x> <z>] - Lists all areas for the marked block or given coords"},
{HandleListUsers, "/ProtUsers", "Prot.List", "<AreaID> - Lists all allowed users for a given area ID"},
{HandleRemoveUser, "/ProtRemUser", "Prot.RemUser", "<AreaID> <UserName> - Removes a user from the protected area"},
{HandleRemoveUserAll, "/ProtRemUserAll", "Prot.RemUser", "<UserName> - Removes a user from all protected areas"},
};
end;
--- Messages sent to players
g_Msgs =
{
AllUsersAlreadyAllowed = "All the specified users were already allowed.";
AreaAdded = "Area added, ID %s";
AreaAllowed = "Allowed";
AreaDeleted = "Area ID %s deleted";
AreaNotAllowed = "NOT allowed";
Coords1Set = "Coords1 set as {%d, %d}";
Coords2Set = "Coords2 set as {%d, %d}";
ErrCmdStateNilAddArea = "Cannot add area, internal plugin error (CmdState == nil)";
ErrCmdStateNilListAreas = "Cannot list areas, internal plugin error (CmdState == nil)";
ErrDBFailAddUsers = "Cannot add users, DB failure";
ErrExpectedAreaID = "Parameter mismatch. Expected <AreaID>.";
ErrExpectedAreaIDUserName = "Parameter mismatch. Expected <AreaID> <UserName>.";
ErrExpectedAreaIDUsernames = "Not enough parameters. Expected <AreaID> and a list of usernames.";
ErrExpectedCoordsUsernames = "Not enough parameters. Expected <x1> <z1> <x2> <z2> coords and a list of usernames.";
ErrExpectedListOfUsernames = "Not enough parameters. Expected a list of usernames.";
ErrExpectedUserName = "Parameter mismatch. Expected <UserName>.";
ErrListNotWanded = "Cannot list areas, no query point has been selected. Use a ProtWand lclk / rclk to select a point first";
ErrNoAreaWanded = "Cannot add area, no area has been selected. Use a ProtWand lclk / rclk to select area first";
ErrNoSpaceForWand = "Cannot give wand, no space in your inventory";
ErrNoSuchArea = "No such area: %s";
ErrParseAreaID = "Cannot parse <AreaID>.";
ErrParseCoords = "Cannot parse coords.";
ErrParseCoordsListAreas = "Cannot list areas, cannot parse coords in params";
ErrSyntaxErrorListAreas = "Cannot list areas, syntax error. Expected either no params or <x> <z>.";
ListAreasFooter = "Area list finished";
ListAreasHeader = "Listing protection areas intersecting block column {%d, %d}:";
ListAreasRow = " %s, %s, created by %s";
ListUsersFooter = "End of area %s user list, total %d users";
ListUsersHeader = "Area ID %s: {%d, %d} - {%d, %d}, created by %s; allowed users:";
ListUsersRow = " %s";
NotAllowedToBuild = "You are not allowed to build here!";
NotAllowedToDig = "You are not allowed to dig here!";
RemovedUser = "Removed %s from area %d";
RemovedUserAll = "Removed %s from all areas";
UsersAdded = "Users added: %s";
WandGiven = "Wand given";
} ;

View File

@ -1,139 +0,0 @@
-- HookHandlers.lua
-- Implements the handlers for individual hooks
--- Registers all the hooks that the plugin needs to know about
function InitializeHooks(a_Plugin)
local PlgMgr = cRoot:Get():GetPluginManager();
PlgMgr:AddHook(a_Plugin, cPluginManager.HOOK_DISCONNECT);
PlgMgr:AddHook(a_Plugin, cPluginManager.HOOK_PLAYER_LEFT_CLICK);
PlgMgr:AddHook(a_Plugin, cPluginManager.HOOK_PLAYER_MOVING);
PlgMgr:AddHook(a_Plugin, cPluginManager.HOOK_PLAYER_RIGHT_CLICK);
PlgMgr:AddHook(a_Plugin, cPluginManager.HOOK_PLAYER_SPAWNED);
end
--- Called by MCS when a player's connectino is lost - either they disconnected or timed out
function OnDisconnect(a_Player, a_Reason)
-- Remove the player's cProtectionArea object
g_PlayerAreas[a_Player:GetUniqueID()] = nil;
-- If the player is a VIP, they had a command state, remove that as well
g_CommandStates[a_Player:GetUniqueID()] = nil;
return false;
end;
--- Called by MCS whenever a player enters a world (is spawned)
function OnPlayerSpawned(a_Player)
-- Create a new cPlayerAreas object for this player
if (g_PlayerAreas[a_Player:GetUniqueID()] == nil) then
LoadPlayerAreas(a_Player);
end;
return false;
end
--- Called by MCS whenever a player is moving (at most once every tick)
function OnPlayerMoving(a_Player)
local PlayerID = a_Player:GetUniqueID();
-- If for some reason we don't have a cPlayerAreas object for this player, load it up
local PlayerAreas = g_PlayerAreas[PlayerID];
if (PlayerAreas == nil) then
LoadPlayerAreas(a_Player);
return false;
end;
-- If the player is outside their areas' safe space, reload
if (not(PlayerAreas:IsInSafe(a_Player:GetPosX(), a_Player:GetPosZ()))) then
LoadPlayerAreas(a_Player);
end
return false;
end
--- Called by MCS when a player left-clicks
function OnPlayerLeftClick(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status)
-- If the player has lclked with the wand; regardless of their permissions, let's set the coords:
if (cConfig:IsWand(a_Player:GetEquippedItem())) then
-- BlockFace < 0 means "use item", for which the coords are not given by the client
if (a_BlockFace < 0) then
return true;
end
-- Convert the clicked coords into the block space
a_BlockX, a_BlockY, a_BlockZ = AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
-- Set the coords in the CommandState
GetCommandStateForPlayer(a_Player):SetCoords1(a_BlockX, a_BlockZ);
a_Player:SendMessage(string.format(g_Msgs.Coords1Set, a_BlockX, a_BlockZ));
return true;
end;
-- Check the player areas to see whether to disable this action
local Areas = g_PlayerAreas[a_Player:GetUniqueID()];
if not(Areas:CanInteractWithBlock(a_BlockX, a_BlockZ)) then
a_Player:SendMessage(g_Msgs.NotAllowedToDig);
return true;
end
-- Allow interaction
return false;
end
--- Called by MCS when a player right-clicks
function OnPlayerRightClick(a_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ, a_Status)
-- BlockFace < 0 means "use item", for which the coords are not given by the client
if (a_BlockFace < 0) then
return true;
end
-- Convert the clicked coords into the block space
a_BlockX, a_BlockY, a_BlockZ = AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
-- If the player has rclked with the wand; regardless of their permissions, let's set the coords
if (cConfig:IsWand(a_Player:GetEquippedItem())) then
-- Set the coords in the CommandState
GetCommandStateForPlayer(a_Player):SetCoords2(a_BlockX, a_BlockZ);
a_Player:SendMessage(string.format(g_Msgs.Coords2Set, a_BlockX, a_BlockZ));
return true;
end;
-- Check the player areas to see whether to disable this action
local Areas = g_PlayerAreas[a_Player:GetUniqueID()];
if not(Areas:CanInteractWithBlock(a_BlockX, a_BlockZ)) then
a_Player:SendMessage(g_Msgs.NotAllowedToBuild);
return true;
end
-- Allow interaction
return false;
end

View File

@ -1,7 +0,0 @@
ProtectionAreas license
=======================
The ProtectionAreas plugin is written by _Xoft(o) / Mattes and is hereby released as public domain.
If you like it, I'd really appreciate a postcard, or something tiny typical from your country :) The current snailmail address is at my personal web, http://xoft.cz .

View File

@ -1,109 +0,0 @@
-- PlayerAreas.lua
-- Implements the cPlayerAreas class representing the per-player area storage object
--[[
Each player instance is expected to have a separate object of type cPlayerAreas.
Each object has an array of {cuboid, IsAllowed} tables, one for each area that is "within reach"
The code can then ask each object, whether the player can interact with a certain block or not.
A player can interact with a block if either one of these is true:
1, There are no areas covering the block
2, There is at least one area covering the block with IsAllowed set to true
The object also has a m_SafeCuboid object that specified the area within which the player may move
without the PlayerAreas needing a re-query.
Also, a global table g_PlayerAreas is the actual map of PlayerID -> cPlayerAreas
--]]
cPlayerAreas = {};
g_PlayerAreas = {};
function cPlayerAreas:new(a_SafeMinX, a_SafeMinZ, a_SafeMaxX, a_SafeMaxZ)
assert(a_SafeMinX);
assert(a_SafeMinZ);
assert(a_SafeMaxX);
assert(a_SafeMaxZ);
local obj = {};
setmetatable(obj, self);
self.__index = self;
self.m_SafeCuboid = cCuboid(a_SafeMinX, 0, a_SafeMinZ, a_SafeMaxX, 255, a_SafeMaxZ);
return obj;
end
-- Adds a new cuboid to the area list, where the player is either allowed or not, depending on the IsAllowed param
function cPlayerAreas:AddArea(a_Cuboid, a_IsAllowed)
table.insert(self, {m_Cuboid = a_Cuboid, m_IsAllowed = a_IsAllowed});
end
--- returns true if the player owning this object can interact with the specified block
function cPlayerAreas:CanInteractWithBlock(a_BlockX, a_BlockZ)
assert(self);
-- iterate through all the stored areas:
local IsInsideAnyArea = false;
for idx, Area in ipairs(self) do
if (Area.m_Cuboid:IsInside(a_BlockX, 1, a_BlockZ)) then -- We don't care about Y coords, so use a dummy value
if (Area.m_IsAllowed) then
return true;
end
-- The coords are inside a cuboid for which the player doesn't have access, take a note of it
IsInsideAnyArea = true;
end
end
if (IsInsideAnyArea) then
-- The specified coords are inside at least one area, but none of them allow the player to interact
return false;
end
-- The coords are not inside any area
return cConfig.m_AllowInteractNoArea;
end
--- Calls the specified callback for each area contained within
-- a_Callback has a signature: function(a_Cuboid, a_IsAllowed)
-- Returns true if all areas have been enumerated, false if the callback has aborted by returning true
function cPlayerAreas:ForEachArea(a_Callback)
assert(self);
for idx, Area in ipairs(self) do
if (a_Callback(Area.m_Cuboid, Area.m_IsAllowed)) then
return false;
end
end
return true;
end
--- Returns true if the player is withing the safe cuboid (no need to re-query the areas)
function cPlayerAreas:IsInSafe(a_BlockX, a_BlockZ)
assert(self);
return self.m_SafeCuboid:IsInside(a_BlockX, 0, a_BlockZ);
end

View File

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<file>
<filename>CommandHandlers.lua</filename>
</file>
<file>
<filename>CommandState.lua</filename>
</file>
<file>
<filename>Config.lua</filename>
</file>
<file>
<filename>CurrentLng.lua</filename>
</file>
<file>
<filename>HookHandlers.lua</filename>
</file>
<file>
<filename>PlayerAreas.lua</filename>
</file>
<file>
<filename>ProtectionAreas.lua</filename>
</file>
<file>
<filename>Storage.lua</filename>
</file>
</project>

View File

@ -1,71 +0,0 @@
-- ProtectionAreas.lua
-- Defines the main plugin entrypoint, as well as some utility functions
--- Prefix for all messages logged to the server console
PluginPrefix = "ProtectionAreas: ";
--- Bounds for the area loading. Areas less this far in any direction from the player will be loaded into cPlayerAreas
g_AreaBounds = 48;
--- If a player moves this close to the PlayerAreas bounds, the PlayerAreas will be re-queried
g_AreaSafeEdge = 12;
--- Called by MCS when the plugin loads
-- Returns true if initialization successful, false otherwise
function Initialize(a_Plugin)
a_Plugin:SetName("ProtectionAreas");
a_Plugin:SetVersion(1);
InitializeConfig();
if (not(InitializeStorage())) then
LOGWARNING(PluginPrefix .. "failed to initialize Storage, plugin is disabled");
return false;
end
InitializeHooks(a_Plugin);
InitializeCommandHandlers();
-- We might be reloading, so there may be players already present in the server; reload all of them
cRoot:Get():ForEachWorld(
function(a_World)
ReloadAllPlayersInWorld(a_World:GetName());
end
);
return true;
end
--- Loads a cPlayerAreas object from the DB for the player, and assigns it to the player map
function LoadPlayerAreas(a_Player)
local PlayerID = a_Player:GetUniqueID();
local PlayerX = math.floor(a_Player:GetPosX());
local PlayerZ = math.floor(a_Player:GetPosZ());
local WorldName = a_Player:GetWorld():GetName();
g_PlayerAreas[PlayerID] = g_Storage:LoadPlayerAreas(a_Player:GetName(), PlayerX, PlayerZ, WorldName);
end
function ReloadAllPlayersInWorld(a_WorldName)
local World = cRoot:Get():GetWorld(a_WorldName);
World:ForEachPlayer(LoadPlayerAreas);
end

View File

@ -1,518 +0,0 @@
-- Storage.lua
-- Implements the storage access object, shielding the rest of the code away from the DB
--[[
The cStorage class is the interface to the underlying storage, the SQLite database.
This class knows how to load player areas from the DB, how to add or remove areas in the DB
and other such operations.
Also, a g_Storage global variable is declared, it holds the single instance of the storage.
--]]
cStorage = {};
g_Storage = {};
--- Initializes the storage subsystem, creates the g_Storage object
-- Returns true if successful, false if not
function InitializeStorage()
g_Storage = cStorage:new();
if (not(g_Storage:OpenDB())) then
return false;
end
return true;
end
function cStorage:new(obj)
obj = obj or {};
setmetatable(obj, self);
self.__index = self;
return obj;
end
--- Opens the DB and makes sure it has all the columns needed
-- Returns true if successful, false otherwise
function cStorage:OpenDB()
local ErrCode, ErrMsg;
self.DB, ErrCode, ErrMsg = sqlite3.open("ProtectionAreas.sqlite");
if (self.DB == nil) then
LOGWARNING(PluginPrefix .. "Cannot open ProtectionAreas.sqlite, error " .. ErrCode .. " (" .. ErrMsg ..")");
return false;
end
if (
not(self:CreateTable("Areas", {"ID INTEGER PRIMARY KEY AUTOINCREMENT", "MinX", "MaxX", "MinZ", "MaxZ", "WorldName", "CreatorUserName"})) or
not(self:CreateTable("AllowedUsers", {"AreaID", "UserName"}))
) then
LOGWARNING(PluginPrefix .. "Cannot create DB tables!");
return false;
end
return true;
end
--- Executes the SQL command given, calling the a_Callback for each result
-- If the SQL command fails, prints it out on the server console and returns false
-- Returns true on success
function cStorage:DBExec(a_SQL, a_Callback, a_CallbackParam)
local ErrCode = self.DB:exec(a_SQL, a_Callback, a_CallbackParam);
if (ErrCode ~= sqlite3.OK) then
LOGWARNING(PluginPrefix .. "Error " .. ErrCode .. " (" .. self.DB:errmsg() ..
") while processing SQL command >>" .. a_SQL .. "<<"
);
return false;
end
return true;
end
--- Creates the table of the specified name and columns[]
-- If the table exists, any columns missing are added; existing data is kept
function cStorage:CreateTable(a_TableName, a_Columns)
-- Try to create the table first
local sql = "CREATE TABLE IF NOT EXISTS '" .. a_TableName .. "' (";
sql = sql .. table.concat(a_Columns, ", ");
sql = sql .. ")";
if (not(self:DBExec(sql))) then
LOGWARNING(PluginPrefix .. "Cannot create DB Table " .. a_TableName);
return false;
end
-- SQLite doesn't inform us if it created the table or not, so we have to continue anyway
-- Check each column whether it exists
-- Remove all the existing columns from a_Columns:
local RemoveExistingColumn = function(UserData, NumCols, Values, Names)
-- Remove the received column from a_Columns. Search for column name in the Names[] / Values[] pairs
for i = 1, NumCols do
if (Names[i] == "name") then
local ColumnName = Values[i]:lower();
-- Search the a_Columns if they have that column:
for j = 1, #a_Columns do
-- Cut away all column specifiers (after the first space), if any:
local SpaceIdx = string.find(a_Columns[j], " ");
if (SpaceIdx ~= nil) then
SpaceIdx = SpaceIdx - 1;
end
local ColumnTemplate = string.lower(string.sub(a_Columns[j], 1, SpaceIdx));
-- If it is a match, remove from a_Columns:
if (ColumnTemplate == ColumnName) then
table.remove(a_Columns, j);
break; -- for j
end
end -- for j - a_Columns[]
end
end -- for i - Names[] / Values[]
return 0;
end
if (not(self:DBExec("PRAGMA table_info(" .. a_TableName .. ")", RemoveExistingColumn))) then
LOGWARNING(PluginPrefix .. "Cannot query DB table structure");
return false;
end
-- Create the missing columns
-- a_Columns now contains only those columns that are missing in the DB
if (#a_Columns > 0) then
LOGINFO(PluginPrefix .. "Database table \"" .. a_TableName .. "\" is missing " .. #a_Columns .. " columns, fixing now.");
for idx, ColumnName in ipairs(a_Columns) do
if (not(self:DBExec("ALTER TABLE '" .. a_TableName .. "' ADD COLUMN " .. ColumnName))) then
LOGWARNING(PluginPrefix .. "Cannot add DB table \"" .. a_TableName .. "\" column \"" .. ColumnName .. "\"");
return false;
end
end
LOGINFO(PluginPrefix .. "Database table \"" .. a_TableName .. "\" columns fixed.");
end
return true;
end
--- Returns true if the specified area is allowed for the specified player
function cStorage:IsAreaAllowed(a_AreaID, a_PlayerName, a_WorldName)
assert(a_AreaID);
assert(a_PlayerName);
assert(a_WorldName);
assert(self);
local lcPlayerName = string.lower(a_PlayerName);
local res = false;
local sql = "SELECT COUNT(*) FROM AllowedUsers WHERE (AreaID = " .. a_AreaID ..
") AND (UserName ='" .. lcPlayerName .. "')";
local function SetResTrue(UserData, NumValues, Values, Names)
res = (tonumber(Values[1]) > 0);
return 0;
end
if (not(self:DBExec(sql, SetResTrue))) then
LOGWARNING("SQL error while determining area allowance");
return false;
end
return res;
end
--- Loads cPlayerAreas for the specified player from the DB. Returns a cPlayerAreas object
function cStorage:LoadPlayerAreas(a_PlayerName, a_PlayerX, a_PlayerZ, a_WorldName)
assert(a_PlayerName);
assert(a_PlayerX);
assert(a_PlayerZ);
assert(a_WorldName);
assert(self);
-- Bounds for which the areas are loaded
local BoundsMinX = a_PlayerX - g_AreaBounds;
local BoundsMaxX = a_PlayerX + g_AreaBounds;
local BoundsMinZ = a_PlayerZ - g_AreaBounds;
local BoundsMaxZ = a_PlayerZ + g_AreaBounds;
local res = cPlayerAreas:new(
BoundsMinX + g_AreaSafeEdge, BoundsMinZ + g_AreaSafeEdge,
BoundsMaxX - g_AreaSafeEdge, BoundsMaxZ - g_AreaSafeEdge
);
--[[
LOG("Loading protection areas for player " .. a_PlayerName .. " centered around {" .. a_PlayerX .. ", " .. a_PlayerZ ..
"}, bounds are {" .. BoundsMinX .. ", " .. BoundsMinZ .. "} - {" ..
BoundsMaxX .. ", " .. BoundsMaxZ .. "}"
);
--]]
-- Load the areas from the DB, based on the player's location
local lcWorldName = string.lower(a_WorldName);
local sql =
"SELECT ID, MinX, MaxX, MinZ, MaxZ FROM Areas WHERE " ..
"MinX < " .. BoundsMaxX .. " AND MaxX > " .. BoundsMinX .. " AND " ..
"MinZ < " .. BoundsMaxZ .. " AND MaxZ > " .. BoundsMinZ .. " AND " ..
"WorldName = '" .. lcWorldName .."'";
local function AddAreas(UserData, NumValues, Values, Names)
if ((NumValues < 5) or ((Values[1] and Values[2] and Values[3] and Values[4] and Values[5]) == nil)) then
LOGWARNING("SQL query didn't return all data");
return 0;
end
res:AddArea(cCuboid(Values[2], 0, Values[4], Values[3], 255, Values[5]), self:IsAreaAllowed(Values[1], a_PlayerName, a_WorldName));
return 0;
end
if (not(self:DBExec(sql, AddAreas))) then
LOGWARNING("SQL error while querying areas");
return res;
end
return res;
end
--- Adds a new area into the DB. a_AllowedNames is a table listing all the players that are allowed in the area
-- Returns the ID of the new area, or -1 on failure
function cStorage:AddArea(a_Cuboid, a_WorldName, a_CreatorName, a_AllowedNames)
assert(a_Cuboid);
assert(a_WorldName);
assert(a_CreatorName);
assert(a_AllowedNames);
assert(self);
-- Store the area in the DB
local ID = -1;
local function RememberID(UserData, NumCols, Values, Names)
for i = 1, NumCols do
if (Names[i] == "ID") then
ID = Values[i];
end
end
return 0;
end
local lcWorldName = string.lower(a_WorldName);
local lcCreatorName = string.lower(a_CreatorName);
local sql =
"INSERT INTO Areas (ID, MinX, MaxX, MinZ, MaxZ, WorldName, CreatorUserName) VALUES (NULL, " ..
a_Cuboid.p1.x .. ", " .. a_Cuboid.p2.x .. ", " .. a_Cuboid.p1.z .. ", " .. a_Cuboid.p2.z ..
", '" .. lcWorldName .. "', '" .. lcCreatorName ..
"'); SELECT last_insert_rowid() AS ID";
if (not(self:DBExec(sql, RememberID))) then
LOGWARNING(PluginPrefix .. "SQL Error while inserting new area");
return -1;
end
if (ID == -1) then
LOGWARNING(PluginPrefix .. "SQL Error while retrieving INSERTion ID");
return -1;
end
-- Store each allowed player in the DB
for idx, Name in ipairs(a_AllowedNames) do
local lcName = string.lower(Name);
local sql = "INSERT INTO AllowedUsers (AreaID, UserName) VALUES (" .. ID .. ", '" .. lcName .. "')";
if (not(self:DBExec(sql))) then
LOGWARNING(PluginPrefix .. "SQL Error while inserting new area's allowed player " .. Name);
end
end
return ID;
end
function cStorage:DelArea(a_WorldName, a_AreaID)
assert(a_WorldName);
assert(a_AreaID);
assert(self);
-- Since all areas are stored in a single DB (for now), the worldname parameter isn't used at all
-- Later if we change to a per-world DB, we'll need the world name
-- Delete from both tables simultaneously
local sql =
"DELETE FROM Areas WHERE ID = " .. a_AreaID .. ";" ..
"DELETE FROM AllowedUsers WHERE AreaID = " .. a_AreaID;
if (not(self:DBExec(sql))) then
LOGWARNING(PluginPrefix .. "SQL error while deleting area " .. a_AreaID .. " from world \"" .. a_WorldName .. "\"");
return false;
end
return true;
end
--- Removes the user from the specified area
function cStorage:RemoveUser(a_AreaID, a_UserName, a_WorldName)
assert(a_AreaID);
assert(a_UserName);
assert(a_WorldName);
assert(self);
-- WorldName is not used yet, because all the worlds share the same DB in this version
local lcUserName = string.lower(a_UserName);
local sql = "DELETE FROM AllowedUsers WHERE " ..
"AreaID = " .. a_AreaID .. " AND UserName = '" .. lcUserName .. "'";
if (not(self:DBExec(sql))) then
LOGWARNING("SQL error while removing user " .. a_UserName .. " from area ID " .. a_AreaID);
return false;
end
return true;
end
--- Removes the user from all areas in the specified world
function cStorage:RemoveUserAll(a_UserName, a_WorldName)
assert(a_UserName);
assert(a_WorldName);
assert(self);
local lcUserName = string.lower(a_UserName);
local sql = "DELETE FROM AllowedUsers WHERE UserName = '" .. lcUserName .."'";
if (not(self:DBExec(sql))) then
LOGWARNING("SQL error while removing user " .. a_UserName .. " from all areas");
return false;
end
return true;
end
--- Calls the callback for each area intersecting the specified coords
-- Callback signature: function(ID, MinX, MinZ, MaxX, MaxZ, CreatorName)
function cStorage:ForEachArea(a_BlockX, a_BlockZ, a_WorldName, a_Callback)
assert(a_BlockX);
assert(a_BlockZ);
assert(a_WorldName);
assert(a_Callback);
assert(self);
-- SQL callback that parses the values and calls our callback
function CallCallback(UserData, NumValues, Values, Names)
if (NumValues ~= 6) then
-- Not enough values returned, skip this row
return 0;
end
local ID = Values[1];
local MinX = Values[2];
local MinZ = Values[3];
local MaxX = Values[4];
local MaxZ = Values[5];
local CreatorName = Values[6];
a_Callback(ID, MinX, MinZ, MaxX, MaxZ, CreatorName);
return 0;
end
local lcWorldName = string.lower(a_WorldName);
local sql = "SELECT ID, MinX, MinZ, MaxX, MaxZ, CreatorUserName FROM Areas WHERE " ..
"MinX <= " .. a_BlockX .. " AND MaxX >= " .. a_BlockX .. " AND " ..
"MinZ <= " .. a_BlockZ .. " AND MaxZ >= " .. a_BlockZ .. " AND " ..
"WorldName = '" .. lcWorldName .. "'";
if (not(self:DBExec(sql, CallCallback))) then
LOGWARNING("SQL Error while iterating through areas (cStorage:ForEachArea())");
return false;
end
return true;
end
--- Returns the info on the specified area
-- Returns MinX, MinZ, MaxX, MaxZ, CreatorName on success, or nothing on failure
function cStorage:GetArea(a_AreaID, a_WorldName)
assert(a_AreaID);
assert(a_WorldName);
assert(self);
local MinX, MinZ, MaxX, MaxZ, CreatorName;
local HasValues = false;
-- SQL callback that parses the values and remembers them in variables
function RememberValues(UserData, NumValues, Values, Names)
if (NumValues ~= 5) then
-- Not enough values returned, skip this row
return 0;
end
MinX = Values[1];
MinZ = Values[2];
MaxX = Values[3];
MaxZ = Values[4];
CreatorName = Values[5];
HasValues = true;
return 0;
end
local lcWorldName = string.lower(a_WorldName);
local sql = "SELECT MinX, MinZ, MaxX, MaxZ, CreatorUserName FROM Areas WHERE " ..
"ID = " .. a_AreaID .. " AND WorldName = '" .. lcWorldName .. "'";
if (not(self:DBExec(sql, RememberValues))) then
LOGWARNING("SQL Error while getting area info (cStorage:ForEachArea())");
return;
end
-- If no data has been retrieved, return nothing
if (not(HasValues)) then
return;
end
return MinX, MinZ, MaxX, MaxZ, CreatorName;
end
--- Calls the callback for each allowed user for the specified area
-- Callback signature: function(UserName)
function cStorage:ForEachUserInArea(a_AreaID, a_WorldName, a_Callback)
assert(a_AreaID);
assert(a_WorldName);
assert(a_Callback);
assert(self);
-- Since in this version all the worlds share a single DB, the a_WorldName parameter is not actually used
-- But this may change in the future, when we have a per-world DB
local function CallCallback(UserData, NumValues, Values)
if (NumValues ~= 1) then
return 0;
end
a_Callback(Values[1]);
return 0;
end
local sql = "SELECT UserName FROM AllowedUsers WHERE AreaID = " .. a_AreaID;
if (not(self:DBExec(sql, CallCallback))) then
LOGWARNING("SQL error while iterating area users for AreaID" .. a_AreaID);
return false;
end
return true;
end
--- Adds the specified usernames to the specified area, if not already present
-- a_Users is an array table of usernames to add
function cStorage:AddAreaUsers(a_AreaID, a_WorldName, a_AddedBy, a_Users)
assert(a_AreaID);
assert(a_WorldName);
assert(a_Users);
assert(self);
-- Convert all usernames to lowercase
for idx, Name in ipairs(a_Users) do
a_Users[idx] = string.lower(Name);
end
-- Remove from a_Users the usernames already present in the area
local sql = "SELECT UserName FROM AllowedUsers WHERE AreaID = " .. a_AreaID;
local function RemovePresent(UserData, NumValues, Values, Names)
if (NumValues ~= 1) then
-- Invalid response format
return 0;
end
local DBName = Values[1];
-- Remove the name from a_Users, if exists
for idx, Name in ipairs(a_Users) do
if (Name == DBName) then
table.remove(a_Users, idx);
return 0;
end
end
return 0;
end
if (not(self:DBExec(sql, RemovePresent))) then
LOGWARNING("SQL error while iterating through users");
return false;
end
-- Add the users
for idx, Name in ipairs(a_Users) do
local sql = "INSERT INTO AllowedUsers (AreaID, UserName) VALUES (" .. a_AreaID .. ", '" .. Name .. "')";
if (not(self:DBExec(sql))) then
LOGWARNING("SQL error while adding user " .. Name .. " to area " .. a_AreaID);
end
end
return true;
end

View File

@ -1,13 +0,0 @@
class SquirrelChatLog extends Plugin
{
function Initialize()
{
this.AddHook(Hook.Chat);
return true;
}
function OnChat(Message, Player)
{
::print(Player.GetName() + ": " + Message);
}
}

View File

@ -53,6 +53,15 @@ if errorlevel 1 goto haderror
:: Update the external plugins to the latest revision:
cd MCServer\Plugins\Core
git pull
if errorlevel 1 goto haderror
cd ..\ProtectionAreas
git pull
if errorlevel 1 goto haderror
cd ..\..\..
:: Get the Git commit ID into an environment var
For /f "tokens=1 delims=/. " %%a in ('git log -1 --oneline --no-abbrev-commit') do (set COMMITID=%%a)
if errorlevel 1 goto haderror
@ -100,7 +109,7 @@ set FILESUFFIX=%MYYEAR%_%MYMONTH%_%MYDAY%_%MYTIME%_%COMMITID%
echo FILESUFFIX=%FILESUFFIX%
copy MCServer\MCServer.exe Install\MCServer.exe
cd Install
%zip% a -mx9 -y MCServer_Win_%FILESUFFIX%.7z -scsWIN @Zip2008.list
%zip% a -mx9 -y MCServer_Win_%FILESUFFIX%.7z -scsWIN -i@Zip2008.list -xr!*.git*
if errorlevel 1 goto haderror
cd ..

View File

@ -390,6 +390,14 @@
RelativePath="..\source\Cuboid.h"
>
</File>
<File
RelativePath="..\source\DeadlockDetect.cpp"
>
</File>
<File
RelativePath="..\source\DeadlockDetect.h"
>
</File>
<File
RelativePath="..\source\Defines.h"
>
@ -2449,7 +2457,15 @@
Name="Core"
>
<File
RelativePath="..\MCServer\Plugins\Core\ban.lua"
RelativePath="..\MCServer\Plugins\Core\back.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\ban-unban.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\clear.lua"
>
</File>
<File
@ -2457,15 +2473,19 @@
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\coords.lua"
RelativePath="..\MCServer\Plugins\Core\do.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\gamemode.lua"
RelativePath="..\MCServer\Plugins\Core\functions.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\gotoworld.lua"
RelativePath="..\MCServer\Plugins\Core\give.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\gm.lua"
>
</File>
<File
@ -2476,32 +2496,44 @@
RelativePath="..\MCServer\Plugins\Core\item.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\itemrepair.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\kick.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\kill.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\locate.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\main.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\me.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\motd.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\onblockdig.lua"
RelativePath="..\MCServer\Plugins\Core\onbreakplaceblock.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\onblockplace.lua"
RelativePath="..\MCServer\Plugins\Core\ondeath.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\oncraftingnorecipe.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\onkilled.lua"
RelativePath="..\MCServer\Plugins\Core\onjoinleave.lua"
>
</File>
<File
@ -2509,23 +2541,23 @@
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\onplayerjoin.lua"
RelativePath="..\MCServer\Plugins\Core\plugins.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\playerlist.lua"
RelativePath="..\MCServer\Plugins\Core\portal-worlds.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\pluginlist.lua"
RelativePath="..\MCServer\Plugins\Core\rank-groups.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\regeneratechunk.lua"
RelativePath="..\MCServer\Plugins\Core\regen.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\reload.lua"
RelativePath="..\MCServer\Plugins\Core\save-reload-stop.lua"
>
</File>
<File
@ -2533,11 +2565,11 @@
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\stop.lua"
RelativePath="..\MCServer\Plugins\Core\teleport.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\teleport.lua"
RelativePath="..\MCServer\Plugins\Core\tell.lua"
>
</File>
<File
@ -2549,11 +2581,11 @@
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\unban.lua"
RelativePath="..\MCServer\Plugins\Core\viewdistance.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\viewdistance.lua"
RelativePath="..\MCServer\Plugins\Core\weather.lua"
>
</File>
<File
@ -2564,6 +2596,10 @@
RelativePath="..\MCServer\Plugins\Core\web_manageplugins.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\web_manageserver.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\web_permissions.lua"
>
@ -2580,6 +2616,10 @@
RelativePath="..\MCServer\Plugins\Core\web_whitelist.lua"
>
</File>
<File
RelativePath="..\MCServer\Plugins\Core\worldlimiter.lua"
>
</File>
</Filter>
<Filter
Name="ChatLog"

View File

@ -8,8 +8,10 @@
:: If there was a Git conflict, resolve it by resetting to HEAD; we're regenerating the files from scratch anyway
git checkout -- Bindings.cpp
git checkout -- Bindings.h
git checkout --ours Bindings.cpp
git add -u Bindings.cpp
git checkout --ours Bindings.h
git add -u Bindings.h

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
/*
** Lua binding: AllToLua
** Generated automatically by tolua++-1.0.92 on 08/12/13 11:15:34.
*/
/* Exported function */
TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S);
/*
** Lua binding: AllToLua
** Generated automatically by tolua++-1.0.92 on 08/16/13 10:46:13.
*/
/* Exported function */
TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S);

View File

@ -112,7 +112,7 @@ void cDispenserEntity::DropSpenseFromSlot(cChunk & a_Chunk, int a_SlotNum)
{
double MobX = 0.5 + (DispX + DispChunk->GetPosX() * cChunkDef::Width);
double MobZ = 0.5 + (DispZ + DispChunk->GetPosZ() * cChunkDef::Width);
if (m_World->SpawnMob(MobX, DispY, MobZ, m_Contents.GetSlot(a_SlotNum).m_ItemDamage) >= 0)
if (m_World->SpawnMob(MobX, DispY, MobZ, (cMonster::eType)m_Contents.GetSlot(a_SlotNum).m_ItemDamage) >= 0)
{
m_Contents.ChangeSlotCount(a_SlotNum, -1);
}

View File

@ -7,6 +7,7 @@
#include "BlockID.h"
#include "../iniFile/iniFile.h"
#include "Item.h"
#include "Mobs/Monster.h"
@ -287,10 +288,10 @@ EMCSBiome StringToBiome(const AString & a_BiomeString)
{biTaiga, "Taiga"},
{biSwampland, "Swampland"},
{biRiver, "River"},
{biHell, "Hell"},
{biHell, "Nether"},
{biSky, "Sky"},
{biSky, "End"},
{biNether, "Hell"},
{biNether, "Nether"},
{biEnd, "Sky"},
{biEnd, "End"},
{biFrozenOcean, "FrozenOcean"},
{biFrozenRiver, "FrozenRiver"},
{biIcePlains, "IcePlains"},
@ -328,34 +329,34 @@ int StringToMobType(const AString & a_MobString)
const char * m_String;
} MobMap [] =
{
{E_ENTITY_TYPE_CREEPER, "Creeper"},
{E_ENTITY_TYPE_SKELETON, "Skeleton"},
{E_ENTITY_TYPE_SPIDER, "Spider"},
{E_ENTITY_TYPE_GIANT, "Giant"},
{E_ENTITY_TYPE_ZOMBIE, "Zombie"},
{E_ENTITY_TYPE_SLIME, "Slime"},
{E_ENTITY_TYPE_GHAST, "Ghast"},
{E_ENTITY_TYPE_ZOMBIE_PIGMAN, "ZombiePigman"},
{E_ENTITY_TYPE_ENDERMAN, "Enderman"},
{E_ENTITY_TYPE_CAVE_SPIDER, "CaveSpider"},
{E_ENTITY_TYPE_SILVERFISH, "SilverFish"},
{E_ENTITY_TYPE_BLAZE, "Blaze"},
{E_ENTITY_TYPE_MAGMA_CUBE, "MagmaCube"},
{E_ENTITY_TYPE_ENDER_DRAGON, "EnderDragon"},
{E_ENTITY_TYPE_WITHER, "Wither"},
{E_ENTITY_TYPE_BAT, "Bat"},
{E_ENTITY_TYPE_WITCH, "Witch"},
{E_ENTITY_TYPE_PIG, "Pig"},
{E_ENTITY_TYPE_SHEEP, "Sheep"},
{E_ENTITY_TYPE_COW, "Cow"},
{E_ENTITY_TYPE_CHICKEN, "Chicken"},
{E_ENTITY_TYPE_SQUID, "Squid"},
{E_ENTITY_TYPE_WOLF, "Wolf"},
{E_ENTITY_TYPE_MOOSHROOM, "Mushroom"},
{E_ENTITY_TYPE_SNOW_GOLEM, "SnowGolem"},
{E_ENTITY_TYPE_OCELOT, "Ocelot"},
{E_ENTITY_TYPE_IRON_GOLEM, "IronGolem"},
{E_ENTITY_TYPE_VILLAGER, "Villager"},
{cMonster::mtCreeper, "Creeper"},
{cMonster::mtSkeleton, "Skeleton"},
{cMonster::mtSpider, "Spider"},
{cMonster::mtGiant, "Giant"},
{cMonster::mtZombie, "Zombie"},
{cMonster::mtSlime, "Slime"},
{cMonster::mtGhast, "Ghast"},
{cMonster::mtZombiePigman, "ZombiePigman"},
{cMonster::mtEnderman, "Enderman"},
{cMonster::mtCaveSpider, "CaveSpider"},
{cMonster::mtSilverfish, "SilverFish"},
{cMonster::mtBlaze, "Blaze"},
{cMonster::mtMagmaCube, "MagmaCube"},
{cMonster::mtEnderDragon, "EnderDragon"},
{cMonster::mtWither, "Wither"},
{cMonster::mtBat, "Bat"},
{cMonster::mtWitch, "Witch"},
{cMonster::mtPig, "Pig"},
{cMonster::mtSheep, "Sheep"},
{cMonster::mtCow, "Cow"},
{cMonster::mtChicken, "Chicken"},
{cMonster::mtSquid, "Squid"},
{cMonster::mtWolf, "Wolf"},
{cMonster::mtMooshroom, "Mooshroom"},
{cMonster::mtSnowGolem, "SnowGolem"},
{cMonster::mtOcelot, "Ocelot"},
{cMonster::mtIronGolem, "IronGolem"},
{cMonster::mtVillager, "Villager"},
};
for (int i = 0; i < ARRAYCOUNT(MobMap); i++)
{
@ -364,7 +365,7 @@ int StringToMobType(const AString & a_MobString)
return MobMap[i].m_MobType;
}
} // for i - MobMap[]
return (int)-1;
return -1;
}

View File

@ -478,16 +478,16 @@ enum
E_META_TORCH_ZP = 4, // Torch attached to the ZP side of its block
// E_BLOCK_WOODEN_DOUBLE_STEP metas:
E_BLOCK_WOODEN_DOUBLE_STEP_APPLE = 0,
E_BLOCK_WOODEN_DOUBLE_STEP_CONIFER = 1,
E_BLOCK_WOODEN_DOUBLE_STEP_BIRCH = 2,
E_BLOCK_WOODEN_DOUBLE_STEP_JUNGLE = 3,
E_META_WOODEN_DOUBLE_STEP_APPLE = 0,
E_META_WOODEN_DOUBLE_STEP_CONIFER = 1,
E_META_WOODEN_DOUBLE_STEP_BIRCH = 2,
E_META_WOODEN_DOUBLE_STEP_JUNGLE = 3,
// E_BLOCK_WOODEN_STEP metas:
E_BLOCK_WOODEN_STEP_APPLE = 0,
E_BLOCK_WOODEN_STEP_CONIFER = 1,
E_BLOCK_WOODEN_STEP_BIRCH = 2,
E_BLOCK_WOODEN_STEP_JUNGLE = 3,
E_META_WOODEN_STEP_APPLE = 0,
E_META_WOODEN_STEP_CONIFER = 1,
E_META_WOODEN_STEP_BIRCH = 2,
E_META_WOODEN_STEP_JUNGLE = 3,
// E_BLOCK_WOOL metas:
E_META_WOOL_WHITE = 0,
@ -541,8 +541,8 @@ enum
E_META_TRACKS_X = 1,
E_META_TRACKS_Z = 0,
// E_ITEM_SPAWN_EGG spawn EntityIDs:
// See also E_ENTITY_TYPE_XXX, since entity type and spawn egg meta are the same
// E_ITEM_SPAWN_EGG metas:
// See also cMonster::eType, since monster type and spawn egg meta are the same
E_META_SPAWN_EGG_CREEPER = 50,
E_META_SPAWN_EGG_SKELETON = 51,
E_META_SPAWN_EGG_SPIDER = 52,
@ -557,6 +557,9 @@ enum
E_META_SPAWN_EGG_BLAZE = 61,
E_META_SPAWN_EGG_MAGMA_CUBE = 62,
E_META_SPAWN_EGG_ENDER_DRAGON = 63,
E_META_SPAWN_EGG_WITHER = 64,
E_META_SPAWN_EGG_BAT = 65,
E_META_SPAWN_EGG_WITCH = 66,
E_META_SPAWN_EGG_PIG = 90,
E_META_SPAWN_EGG_SHEEP = 91,
E_META_SPAWN_EGG_COW = 92,
@ -567,48 +570,15 @@ enum
E_META_SPAWN_EGG_SNOW_GOLEM = 97,
E_META_SPAWN_EGG_OCELOT = 98,
E_META_SPAWN_EGG_IRON_GOLEM = 99,
E_META_SPAWN_EGG_HORSE = 100,
E_META_SPAWN_EGG_VILLAGER = 120,
} ;
enum
{
// See also E_META_SPAWN_EGG_XXX, since entity type and spawn egg meta are the same
E_ENTITY_TYPE_CREEPER = 50,
E_ENTITY_TYPE_SKELETON = 51,
E_ENTITY_TYPE_SPIDER = 52,
E_ENTITY_TYPE_GIANT = 53,
E_ENTITY_TYPE_ZOMBIE = 54,
E_ENTITY_TYPE_SLIME = 55,
E_ENTITY_TYPE_GHAST = 56,
E_ENTITY_TYPE_ZOMBIE_PIGMAN = 57,
E_ENTITY_TYPE_ENDERMAN = 58,
E_ENTITY_TYPE_CAVE_SPIDER = 59,
E_ENTITY_TYPE_SILVERFISH = 60,
E_ENTITY_TYPE_BLAZE = 61,
E_ENTITY_TYPE_MAGMA_CUBE = 62,
E_ENTITY_TYPE_ENDER_DRAGON = 63,
E_ENTITY_TYPE_WITHER = 64,
E_ENTITY_TYPE_BAT = 65,
E_ENTITY_TYPE_WITCH = 66,
E_ENTITY_TYPE_PIG = 90,
E_ENTITY_TYPE_SHEEP = 91,
E_ENTITY_TYPE_COW = 92,
E_ENTITY_TYPE_CHICKEN = 93,
E_ENTITY_TYPE_SQUID = 94,
E_ENTITY_TYPE_WOLF = 95,
E_ENTITY_TYPE_MOOSHROOM = 96,
E_ENTITY_TYPE_SNOW_GOLEM = 97,
E_ENTITY_TYPE_OCELOT = 98,
E_ENTITY_TYPE_IRON_GOLEM = 99,
E_ENTITY_TYPE_VILLAGER = 120,
} ;
/// Dimension of a world
enum eDimension
{
dimNether = -1,

View File

@ -76,7 +76,8 @@ enum EMCSBiome
biRiver = 7,
biHell = 8, // same as Nether
biNether = 8,
biSky = 9,
biSky = 9, // same as biEnd
biEnd = 9,
biFrozenOcean = 10,
biFrozenRiver = 11,
biIcePlains = 12,

View File

@ -170,13 +170,21 @@ cClientHandle::~cClientHandle()
void cClientHandle::Destroy()
void cClientHandle::Destroy(void)
{
// Setting m_bDestroyed was moved to the bottom of Destroy(),
// otherwise the destructor may be called within another thread before the client is removed from chunks
// http://forum.mc-server.org/showthread.php?tid=366
{
cCSLock Lock(m_CSDestroyingState);
if (m_State >= csDestroying)
{
// Already called
return;
}
m_State = csDestroying;
}
// DEBUG:
LOGD("%s: client %p, \"%s\"", __FUNCTION__, this, m_Username.c_str());
m_State = csDestroying;
if ((m_Player != NULL) && (m_Player->GetWorld() != NULL))
{
RemoveFromAllChunks();
@ -253,9 +261,8 @@ void cClientHandle::Authenticate(void)
SendGameMode(m_Player->GetGameMode());
m_Player->Initialize(World);
StreamChunks();
m_State = csDownloadingWorld;
m_State = csAuthenticated;
// Broadcast this player's spawning to all other players in the same chunk
m_Player->GetWorld()->BroadcastSpawnEntity(*m_Player, this);
@ -268,7 +275,7 @@ void cClientHandle::Authenticate(void)
void cClientHandle::StreamChunks(void)
{
if ((m_State < csAuthenticating) || (m_State >= csDestroying))
if ((m_State < csAuthenticated) || (m_State >= csDestroying))
{
return;
}
@ -421,11 +428,11 @@ void cClientHandle::HandlePing(void)
// Somebody tries to retrieve information about the server
AString Reply;
Printf(Reply, "%s%s%i%s%i",
cRoot::Get()->GetDefaultWorld()->GetDescription().c_str(),
cChatColor::Delimiter.c_str(),
cRoot::Get()->GetDefaultWorld()->GetNumPlayers(),
cChatColor::Delimiter.c_str(),
cRoot::Get()->GetDefaultWorld()->GetMaxPlayers()
cRoot::Get()->GetServer()->GetDescription().c_str(),
cChatColor::Delimiter.c_str(),
cRoot::Get()->GetServer()->GetNumPlayers(),
cChatColor::Delimiter.c_str(),
cRoot::Get()->GetServer()->GetMaxPlayers()
);
Kick(Reply.c_str());
}
@ -914,11 +921,24 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, c
void cClientHandle::HandleChat(const AString & a_Message)
{
// We need to process messages in the Tick thread, to avoid deadlocks resulting from player-commands being processed
// in the SocketThread and waiting for acquiring the ChunkMap CS with Plugin CS locked
// We no longer need to postpone message processing, because the messages already arrive in the Tick thread
cCSLock Lock(m_CSMessages);
m_PendingMessages.push_back(a_Message);
// If a command, perform it:
AString Message(a_Message);
if (cRoot::Get()->GetServer()->Command(*this, Message))
{
return;
}
// Not a command, broadcast as a simple message:
AString Msg;
Printf(Msg, "<%s%s%s> %s",
m_Player->GetColor().c_str(),
m_Player->GetName().c_str(),
cChatColor::White.c_str(),
Message.c_str()
);
m_Player->GetWorld()->BroadcastChat(Msg);
}
@ -1176,7 +1196,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
{
if (!cRoot::Get()->GetPluginManager()->CallHookHandshake(this, a_Username))
{
if (cRoot::Get()->GetDefaultWorld()->GetNumPlayers() >= cRoot::Get()->GetDefaultWorld()->GetMaxPlayers())
if (cRoot::Get()->GetServer()->GetNumPlayers() >= cRoot::Get()->GetServer()->GetMaxPlayers())
{
Kick("The server is currently full :(-- Try again later");
return false;
@ -1191,7 +1211,7 @@ bool cClientHandle::HandleHandshake(const AString & a_Username)
void cClientHandle::HandleEntityAction(int a_EntityID, char a_ActionID)
{
if( a_EntityID != m_Player->GetUniqueID() )
if (a_EntityID != m_Player->GetUniqueID())
{
// We should only receive entity actions from the entity that is performing the action
return;
@ -1307,6 +1327,42 @@ void cClientHandle::SendData(const char * a_Data, int a_Size)
void cClientHandle::MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket)
{
ASSERT(m_Player != NULL);
if (a_SendRespawnPacket)
{
SendRespawn();
}
cWorld * World = m_Player->GetWorld();
// Remove all associated chunks:
cChunkCoordsList Chunks;
{
cCSLock Lock(m_CSChunkLists);
std::swap(Chunks, m_LoadedChunks);
m_ChunksToSend.clear();
}
for (cChunkCoordsList::iterator itr = Chunks.begin(), end = Chunks.end(); itr != end; ++itr)
{
World->RemoveChunkClient(itr->m_ChunkX, itr->m_ChunkZ, this);
m_Protocol->SendUnloadChunk(itr->m_ChunkX, itr->m_ChunkZ);
} // for itr - Chunks[]
// Do NOT stream new chunks, the new world runs its own tick thread and may deadlock
// Instead, the chunks will be streamed when the client is moved to the new world's Tick list,
// by setting state to csAuthenticated
m_State = csAuthenticated;
m_LastStreamedChunkX = 0x7fffffff;
m_LastStreamedChunkZ = 0x7fffffff;
}
bool cClientHandle::CheckBlockInteractionsRate(void)
{
ASSERT(m_Player != NULL);
@ -1342,6 +1398,20 @@ bool cClientHandle::CheckBlockInteractionsRate(void)
void cClientHandle::Tick(float a_Dt)
{
// Process received network data:
AString IncomingData;
{
cCSLock Lock(m_CSIncomingData);
std::swap(IncomingData, m_IncomingData);
}
m_Protocol->DataReceived(IncomingData.data(), IncomingData.size());
if (m_State == csAuthenticated)
{
StreamChunks();
m_State = csDownloadingWorld;
}
m_TimeSinceLastPacket += a_Dt;
if (m_TimeSinceLastPacket > 30000.f) // 30 seconds time-out
{
@ -1355,12 +1425,14 @@ void cClientHandle::Tick(float a_Dt)
m_ShouldCheckDownloaded = false;
}
if (m_Player == NULL)
{
return;
}
// Send a ping packet:
cTimer t1;
if (
(m_Player != NULL) && // Is logged in?
(m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())
)
if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime()))
{
m_PingID++;
m_PingStartTime = t1.GetNowTime();
@ -1369,7 +1441,7 @@ void cClientHandle::Tick(float a_Dt)
}
// Handle block break animation:
if ((m_Player != NULL) && (m_BlockDigAnimStage > -1))
if (m_BlockDigAnimStage > -1)
{
int lastAnimVal = m_BlockDigAnimStage;
m_BlockDigAnimStage += (int)(m_BlockDigAnimSpeed * a_Dt);
@ -1387,9 +1459,6 @@ void cClientHandle::Tick(float a_Dt)
m_CurrentExplosionTick = (m_CurrentExplosionTick + 1) % ARRAYCOUNT(m_NumExplosionsPerTick);
m_RunningSumExplosions -= m_NumExplosionsPerTick[m_CurrentExplosionTick];
m_NumExplosionsPerTick[m_CurrentExplosionTick] = 0;
// Process the queued messages:
ProcessPendingMessages();
}
@ -1955,7 +2024,7 @@ void cClientHandle::SendConfirmPosition(void)
if (!cRoot::Get()->GetPluginManager()->CallHookPlayerJoined(*m_Player))
{
// Broadcast that this player has joined the game! Yay~
cRoot::Get()->GetServer()->BroadcastChat(m_Username + " joined the game!", this);
m_Player->GetWorld()->BroadcastChat(m_Username + " joined the game!", this);
}
SendPlayerMoveLook();
@ -2037,46 +2106,6 @@ void cClientHandle::AddWantedChunk(int a_ChunkX, int a_ChunkZ)
void cClientHandle::ProcessPendingMessages(void)
{
while (true)
{
AString Message;
// Extract one message from the PendingMessages buffer:
{
cCSLock Lock(m_CSMessages);
if (m_PendingMessages.empty())
{
// No more messages in the buffer, bail out
return;
}
Message = m_PendingMessages.front();
m_PendingMessages.pop_front();
} // Lock(m_CSMessages)
// If a command, perform it:
if (cRoot::Get()->GetServer()->Command(*this, Message))
{
continue;
}
// Not a command, broadcast as a simple message:
AString Msg;
Printf(Msg, "<%s%s%s> %s",
m_Player->GetColor().c_str(),
m_Player->GetName().c_str(),
cChatColor::White.c_str(),
Message.c_str()
);
m_Player->GetWorld()->BroadcastChat(Msg);
} // while (true)
}
void cClientHandle::PacketBufferFull(void)
{
// Too much data in the incoming queue, the server is probably too busy, kick the client:
@ -2116,30 +2145,10 @@ void cClientHandle::PacketError(unsigned char a_PacketType)
void cClientHandle::DataReceived(const char * a_Data, int a_Size)
{
// Data is received from the client, hand it off to the protocol:
if ((m_Player != NULL) && (m_Player->GetWorld() != NULL))
{
/*
_X: Lock the world, so that plugins reacting to protocol events have already the chunkmap locked.
There was a possibility of a deadlock between SocketThreads and TickThreads, resulting from each
holding one CS an requesting the other one (ChunkMap CS vs Plugin CS) (FS #375). To break this, it's
sufficient to break any of the four Coffman conditions for a deadlock. We'll solve this by requiring
the ChunkMap CS for all SocketThreads operations before they lock the PluginCS - thus creating a kind
of a lock hierarchy. However, this incurs a performance penalty, we're de facto locking the chunkmap
for each incoming packet. A better, but more involved solutin would be to lock the chunkmap only when
the incoming packet really has a plugin CS lock request.
Also, it is still possible for a packet to slip through - when a player still doesn't have their world
assigned and several packets arrive at once.
*/
cWorld::cLock(*m_Player->GetWorld());
m_Protocol->DataReceived(a_Data, a_Size);
}
else
{
m_Protocol->DataReceived(a_Data, a_Size);
}
// Data is received from the client, store it in the buffer to be processed by the Tick thread:
m_TimeSinceLastPacket = 0;
cCSLock Lock(m_CSIncomingData);
m_IncomingData.append(a_Data, a_Size);
}

View File

@ -32,6 +32,7 @@ class cRedstone;
class cWindow;
class cFallingBlock;
class cItemHandler;
class cWorld;
@ -194,6 +195,9 @@ public:
void SendData(const char * a_Data, int a_Size);
/// Called when the player moves into a different world; queues sreaming the new chunks
void MoveToWorld(cWorld & a_World, bool a_SendRespawnPacket);
private:
int m_ViewDistance; // Number of chunks the player can see in each direction; 4 is the minimum ( http://wiki.vg/Protocol_FAQ#.E2.80.A6all_connecting_clients_spasm_and_jerk_uncontrollably.21 )
@ -212,11 +216,12 @@ private:
cProtocol * m_Protocol;
cCriticalSection m_CSIncomingData;
AString m_IncomingData;
cCriticalSection m_CSOutgoingData;
cByteBuffer m_OutgoingData;
AString m_OutgoingDataOverflow; //< For data that didn't fit into the m_OutgoingData ringbuffer temporarily
cCriticalSection m_CriticalSection;
AString m_OutgoingDataOverflow; ///< For data that didn't fit into the m_OutgoingData ringbuffer temporarily
Vector3d m_ConfirmPosition;
@ -252,18 +257,22 @@ private:
enum eState
{
csConnected, // The client has just connected, waiting for their handshake / login
csAuthenticating, // The client has logged in, waiting for external authentication
csDownloadingWorld, // The client is waiting for chunks, we're waiting for the loader to provide and send them
csConfirmingPos, // The client has been sent the position packet, waiting for them to repeat the position back
csPlaying, // Normal gameplay
csDestroying, // The client is being destroyed, don't queue any more packets / don't add to chunks
csDestroyed, // The client has been destroyed, the destructor is to be called from the owner thread
csConnected, ///< The client has just connected, waiting for their handshake / login
csAuthenticating, ///< The client has logged in, waiting for external authentication
csAuthenticated, ///< The client has been authenticated, will start streaming chunks in the next tick
csDownloadingWorld, ///< The client is waiting for chunks, we're waiting for the loader to provide and send them
csConfirmingPos, ///< The client has been sent the position packet, waiting for them to repeat the position back
csPlaying, ///< Normal gameplay
csDestroying, ///< The client is being destroyed, don't queue any more packets / don't add to chunks
csDestroyed, ///< The client has been destroyed, the destructor is to be called from the owner thread
// TODO: Add Kicking here as well
} ;
eState m_State;
/// m_State needs to be locked in the Destroy() function so that the destruction code doesn't run twice on two different threads
cCriticalSection m_CSDestroyingState;
bool m_bKeepThreadGoing;
@ -279,12 +288,6 @@ private:
/// Running sum of m_NumExplosionsPerTick[]
int m_RunningSumExplosions;
/// Lock for the m_PendingMessages buffer
cCriticalSection m_CSMessages;
/// Buffer for received messages to be processed in the Tick thread
AStringList m_PendingMessages;
static int s_ClientCount;
int m_UniqueID;
@ -311,9 +314,6 @@ private:
/// Handles the block placing packet when it is a real block placement (not block-using, item-using or eating)
void HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, cItemHandler & a_ItemHandler);
/// Processes the messages in m_PendingMessages; called from the Tick thread
void ProcessPendingMessages(void);
// cSocketThreads::cCallback overrides:
virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client

155
source/DeadlockDetect.cpp Normal file
View File

@ -0,0 +1,155 @@
// DeadlockDetect.cpp
// Declares the cDeadlockDetect class that tries to detect deadlocks and aborts the server when it detects one
#include "Globals.h"
#include "DeadlockDetect.h"
#include "Root.h"
#include "World.h"
/// Number of milliseconds per cycle
const int CYCLE_MILLISECONDS = 500;
/// When the number of cycles for the same world age hits this value, it is considered a deadlock
const int NUM_CYCLES_LIMIT = 40; // 40 = twenty seconds
cDeadlockDetect::cDeadlockDetect(void) :
super("DeadlockDetect")
{
}
bool cDeadlockDetect::Start(void)
{
// Read the initial world data:
class cFillIn :
public cWorldListCallback
{
public:
cFillIn(cDeadlockDetect * a_Detect) :
m_Detect(a_Detect)
{
}
virtual bool Item(cWorld * a_World) override
{
m_Detect->SetWorldAge(a_World->GetName(), a_World->GetWorldAge());
return false;
}
protected:
cDeadlockDetect * m_Detect;
} FillIn(this);
cRoot::Get()->ForEachWorld(FillIn);
return super::Start();
}
void cDeadlockDetect::Stop(void)
{
m_EvtTerminate.Set();
super::Stop();
}
void cDeadlockDetect::Execute(void)
{
// Loop until the event is signalled
while (m_EvtTerminate.Wait(CYCLE_MILLISECONDS) == cEvent::wrTimeout)
{
// Check the world ages:
class cChecker :
public cWorldListCallback
{
public:
cChecker(cDeadlockDetect * a_Detect) :
m_Detect(a_Detect)
{
}
protected:
cDeadlockDetect * m_Detect;
virtual bool Item(cWorld * a_World) override
{
m_Detect->CheckWorldAge(a_World->GetName(), a_World->GetWorldAge());
return false;
}
} Checker(this);
cRoot::Get()->ForEachWorld(Checker);
} // while (should run)
}
void cDeadlockDetect::SetWorldAge(const AString & a_WorldName, Int64 a_Age)
{
m_WorldAges[a_WorldName].m_Age = a_Age;
m_WorldAges[a_WorldName].m_NumCyclesSame = 0;
}
void cDeadlockDetect::CheckWorldAge(const AString & a_WorldName, Int64 a_Age)
{
WorldAges::iterator itr = m_WorldAges.find(a_WorldName);
if (itr == m_WorldAges.end())
{
ASSERT(!"Unknown world in cDeadlockDetect");
return;
}
if (itr->second.m_Age == a_Age)
{
itr->second.m_NumCyclesSame += 1;
if (itr->second.m_NumCyclesSame > NUM_CYCLES_LIMIT)
{
DeadlockDetected();
return;
}
}
else
{
itr->second.m_Age = a_Age;
itr->second.m_NumCyclesSame = 0;
}
}
void cDeadlockDetect::DeadlockDetected(void)
{
ASSERT(!"Deadlock detected");
// TODO: Make a crashdump / coredump
// Crash the server intentionally:
*((int *)0) = 0;
}

70
source/DeadlockDetect.h Normal file
View File

@ -0,0 +1,70 @@
// DeadlockDetect.h
// Declares the cDeadlockDetect class that tries to detect deadlocks and aborts the server when it detects one
/*
This class simply monitors each world's m_WorldAge, which is expected to grow on each tick.
If the world age doesn't grow for several seconds, it's either because the server is super-overloaded,
or because the world tick thread hangs in a deadlock. We presume the latter and therefore kill the server.
Once we learn to write crashdumps programmatically, we should do so just before killing, to enable debugging.
*/
#pragma once
#include "OSSupport/IsThread.h"
class cDeadlockDetect :
public cIsThread
{
typedef cIsThread super;
public:
cDeadlockDetect(void);
/// Starts the detection. Hides cIsThread's Start, because we need some initialization
bool Start(void);
/// Stops the detection. Hides cIsThread's Stop, because we need to signal m_EvtTerminate
void Stop(void);
protected:
struct sWorldAge
{
/// Last m_WorldAge that has been detected in this world
Int64 m_Age;
/// Number of cycles for which the age has been the same
int m_NumCyclesSame;
} ;
/// Maps world name -> sWorldAge
typedef std::map<AString, sWorldAge> WorldAges;
WorldAges m_WorldAges;
cEvent m_EvtTerminate;
// cIsThread overrides:
virtual void Execute(void) override;
/// Sets the initial world age
void SetWorldAge(const AString & a_WorldName, Int64 a_Age);
/// Checks if the world's age has changed, updates the world's stats; calls DeadlockDetected() if deadlock detected
void CheckWorldAge(const AString & a_WorldName, Int64 a_Age);
/// Called when a deadlock is detected. Aborts the server.
void DeadlockDetected(void);
} ;

View File

@ -33,7 +33,7 @@ public:
a_BlockY--;
}
if (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, a_Item.m_ItemDamage) >= 0)
if (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, (cMonster::eType)(a_Item.m_ItemDamage)) >= 0)
{
if (a_Player->GetGameMode() != 1)
{

View File

@ -32,7 +32,7 @@ extern "C"
const cLuaState::cRet cLuaState::Return;
const cLuaState::cRet cLuaState::Return = {};

View File

@ -3,6 +3,7 @@
#include "AggressiveMonster.h"
#include "../World.h"
#include "../Vector3f.h"
#include "../Player.h"
#include "../MersenneTwister.h"

View File

@ -2,6 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Cavespider.h"
#include "../World.h"

View File

@ -3,7 +3,6 @@
#include "../Pawn.h"
#include "../Defines.h"
#include "../World.h"
#include "../BlockID.h"
#include "../Item.h"
@ -13,6 +12,7 @@
class Vector3f;
class cClientHandle;
class cWorld;
@ -23,7 +23,41 @@ class cMonster :
{
typedef cPawn super;
public:
/// This identifies individual monster type, as well as their network type-ID
enum eType
{
mtCreeper = E_META_SPAWN_EGG_CREEPER,
mtSkeleton = E_META_SPAWN_EGG_SKELETON,
mtSpider = E_META_SPAWN_EGG_SPIDER,
mtGiant = E_META_SPAWN_EGG_GIANT,
mtZombie = E_META_SPAWN_EGG_ZOMBIE,
mtSlime = E_META_SPAWN_EGG_SLIME,
mtGhast = E_META_SPAWN_EGG_GHAST,
mtZombiePigman = E_META_SPAWN_EGG_ZOMBIE_PIGMAN,
mtEnderman = E_META_SPAWN_EGG_ENDERMAN,
mtCaveSpider = E_META_SPAWN_EGG_CAVE_SPIDER,
mtSilverfish = E_META_SPAWN_EGG_SILVERFISH,
mtBlaze = E_META_SPAWN_EGG_BLAZE,
mtMagmaCube = E_META_SPAWN_EGG_MAGMA_CUBE,
mtEnderDragon = E_META_SPAWN_EGG_ENDER_DRAGON,
mtWither = E_META_SPAWN_EGG_WITHER,
mtBat = E_META_SPAWN_EGG_BAT,
mtWitch = E_META_SPAWN_EGG_WITCH,
mtPig = E_META_SPAWN_EGG_PIG,
mtSheep = E_META_SPAWN_EGG_SHEEP,
mtCow = E_META_SPAWN_EGG_COW,
mtChicken = E_META_SPAWN_EGG_CHICKEN,
mtSquid = E_META_SPAWN_EGG_SQUID,
mtWolf = E_META_SPAWN_EGG_WOLF,
mtMooshroom = E_META_SPAWN_EGG_MOOSHROOM,
mtSnowGolem = E_META_SPAWN_EGG_SNOW_GOLEM,
mtOcelot = E_META_SPAWN_EGG_OCELOT,
mtIronGolem = E_META_SPAWN_EGG_IRON_GOLEM,
mtVillager = E_META_SPAWN_EGG_VILLAGER,
} ;
// tolua_end
float m_SightDistance;
/** Creates the mob object.

View File

@ -3,6 +3,7 @@
#include "PassiveMonster.h"
#include "../MersenneTwister.h"
#include "../World.h"

View File

@ -2,6 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Skeleton.h"
#include "../World.h"

View File

@ -2,6 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Zombie.h"
#include "../World.h"

View File

@ -2,6 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Zombiepigman.h"
#include "../World.h"

View File

@ -15,7 +15,7 @@
cEvent::cEvent(void)
{
#ifdef _WIN32
m_Event = CreateEvent( 0, FALSE, FALSE, 0 );
m_Event = CreateEvent(NULL, FALSE, FALSE, NULL);
if (m_Event == NULL)
{
LOGERROR("cEvent: cannot create event, GLE = %d. Aborting server.", GetLastError());
@ -78,19 +78,19 @@ cEvent::~cEvent()
void cEvent::Wait(void)
{
#ifdef _WIN32
DWORD res = WaitForSingleObject(m_Event, INFINITE);
if (res != WAIT_OBJECT_0)
{
LOGWARN("cEvent: waiting for the event failed: %d, GLE = %d. Continuing, but server may be unstable.", res, GetLastError());
}
#else
int res = sem_wait(m_Event);
if (res != 0 )
{
LOGWARN("cEvent: waiting for the event failed: %i, errno = %i. Continuing, but server may be unstable.", res, errno);
}
#endif
#ifdef _WIN32
DWORD res = WaitForSingleObject(m_Event, INFINITE);
if (res != WAIT_OBJECT_0)
{
LOGWARN("cEvent: waiting for the event failed: %d, GLE = %d. Continuing, but server may be unstable.", res, GetLastError());
}
#else
int res = sem_wait(m_Event);
if (res != 0 )
{
LOGWARN("cEvent: waiting for the event failed: %i, errno = %i. Continuing, but server may be unstable.", res, errno);
}
#endif
}
@ -99,18 +99,70 @@ void cEvent::Wait(void)
void cEvent::Set(void)
{
#ifdef _WIN32
if (!SetEvent(m_Event))
{
LOGWARN("cEvent: Could not set cEvent: GLE = %d", GetLastError());
}
#else
int res = sem_post(m_Event);
if (res != 0)
{
LOGWARN("cEvent: Could not set cEvent: %i, errno = %d", res, errno);
}
#endif
#ifdef _WIN32
if (!SetEvent(m_Event))
{
LOGWARN("cEvent: Could not set cEvent: GLE = %d", GetLastError());
}
#else
int res = sem_post(m_Event);
if (res != 0)
{
LOGWARN("cEvent: Could not set cEvent: %i, errno = %d", res, errno);
}
#endif
}
cEvent::eWaitResult cEvent::Wait(int a_TimeoutMilliSec)
{
#ifdef _WIN32
DWORD res = WaitForSingleObject(m_Event, (DWORD)a_TimeoutMilliSec);
switch (res)
{
case WAIT_OBJECT_0:
{
// The semaphore was signalled
return wrSignalled;
}
case WAIT_TIMEOUT:
{
// The timeout was hit
return wrTimeout;
}
default:
{
LOGWARNING("cEvent: timed-waiting for the event failed: %d, GLE = %d. Continuing, but server may be unstable.", res, GetLastError());
return wrError;
}
}
#else
timespec timeout;
timeout.tv_sec = a_TimeoutMilliSec / 1000;
timeout.tv_nsec = (a_TimeoutMilliSec % 1000) * 1000000;
int res = sem_timedwait(m_Event, &timeout);
switch (res)
{
case 0:
{
// The semaphore was signalled
return wrSignalled;
}
case ETIMEDOUT:
{
// The timeout was hit
return wrTimeout;
}
default:
{
LOGWARNING("cEvent: timed-waiting for the event failed: %i, errno = %i. Continuing, but server may be unstable.", res, errno);
return wrError;
}
}
#endif
}

View File

@ -19,12 +19,22 @@
class cEvent
{
public:
enum eWaitResult
{
wrSignalled,
wrTimeout,
wrError,
} ;
cEvent(void);
~cEvent();
void Wait(void);
void Set (void);
/// Waits for the semaphore with a timeout
eWaitResult Wait(int a_TimeoutMilliSec);
private:
#ifdef _WIN32

View File

@ -116,36 +116,38 @@ bool cIsThread::Start(void)
void cIsThread::Stop(void)
{
if (m_Handle == NULL)
{
return;
}
m_ShouldTerminate = true;
Wait();
}
bool cIsThread::Wait(void)
{
#ifdef _WIN32
if (m_Handle == NULL)
{
return true;
}
LOGD("Waiting for thread %s to finish", m_ThreadName.c_str());
if (m_Handle == NULL)
{
return true;
}
// Cannot log, logger may already be stopped:
// LOG("Waiting for thread \"%s\" to terminate.", m_ThreadName.c_str());
#ifdef _WIN32
int res = WaitForSingleObject(m_Handle, INFINITE);
m_Handle = NULL;
// Cannot log, logger may already be stopped:
// LOG("Thread \"%s\" %s terminated, GLE = %d", m_ThreadName.c_str(), (res == WAIT_OBJECT_0) ? "" : "not", GetLastError());
LOGD("Thread %s finished", m_ThreadName.c_str());
return (res == WAIT_OBJECT_0);
#else // _WIN32
if (!m_HasStarted)
{
return true;
}
// Cannot log, logger may already be stopped:
// LOG("Waiting for thread \"%s\" to terminate.", m_ThreadName.c_str());
int res = pthread_join(m_Handle, NULL);
m_HasStarted = false;
// Cannot log, logger may already be stopped:
// LOG("Thread \"%s\" %s terminated, errno = %d", m_ThreadName.c_str(), (res == 0) ? "" : "not", errno);
m_Handle = NULL;
LOGD("Thread %s finished", m_ThreadName.c_str());
return (res == 0);
#endif // else _WIN32
}

View File

@ -39,6 +39,9 @@ public:
/// Starts the thread; returns without waiting for the actual start
bool Start(void);
/// Signals the thread to terminate and waits until it's finished
void Stop(void);
/// Waits for the thread to finish. Doesn't signalize the ShouldTerminate flag
bool Wait(void);
@ -54,7 +57,9 @@ private:
static DWORD_PTR __stdcall thrExecute(LPVOID a_Param)
{
HWND IdentificationWnd = CreateWindow("STATIC", ((cIsThread *)a_Param)->m_ThreadName.c_str(), 0, 0, 0, 0, WS_OVERLAPPED, NULL, NULL, NULL, NULL);
((cIsThread *)a_Param)->Execute();
DestroyWindow(IdentificationWnd);
return 0;
}
@ -70,7 +75,6 @@ private:
}
#endif // else _WIN32
} ;

View File

@ -100,6 +100,8 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
m_LastJumpHeight = (float)(GetPosY());
m_LastGroundHeight = (float)(GetPosY());
m_Stance = GetPosY() + 1.62;
cRoot::Get()->GetServer()->PlayerCreated(this);
}
@ -110,6 +112,9 @@ cPlayer::~cPlayer(void)
{
LOGD("Deleting cPlayer \"%s\" at %p, ID %d", m_PlayerName.c_str(), this, GetUniqueID());
// Notify the server that the player is being destroyed
cRoot::Get()->GetServer()->PlayerDestroying(this);
SaveToDisk();
m_World->RemovePlayer( this );
@ -127,8 +132,16 @@ cPlayer::~cPlayer(void)
bool cPlayer::Initialize(cWorld * a_World)
{
ASSERT(a_World != NULL);
if (super::Initialize(a_World))
{
// Remove the client handle from the server, it will be ticked from this object from now on
if (m_ClientHandle != NULL)
{
cRoot::Get()->GetServer()->ClientMovedToWorld(m_ClientHandle);
}
GetWorld()->AddPlayer(this);
return true;
}
@ -142,6 +155,7 @@ bool cPlayer::Initialize(cWorld * a_World)
void cPlayer::Destroyed()
{
CloseWindow(false);
m_ClientHandle = NULL;
}
@ -151,22 +165,17 @@ void cPlayer::Destroyed()
void cPlayer::SpawnOn(cClientHandle & a_Client)
{
/*
LOGD("cPlayer::SpawnOn(%s) for \"%s\" at pos {%.2f, %.2f, %.2f}",
a_Client.GetUsername().c_str(), m_PlayerName.c_str(), m_Pos.x, m_Pos.y, m_Pos.z
);
*/
if (m_bVisible && (m_ClientHandle != (&a_Client)))
if (!m_bVisible || (m_ClientHandle == (&a_Client)))
{
a_Client.SendPlayerSpawn(*this);
a_Client.SendEntityHeadLook(*this);
a_Client.SendEntityEquipment(*this, 0, m_Inventory.GetEquippedItem() );
a_Client.SendEntityEquipment(*this, 1, m_Inventory.GetEquippedBoots() );
a_Client.SendEntityEquipment(*this, 2, m_Inventory.GetEquippedLeggings() );
a_Client.SendEntityEquipment(*this, 3, m_Inventory.GetEquippedChestplate() );
a_Client.SendEntityEquipment(*this, 4, m_Inventory.GetEquippedHelmet() );
return;
}
a_Client.SendPlayerSpawn(*this);
a_Client.SendEntityHeadLook(*this);
a_Client.SendEntityEquipment(*this, 0, m_Inventory.GetEquippedItem() );
a_Client.SendEntityEquipment(*this, 1, m_Inventory.GetEquippedBoots() );
a_Client.SendEntityEquipment(*this, 2, m_Inventory.GetEquippedLeggings() );
a_Client.SendEntityEquipment(*this, 3, m_Inventory.GetEquippedChestplate() );
a_Client.SendEntityEquipment(*this, 4, m_Inventory.GetEquippedHelmet() );
}
@ -175,18 +184,28 @@ void cPlayer::SpawnOn(cClientHandle & a_Client)
void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
{
if (!m_ClientHandle->IsPlaying())
if (m_ClientHandle != NULL)
{
// We're not yet in the game, ignore everything
return;
if (m_ClientHandle->IsDestroyed())
{
// This should not happen, because destroying a client will remove it from the world, but just in case
m_ClientHandle = NULL;
return;
}
if (!m_ClientHandle->IsPlaying())
{
// We're not yet in the game, ignore everything
return;
}
}
super::Tick(a_Dt, a_Chunk);
// set player swimming state
SetSwimState( a_Chunk);
// Set player swimming state
SetSwimState(a_Chunk);
// handle air drowning stuff
// Handle air drowning stuff
HandleAir();
if (m_bDirtyPosition)
@ -1106,20 +1125,15 @@ bool cPlayer::MoveToWorld(const char * a_WorldName)
m_ClientHandle->RemoveFromAllChunks();
m_World->RemoveEntity(this);
// If the dimension is different, we can send the respawn packet
// http://wiki.vg/Protocol#0x09 says "don't send if dimension is the same" as of 2013_07_02
m_ClientHandle->MoveToWorld(*World, (OldDimension != World->GetDimension()));
// Add player to all the necessary parts of the new world
SetWorld(World);
World->AddEntity(this);
World->AddPlayer(this);
// If the dimension is different, we can send the respawn packet
// http://wiki.vg/Protocol#0x09 says "don't send if dimension is the same" as of 2013_07_02
if (OldDimension != World->GetDimension())
{
m_ClientHandle->SendRespawn();
}
// Stream the new chunks:
m_ClientHandle->StreamChunks();
return true;
}

View File

@ -40,7 +40,7 @@ public:
cPlayer(cClientHandle * a_Client, const AString & a_PlayerName);
virtual ~cPlayer();
virtual bool Initialize(cWorld * a_World); // tolua_export
virtual bool Initialize(cWorld * a_World) override;
virtual void SpawnOn(cClientHandle & a_Client) override;

View File

@ -14,6 +14,7 @@ Documentation:
#include "Protocol125.h"
#include "../ClientHandle.h"
#include "../World.h"
#include "ChunkDataSerializer.h"
#include "../Entity.h"
#include "../Mobs/Monster.h"

Some files were not shown because too many files have changed in this diff Show More