Files
mod-ale/ElunaUtility.cpp
Patman64 31470c2cf7 Allow scripting of instances w/ persistent data
Some fixes for TC and changes overall

Pass map object to hook via function arguments

The map object is no longer stored inside the instance data table.

Fix mistake in base64 decoder

It was failing whenever it encountered a '=' character, which is
completely valid.

Make ElunaInstanceAI::Load always load something

When it failed to load data, it was leaving nothing on the stack. Since
subsequent code expected Load to always load something, this was causing
issues.

Now, when Load fails to load anything, it just leaves a new empty table on
the stack.

Also: the error messages for Load have been improved.

Modify lua-marshal to allow saving of functions/userdata.

Some additional code was needed to save functions due to the inclusion of
a reference to _ENV within their upvalues (since Lua 5.2).

During encoding, a placeholder is left where the _ENV reference would be.
During decoding, a reference to the current _G is swapped with the
placeholder.

Make ElunaInstanceAI::Load re-initialize if data failed to load.

Also improve error messages by not including the raw data.

Improve storage format of upvalues

Instead of storing the upvalues by name, store by index. A wrapper is
still used in case the upvalue is nil, to prevent holes in the upvalues table.

A special field in the upvalues table, "E", is used to store the index of
the _ENV reference (if there was one). A reference to the current globals
table is set as the upvalue upon decoding.

Remove wrapping from upvalue storing, instead save amount of upvalues
2015-08-01 00:35:41 +03:00

182 lines
5.8 KiB
C++

/*
* Copyright (C) 2010 - 2015 Eluna Lua Engine <http://emudevs.com/>
* This program is free software licensed under GPL version 3
* Please see the included DOCS/LICENSE.md for more information
*/
#include "ElunaUtility.h"
#include "World.h"
#include "Object.h"
#include "Unit.h"
uint32 ElunaUtil::GetCurrTime()
{
#ifndef TRINITY
return WorldTimer::getMSTime();
#else
return getMSTime();
#endif
}
uint32 ElunaUtil::GetTimeDiff(uint32 oldMSTime)
{
#ifndef TRINITY
return WorldTimer::getMSTimeDiff(oldMSTime, GetCurrTime());
#else
return GetMSTimeDiffToNow(oldMSTime);
#endif
}
ElunaUtil::ObjectGUIDCheck::ObjectGUIDCheck(ObjectGuid guid) : _guid(guid)
{
}
bool ElunaUtil::ObjectGUIDCheck::operator()(WorldObject* object)
{
return object->GET_GUID() == _guid;
}
ElunaUtil::ObjectDistanceOrderPred::ObjectDistanceOrderPred(WorldObject const* pRefObj, bool ascending) : m_refObj(pRefObj), m_ascending(ascending)
{
}
bool ElunaUtil::ObjectDistanceOrderPred::operator()(WorldObject const* pLeft, WorldObject const* pRight) const
{
return m_ascending ? m_refObj->GetDistanceOrder(pLeft, pRight) : !m_refObj->GetDistanceOrder(pLeft, pRight);
}
ElunaUtil::WorldObjectInRangeCheck::WorldObjectInRangeCheck(bool nearest, WorldObject const* obj, float range,
uint16 typeMask, uint32 entry, uint32 hostile) :
i_obj(obj), i_hostile(hostile), i_entry(entry), i_range(range), i_typeMask(typeMask), i_nearest(nearest)
{
}
WorldObject const& ElunaUtil::WorldObjectInRangeCheck::GetFocusObject() const
{
return *i_obj;
}
bool ElunaUtil::WorldObjectInRangeCheck::operator()(WorldObject* u)
{
if (i_typeMask && !u->isType(TypeMask(i_typeMask)))
return false;
if (i_entry && u->GetEntry() != i_entry)
return false;
if (i_obj->GET_GUID() == u->GET_GUID())
return false;
if (!i_obj->IsWithinDistInMap(u, i_range))
return false;
if (Unit* unit = u->ToUnit())
{
#ifdef CMANGOS
if (!unit->isAlive())
return false;
#else
if (!unit->IsAlive())
return false;
#endif
if (i_hostile)
{
if (const Unit* obj = i_obj->ToUnit())
{
if ((i_hostile == 1) != obj->IsHostileTo(unit))
return false;
}
}
}
if (i_nearest)
i_range = i_obj->GetDistance(u);
return true;
}
static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'};
static char decoding_table[256];
static int mod_table[] = {0, 2, 1};
static void build_decoding_table()
{
for (int i = 0; i < 64; i++)
decoding_table[(unsigned char)encoding_table[i]] = i;
}
void ElunaUtil::EncodeData(const unsigned char* data, size_t input_length, std::string& output)
{
size_t output_length = 4 * ((input_length + 2) / 3);
char* buffer = new char[output_length];
for (size_t i = 0, j = 0; i < input_length;)
{
uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0;
uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0;
uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0;
uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
buffer[j++] = encoding_table[(triple >> (3 * 6)) & 0x3F];
buffer[j++] = encoding_table[(triple >> (2 * 6)) & 0x3F];
buffer[j++] = encoding_table[(triple >> (1 * 6)) & 0x3F];
buffer[j++] = encoding_table[(triple >> (0 * 6)) & 0x3F];
}
for (int i = 0; i < mod_table[input_length % 3]; i++)
buffer[output_length - 1 - i] = '=';
output.assign(buffer, output_length); // Need length because `buffer` is not terminated!
delete[] buffer;
}
unsigned char* ElunaUtil::DecodeData(const char *data, size_t *output_length)
{
if (decoding_table['B'] == 0)
build_decoding_table();
size_t input_length = strlen(data);
if (input_length % 4 != 0)
return NULL;
// Make sure there's no invalid characters in the data.
for (size_t i = 0; i < input_length; ++i)
{
unsigned char byte = data[i];
if (byte == '=')
continue;
// Every invalid character (and 'A') will map to 0 (due to `calloc`).
if (decoding_table[byte] == 0 && byte != 'A')
return NULL;
}
*output_length = input_length / 4 * 3;
if (data[input_length - 1] == '=') (*output_length)--;
if (data[input_length - 2] == '=') (*output_length)--;
unsigned char *decoded_data = new unsigned char[*output_length];
if (!decoded_data)
return NULL;
for (size_t i = 0, j = 0; i < input_length;)
{
uint32_t sextet_a = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
uint32_t sextet_b = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
uint32_t sextet_c = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
uint32_t sextet_d = data[i] == '=' ? 0 & i++ : decoding_table[data[i++]];
uint32_t triple = (sextet_a << (3 * 6))
+ (sextet_b << (2 * 6))
+ (sextet_c << (1 * 6))
+ (sextet_d << (0 * 6));
if (j < *output_length) decoded_data[j++] = (triple >> (2 * 8)) & 0xFF;
if (j < *output_length) decoded_data[j++] = (triple >> (1 * 8)) & 0xFF;
if (j < *output_length) decoded_data[j++] = (triple >> (0 * 8)) & 0xFF;
}
return decoded_data;
}