Retransmit support added back in (stupid compile flags), prelim work on lua_client stuff, took out a few redundant or non-working functions

This commit is contained in:
KimLS 2013-05-25 01:08:30 -07:00
parent d25d8187b6
commit 79a9d2112a
17 changed files with 405 additions and 491 deletions

View File

@ -23,6 +23,7 @@
#include "Mutex.h"
#include "op_codes.h"
#include "CRC16.h"
#include "platform.h"
#include <string>
#include <iomanip>
@ -30,13 +31,6 @@
#include <vector>
#include <algorithm>
#if defined(ZONE) || defined(WORLD)
#define RETRANSMITS
#endif
#ifdef RETRANSMITS
#include "rulesys.h"
#endif
#ifdef _WINDOWS
#include <time.h>
#else
@ -75,17 +69,20 @@ void EQStream::init() {
BytesWritten=0;
SequencedBase = 0;
NextSequencedSend = 0;
#ifdef RETRANSMITS
retransmittimer = Timer::GetCurrentTime();
retransmittimeout = 500 * RuleR(EQStream, RetransmitTimeoutMult); //use 500ms as base before we have connection stats
#endif
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
retransmittimer = Timer::GetCurrentTime();
retransmittimeout = 500 * RETRANSMIT_TIMEOUT_MULT;
}
OpMgr = nullptr;
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
_log(NET__ERROR, _L "init Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
if(NextSequencedSend > SequencedQueue.size()) {
_log(NET__ERROR, _L "init Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size());
}
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
_log(NET__ERROR, _L "init Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
if(NextSequencedSend > SequencedQueue.size()) {
_log(NET__ERROR, _L "init Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size());
}
}
EQRawApplicationPacket *EQStream::MakeApplicationPacket(EQProtocolPacket *p)
@ -118,7 +115,7 @@ EQProtocolPacket *EQStream::MakeProtocolPacket(const unsigned char *buf, uint32
void EQStream::ProcessPacket(EQProtocolPacket *p)
{
uint32 processed=0,subpacket_length=0;
uint32 processed=0, subpacket_length=0;
if (p == nullptr)
return;
// Raw Application packet
@ -304,9 +301,10 @@ uint32 processed=0,subpacket_length=0;
#ifndef COLLECTOR
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
AckPackets(seq);
#ifdef RETRANSMITS
retransmittimer = Timer::GetCurrentTime();
#endif
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
retransmittimer = Timer::GetCurrentTime();
}
#endif
}
break;
@ -409,19 +407,24 @@ uint32 processed=0,subpacket_length=0;
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
MOutboundQueue.lock();
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
_log(NET__ERROR, _L "Pre-OOA Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
if(NextSequencedSend > SequencedQueue.size()) {
_log(NET__ERROR, _L "Pre-OOA Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size());
}
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
_log(NET__ERROR, _L "Pre-OOA Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
if(NextSequencedSend > SequencedQueue.size()) {
_log(NET__ERROR, _L "Pre-OOA Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size());
}
//if the packet they got out of order is between our last acked packet and the last sent packet, then its valid.
if (CompareSequence(SequencedBase,seq) != SeqPast && CompareSequence(NextOutSeq,seq) == SeqPast) {
_log(NET__NET_TRACE, _L "Received OP_OutOfOrderAck for sequence %d, starting retransmit at the start of our unacked buffer (seq %d, was %d)." __L,
seq, SequencedBase, SequencedBase+NextSequencedSend);
#ifdef RETRANSMITS
if (!RuleB(EQStream, RetransmitAckedPackets)) {
#endif
bool retransmit_acked_packets = false;
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
retransmit_acked_packets = RETRANSMIT_ACKED_PACKETS;
}
if(!retransmit_acked_packets) {
uint16 sqsize = SequencedQueue.size();
uint16 index = seq - SequencedBase;
_log(NET__NET_TRACE, _L "OP_OutOfOrderAck marking packet acked in queue (queue index = %d, queue size = %d)." __L, index, sqsize);
@ -431,22 +434,24 @@ if(NextSequencedSend > SequencedQueue.size()) {
sitr += index;
(*sitr)->acked = true;
}
#ifdef RETRANSMITS
}
if (RuleR(EQStream, RetransmitTimeoutMult)) { // only choose new behavior if multiplier is set
if(RETRANSMIT_TIMEOUT_MULT) {
retransmittimer = Timer::GetCurrentTime();
}
#endif
NextSequencedSend = 0;
} else {
_log(NET__NET_TRACE, _L "Received OP_OutOfOrderAck for out-of-window %d. Window (%d->%d)." __L, seq, SequencedBase, NextOutSeq);
}
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
_log(NET__ERROR, _L "Post-OOA Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
if(NextSequencedSend > SequencedQueue.size()) {
_log(NET__ERROR, _L "Post-OOA Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size());
}
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
_log(NET__ERROR, _L "Post-OOA Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
if(NextSequencedSend > SequencedQueue.size()) {
_log(NET__ERROR, _L "Post-OOA Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size());
}
MOutboundQueue.unlock();
#endif
}
@ -468,19 +473,21 @@ if(NextSequencedSend > SequencedQueue.size()) {
Stats->packets_sent=x;
NonSequencedPush(new EQProtocolPacket(OP_SessionStatResponse,p->pBuffer,p->size));
AdjustRates(ntohl(Stats->average_delta));
#ifdef RETRANSMITS
if (RuleR(EQStream, RetransmitTimeoutMult) && ntohl(Stats->average_delta)) {
//recalculate retransmittimeout using the larger of the last rtt or average rtt, which is multiplied by the rule value
if((ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta)) > (ntohl(Stats->average_delta) * 2)) {
retransmittimeout = (ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta)) * RuleR(EQStream, RetransmitTimeoutMult);
} else {
retransmittimeout = ntohl(Stats->average_delta) * 2 * RuleR(EQStream, RetransmitTimeoutMult);
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
if(RETRANSMIT_TIMEOUT_MULT && ntohl(Stats->average_delta)) {
//recalculate retransmittimeout using the larger of the last rtt or average rtt, which is multiplied by the rule value
if((ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta)) > (ntohl(Stats->average_delta) * 2)) {
retransmittimeout = (ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta))
* RETRANSMIT_TIMEOUT_MULT;
} else {
retransmittimeout = ntohl(Stats->average_delta) * 2 * RETRANSMIT_TIMEOUT_MULT;
}
if(retransmittimeout > RETRANSMIT_TIMEOUT_MAX)
retransmittimeout = RETRANSMIT_TIMEOUT_MAX;
_log(NET__NET_TRACE, _L "Retransmit timeout recalculated to %dms" __L, retransmittimeout);
}
if(retransmittimeout > RuleI(EQStream, RetransmitTimeoutMax))
retransmittimeout = RuleI(EQStream, RetransmitTimeoutMax);
_log(NET__NET_TRACE, _L "Retransmit timeout recalculated to %dms" __L, retransmittimeout);
}
#endif
#endif
}
break;
@ -527,16 +534,6 @@ void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req)
uint16 opcode = (*OpMgr)->EmuToEQ(pack->emu_opcode);
//make sure this packet is compatible with this stream
/* if(StreamType == UnknownStream || StreamType == ChatOrMailStream) {
_log(NET__DEBUG, _L "Stream type undetermined (%s), packet ignored" __L, StreamTypeString(StreamType));
return;
}
if(pack->GetPacketType() != StreamType) {
_log(NET__ERROR, _L "Trying to queue a packet of type %s into a stream of type %s, dropping it." __L, StreamTypeString(pack->GetPacketType()), StreamTypeString(StreamType));
return;
}*/
_log(NET__APP_TRACE, "Queueing %sacked packet with opcode 0x%x (%s) and length %d", ack_req?"":"non-", opcode, OpcodeManager::EmuToName(pack->emu_opcode), pack->size);
if (!ack_req) {
@ -549,8 +546,8 @@ void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req)
void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
{
uint32 chunksize,used;
uint32 length;
uint32 chunksize,used;
uint32 length;
// Convert the EQApplicationPacket to 1 or more EQProtocolPackets
if (p->size>(MaxLen-8)) { // proto-op(2), seq(2), app-op(2) ... data ... crc(2)
@ -648,9 +645,9 @@ uint16 Seq=htons(seq);
void EQStream::Write(int eq_fd)
{
std::queue<EQProtocolPacket *> ReadyToSend;
bool SeqEmpty=false,NonSeqEmpty=false;
std::deque<EQProtocolPacket *>::iterator sitr;
std::queue<EQProtocolPacket *> ReadyToSend;
bool SeqEmpty=false, NonSeqEmpty=false;
std::deque<EQProtocolPacket *>::iterator sitr;
// Check our rate to make sure we can send more
MRate.lock();
@ -673,14 +670,16 @@ std::deque<EQProtocolPacket *>::iterator sitr;
// Place to hold the base packet t combine into
EQProtocolPacket *p=nullptr;
#ifdef RETRANSMITS
// if we have a timeout defined and we have not received an ack recently enough, retransmit from beginning of queue
if (RuleR(EQStream, RetransmitTimeoutMult) && !SequencedQueue.empty() && NextSequencedSend && (GetState()==ESTABLISHED) && ((retransmittimer+retransmittimeout) < Timer::GetCurrentTime())) {
_log(NET__NET_TRACE, _L "Timeout since last ack received, starting retransmit at the start of our unacked buffer (seq %d, was %d)." __L, SequencedBase, SequencedBase+NextSequencedSend);
NextSequencedSend = 0;
retransmittimer = Timer::GetCurrentTime(); // don't want to endlessly retransmit the first packet
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
// if we have a timeout defined and we have not received an ack recently enough, retransmit from beginning of queue
if (RETRANSMIT_TIMEOUT_MULT && !SequencedQueue.empty() && NextSequencedSend &&
(GetState()==ESTABLISHED) && ((retransmittimer+retransmittimeout) < Timer::GetCurrentTime())) {
_log(NET__NET_TRACE, _L "Timeout since last ack received, starting retransmit at the start of our unacked "
"buffer (seq %d, was %d)." __L, SequencedBase, SequencedBase+NextSequencedSend);
NextSequencedSend = 0;
retransmittimer = Timer::GetCurrentTime(); // don't want to endlessly retransmit the first packet
}
}
#endif
// Find the next sequenced packet to send from the "queue"
sitr = SequencedQueue.begin();
@ -723,65 +722,87 @@ std::deque<EQProtocolPacket *>::iterator sitr;
}
if (sitr!=SequencedQueue.end()) {
//_log(NET__NET_COMBINE, _L "Send Seq with %d seq packets starting at seq %d, next send %d, and %d non-seq packets." __L,
// SequencedQueue.size(), SequencedBase, NextSequencedSend, NonSequencedQueue.size());
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
_log(NET__ERROR, _L "Pre-Send Seq NSS=%d Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, NextSequencedSend, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
if(NextSequencedSend > SequencedQueue.size()) {
_log(NET__ERROR, _L "Pre-Send Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size());
}
uint16 seq_send = SequencedBase + NextSequencedSend; //just for logging...
if(SequencedQueue.empty()) {
_log(NET__ERROR, _L "Tried to write a packet with an empty queue (%d is past next out %d)" __L, seq_send, NextOutSeq);
SeqEmpty=true;
continue;
}
/*if(CompareSequence(NextOutSeq, seq_send) == SeqFuture) {
_log(NET__ERROR, _L "Tried to write a packet beyond the end of the queue! (%d is past next out %d)" __L, seq_send, NextOutSeq);
sitr=SequencedQueue.end();
continue;
}*/
#ifdef RETRANSMITS
if (!RuleB(EQStream, RetransmitAckedPackets) && (*sitr)->acked) {
_log(NET__NET_TRACE, _L "Not retransmitting seq packet %d because already marked as acked" __L, seq_send);
sitr++;
NextSequencedSend++;
} else if (!p) {
#else
if (!p) {
#endif
// If we don't have a packet to try to combine into, use this one as the base
// Copy it first as it will still live until it is acked
p=(*sitr)->Copy();
_log(NET__NET_COMBINE, _L "Starting combined packet with seq packet %d of len %d" __L, seq_send, p->size);
sitr++;
NextSequencedSend++;
} else if (!p->combine(*sitr)) {
// Trying to combine this packet with the base didn't work (too big maybe)
// So just send the base packet (we'll try this packet again later)
_log(NET__NET_COMBINE, _L "Combined packet full at len %d, next seq packet %d is len %d" __L, p->size, seq_send, (*sitr)->size);
ReadyToSend.push(p);
BytesWritten+=p->size;
p=nullptr;
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
_log(NET__ERROR, _L "Pre-Send Seq NSS=%d Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, NextSequencedSend, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
if (BytesWritten > threshold) {
// Sent enough this round, lets stop to be fair
_log(NET__RATES, _L "Exceeded write threshold in seq (%d > %d)" __L, BytesWritten, threshold);
break;
if(NextSequencedSend > SequencedQueue.size()) {
_log(NET__ERROR, _L "Pre-Send Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size());
}
uint16 seq_send = SequencedBase + NextSequencedSend; //just for logging...
if(SequencedQueue.empty()) {
_log(NET__ERROR, _L "Tried to write a packet with an empty queue (%d is past next out %d)" __L, seq_send, NextOutSeq);
SeqEmpty=true;
continue;
}
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
if (!RETRANSMIT_ACKED_PACKETS && (*sitr)->acked) {
_log(NET__NET_TRACE, _L "Not retransmitting seq packet %d because already marked as acked" __L, seq_send);
sitr++;
NextSequencedSend++;
} else if (!p) {
// If we don't have a packet to try to combine into, use this one as the base
// Copy it first as it will still live until it is acked
p=(*sitr)->Copy();
_log(NET__NET_COMBINE, _L "Starting combined packet with seq packet %d of len %d" __L, seq_send, p->size);
sitr++;
NextSequencedSend++;
} else if (!p->combine(*sitr)) {
// Trying to combine this packet with the base didn't work (too big maybe)
// So just send the base packet (we'll try this packet again later)
_log(NET__NET_COMBINE, _L "Combined packet full at len %d, next seq packet %d is len %d" __L, p->size, seq_send, (*sitr)->size);
ReadyToSend.push(p);
BytesWritten+=p->size;
p=nullptr;
if (BytesWritten > threshold) {
// Sent enough this round, lets stop to be fair
_log(NET__RATES, _L "Exceeded write threshold in seq (%d > %d)" __L, BytesWritten, threshold);
break;
}
} else {
// Combine worked
_log(NET__NET_COMBINE, _L "Combined seq packet %d of len %d, yeilding %d combined." __L, seq_send, (*sitr)->size, p->size);
sitr++;
NextSequencedSend++;
}
} else {
// Combine worked
_log(NET__NET_COMBINE, _L "Combined seq packet %d of len %d, yeilding %d combined." __L, seq_send, (*sitr)->size, p->size);
sitr++;
NextSequencedSend++;
if (!p) {
// If we don't have a packet to try to combine into, use this one as the base
// Copy it first as it will still live until it is acked
p=(*sitr)->Copy();
_log(NET__NET_COMBINE, _L "Starting combined packet with seq packet %d of len %d" __L, seq_send, p->size);
sitr++;
NextSequencedSend++;
} else if (!p->combine(*sitr)) {
// Trying to combine this packet with the base didn't work (too big maybe)
// So just send the base packet (we'll try this packet again later)
_log(NET__NET_COMBINE, _L "Combined packet full at len %d, next seq packet %d is len %d" __L, p->size, seq_send, (*sitr)->size);
ReadyToSend.push(p);
BytesWritten+=p->size;
p=nullptr;
if (BytesWritten > threshold) {
// Sent enough this round, lets stop to be fair
_log(NET__RATES, _L "Exceeded write threshold in seq (%d > %d)" __L, BytesWritten, threshold);
break;
}
} else {
// Combine worked
_log(NET__NET_COMBINE, _L "Combined seq packet %d of len %d, yeilding %d combined." __L, seq_send, (*sitr)->size, p->size);
sitr++;
NextSequencedSend++;
}
}
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
_log(NET__ERROR, _L "Post send Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
if(NextSequencedSend > SequencedQueue.size()) {
_log(NET__ERROR, _L "Post send Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size());
}
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
_log(NET__ERROR, _L "Post send Invalid Sequenced queue: BS %d + SQ %d != NOS %d" __L, SequencedBase, SequencedQueue.size(), NextOutSeq);
}
if(NextSequencedSend > SequencedQueue.size()) {
_log(NET__ERROR, _L "Post send Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size());
}
} else {
// No more sequenced packets
SeqEmpty=true;
@ -1379,20 +1400,27 @@ void EQStream::Decay()
void EQStream::AdjustRates(uint32 average_delta)
{
#ifdef RETRANSMITS
if (average_delta && (average_delta <= RuleI(EQStream, AverageDeltaMax))) {
#else
if (average_delta) {
#endif
MRate.lock();
RateThreshold=RATEBASE/average_delta;
DecayRate=DECAYBASE/average_delta;
_log(NET__RATES, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L, RateThreshold, DecayRate, average_delta);
MRate.unlock();
#ifdef RETRANSMITS
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
if (average_delta && (average_delta <= AVERAGE_DELTA_MAX)) {
MRate.lock();
RateThreshold=RATEBASE/average_delta;
DecayRate=DECAYBASE/average_delta;
_log(NET__RATES, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L,
RateThreshold, DecayRate, average_delta);
MRate.unlock();
} else {
_log(NET__RATES, _L "Not adjusting data rate because avg delta over max (%d > %d)" __L,
average_delta, AVERAGE_DELTA_MAX);
}
} else {
_log(NET__RATES, _L "Not adjusting data rate because avg delta over max (%d > %d)" __L, average_delta, RuleI(EQStream, AverageDeltaMax));
#endif
if (average_delta) {
MRate.lock();
RateThreshold=RATEBASE/average_delta;
DecayRate=DECAYBASE/average_delta;
_log(NET__RATES, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L,
RateThreshold, DecayRate, average_delta);
MRate.unlock();
}
}
}

View File

@ -24,6 +24,11 @@
#define RATEBASE 1048576 // 1 MB
#define DECAYBASE 78642 // RATEBASE/10
#define RETRANSMIT_TIMEOUT_MULT 3.0
#define RETRANSMIT_TIMEOUT_MAX 5000
#define AVERAGE_DELTA_MAX 2500
#define RETRANSMIT_ACKED_PACKETS true
#pragma pack(1)
struct SessionRequest {
uint32 UnknownA;

View File

@ -499,13 +499,6 @@ RULE_CATEGORY( Console )
RULE_INT ( Console, SessionTimeOut, 600000 ) // Amount of time in ms for the console session to time out
RULE_CATEGORY_END()
RULE_CATEGORY( EQStream )
RULE_INT ( EQStream, RetransmitTimeoutMax, 5000 ) // maximum retransmit timeout before retransmitting unacked packets
RULE_INT ( EQStream, AverageDeltaMax, 2500 ) // maximum average rtt where we will still recalculate transmit rates
RULE_REAL ( EQStream, RetransmitTimeoutMult, 3.0 ) // multiplier applied to rtt stats to generate a retransmit timeout value
RULE_BOOL ( EQStream, RetransmitAckedPackets, true ) // should we restransmit packets that were already acked?
RULE_CATEGORY_END()
RULE_CATEGORY( QueryServ )
RULE_BOOL( QueryServ, PlayerChatLogging, false) // Logs Player Chat
RULE_BOOL( QueryServ, PlayerLogTrades, false) // Logs Player Trades

View File

@ -7114,13 +7114,13 @@ const char* Client::GetClassPlural(Client* client) {
void Client::SendWebLink(const char *website)
{
if(website != 0)
size_t len = strlen(website) + 1;
if(website != 0 && len > 1)
{
std::string str = website;
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weblink, sizeof(Weblink_Struct) + str.length() + 1);
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weblink, sizeof(Weblink_Struct) + len);
Weblink_Struct *wl = (Weblink_Struct*)outapp->pBuffer;
memcpy(wl->weblink, str.c_str(), str.length() + 1);
wl->weblink[str.length() + 1] = '\0';
memcpy(wl->weblink, website, len);
wl->weblink[len] = '\0';
FastQueuePacket(&outapp);
}

View File

@ -687,7 +687,6 @@ public:
inline uint8 GetBecomeNPCLevel() const { return npclevel; }
inline void SetBecomeNPC(bool flag) { npcflag = flag; }
inline void SetBecomeNPCLevel(uint8 level) { npclevel = level; }
bool LootToStack(uint32 itemid);
void SetFeigned(bool in_feigned);
/// this cures timing issues cuz dead animation isn't done but server side feigning is?
inline bool GetFeigned() const { return(feigned); }

View File

@ -1914,50 +1914,6 @@ uint32 Client::GetEquipmentColor(uint8 material_slot) const
return 0;
}
bool Client::LootToStack(uint32 itemid) { //Loots stackable items to existing stacks - Wiz
// @merth: Need to do loot code with new inventory struct
/*
const Item_Struct* item;
int i;
for (i=22; i<=29; i++) {
item = GetItemAt(i);
if (item) {
if (m_pp.invitemproperties[i].charges < 20 && item->ID == itemid)
{
m_pp.invitemproperties[i].charges += 1;
EQApplicationPacket* outapp = new EQApplicationPacket(OP_PlaceItem, sizeof(Item_Struct));
memcpy(outapp->pBuffer, item, outapp->size);
Item_Struct* outitem = (Item_Struct*) outapp->pBuffer;
outitem->equipSlot = i;
outitem->charges = m_pp.invitemproperties[i].charges;
QueuePacket(outapp);
safe_delete(outapp);
return true;
}
}
}
for (i=0; i<=pp_containerinv_size; i++) {
if (m_pp.containerinv[i] != 0xFFFF) {
item = database.GetItem(m_pp.containerinv[i]);
if (m_pp.bagitemproperties[i].charges < 20 && item->ID == itemid)
{
m_pp.bagitemproperties[i].charges += 1;
EQApplicationPacket* outapp = new EQApplicationPacket(OP_PlaceItem, sizeof(Item_Struct));
memcpy(outapp->pBuffer, item, outapp->size);
Item_Struct* outitem = (Item_Struct*) outapp->pBuffer;
outitem->equipSlot = 250+i;
outitem->charges = m_pp.bagitemproperties[i].charges;
QueuePacket(outapp);
safe_delete(outapp);
return true;
}
}
}
*/
return false;
}
// Send an item packet (including all subitems of the item)
void Client::SendItemPacket(int16 slot_id, const ItemInst* inst, ItemPacketType packet_type)
{

View File

@ -6,10 +6,25 @@
#include "masterentity.h"
#include "lua_client.h"
#include "../common/item.h"
struct InventoryWhere { };
luabind::scope lua_register_client() {
return luabind::class_<Lua_Client, Lua_Mob>("Client")
.def(luabind::constructor<>());
}
luabind::scope lua_register_inventory_where() {
return luabind::class_<InventoryWhere>("InventoryWhere")
.enum_("constants")
[
luabind::value("Personal", static_cast<int>(invWherePersonal)),
luabind::value("Bank", static_cast<int>(invWhereBank)),
luabind::value("SharedBank", static_cast<int>(invWhereSharedBank)),
luabind::value("Trading", static_cast<int>(invWhereTrading)),
luabind::value("Cursor", static_cast<int>(invWhereCursor))
];
}
#endif

View File

@ -11,6 +11,7 @@ namespace luabind {
}
luabind::scope lua_register_client();
luabind::scope lua_register_inventory_where();
class Lua_Client : public Lua_Mob
{
@ -39,206 +40,189 @@ public:
void Kick();
void Disconnect();
bool IsLD();
WorldKick
GetAnon
Duck
Stand
SetGM
SetPVP
GetPVP
GetGM
SetBaseClass
SetBaseRace
SetBaseGender
GetBaseFace
GetLanguageSkill
GetLastName
GetLDoNPointsTheme
GetBaseSTR
GetBaseSTA
GetBaseCHA
GetBaseDEX
GetBaseINT
GetBaseAGI
GetBaseWIS
GetWeight
GetEXP
GetAAExp
GetTotalSecondsPlayed
UpdateLDoNPoints
SetDeity
AddEXP
SetEXP
SetBindPoint
GetBindX
GetBindY
GetBindZ
GetBindHeading
GetBindZoneID
MovePC
MovePCInstance
ChangeLastName
GetFactionLevel
SetFactionLevel
SetFactionLevel2
GetRawItemAC
AccountID
AccountName
Admin
CharacterID
UpdateAdmin
UpdateWho
GuildRank
GuildID
GetFace
TakeMoneyFromPP
AddMoneyToPP
TGB
GetSkillPoints
SetSkillPoints
IncreaseSkill
IncreaseLanguageSkill
GetSkill
GetRawSkill
HasSkill
CanHaveSkill
SetSkill
AddSkill
CheckSpecializeIncrease
CheckIncreaseSkill
SetLanguageSkill
MaxSkill
GMKill
IsMedding
GetDuelTarget
IsDueling
SetDuelTarget
SetDueling
ResetAA
MemSpell
UnmemSpell
UnmemSpellAll
ScribeSpell
UnscribeSpell
UnscribeSpellAll
UntrainDisc
UntrainDiscAll
IsSitting
IsBecomeNPC
GetBecomeNPCLevel
SetBecomeNPC
SetBecomeNPCLevel
LootToStack
SetFeigned
GetFeigned
AutoSplitEnabled
SetHorseId
GetHorseId
NukeItem
SetTint
SetMaterial
Undye
GetItemIDAt
GetAugmentIDAt
DeleteItemInInventory
SummonItem
SetStats
IncStats
DropItem
BreakInvis
GetGroup
LeaveGroup
GetRaid
IsGrouped
IsRaidGrouped
Hungry
Thirsty
GetInstrumentMod
DecreaseByID
SlotConvert2
Escape
RemoveNoRent
GoFish
ForageItem
CalcPriceMod
ResetTrade
UseDiscipline
GetCharacterFactionLevel
SetZoneFlag
ClearZoneFlag
HasZoneFlag
SendZoneFlagInfo
LoadZoneFlags
SetAATitle
GetClientVersion
GetClientVersionBit
SetTitleSuffix
SetAAPoints
GetAAPoints
GetSpentAA
AddAAPoints
RefundAA
GetModCharacterFactionLevel
GetLDoNWins
GetLDoNLosses
GetLDoNWinsTheme
GetLDoNLossesTheme
GetItemAt
GetAugmentAt
GetStartZone
SetStartZone
KeyRingAdd
KeyRingCheck
AddPVPPoints
AddCrystals
GetPVPPoints
GetRadiantCrystals
GetEbonCrystals
ReadBook
UpdateGroupAAs
GetGroupPoints
GetRaidPoints
LearnRecipe
GetEndurance
GetMaxEndurance
GetEnduranceRatio
SetEndurance
SendOPTranslocateConfirm
NPCSpawn
GetIP
AddLevelBasedExp
IncrementAA
GetAALevel
MarkCompassLoc
ClearCompassMark
GetFreeSpellBookSlot
GetSpellBookSlotBySpellID
UpdateTaskActivity
AssignTask
FailTask
IsTaskCompleted
IsTaskActive
IsTaskActivityActive
GetCorpseCount
GetCorpseID
GetCorpseItemAt
AssignToInstance
Freeze
UnFreeze
GetAggroCount
GetCarriedMoney
GetAllMoney
GetItemInInventory
SetCustomItemData
GetCustomItemData
OpenLFGuildWindow
SignalClient
AddAlternateCurrencyValue
SendWebLink
GetInstanceID
HasSpellScribed
SetAccountFlag
GetAccountFlag
void WorldKick();
bool GetAnon();
void Duck();
void Stand();
void SetGM(bool v);
void SetPVP(bool v);
bool GetPVP();
bool GetGM();
void SetBaseClass(int v);
void SetBaseRace(int v);
void SetBaseGender(int v);
int GetBaseFace();
int GetLanguageSkill();
int GetLastName();
int GetLDoNPointsTheme();
int GetBaseSTR();
int GetBaseSTA();
int GetBaseCHA();
int GetBaseDEX();
int GetBaseINT();
int GetBaseAGI();
int GetBaseWIS();
int GetWeight();
uint32 GetEXP();
uint32 GetAAExp();
uint32 GetTotalSecondsPlayed();
void UpdateLDoNPoints(int points, uint32 theme);
void SetDeity(int v);
void AddEXP(uint32 add_exp, int conlevel = 255, bool resexp = false);
void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp = false);
SetBindPoint(int to_zone = -1, float new_x = 0.0f, float new_y = 0.0f, float new_z = 0.0f);
float GetBindX(int index = 0);
float GetBindY(int index = 0);
float GetBindZ(int index = 0);
float GetBindHeading(int index = 0);
uint32 GetBindZoneID(int index = 0);
void MovePC(int zone, float x, float y, float z, float heading);
void MovePCInstance(int zone, int instance, float x, float y, float z, float heading);
void ChangeLastName(const char *in);
int GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 race, uint32 class, uint32 deity, uint32 faction, Lua_NPC npc);
void SetFactionLevel(uint32 char_id, uint32 npc_id, int char_class, int char_race, int char_deity);
void SetFactionLevel2(uint32 char_id, int faction_id, int char_class, int char_race, int char_deity, int value, int temp);
int GetRawItemAC();
uint32 AccountID();
const char *AccountName();
bool Admin();
uint32 CharacterID();
int GuildRank();
uint32 GuildID();
int GetFace();
bool TakeMoneyFromPP(uint64 copper, bool update_client = false);
void AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, bool update_client = false);
bool TGB();
int GetSkillPoints();
void SetSkillPoints(int skill);
void IncreaseSkill(int skill_id, int value);
void IncreaseLanguageSkill(int skill_id, int value);
int GetRawSkill(int skill_id);
bool HasSkill(int skill_id);
bool CanHaveSkill(int skill_id);
void SetSkill(int skill_id, int value);
void AddSkill(int skill_id, int value);
void CheckSpecializeIncrease(int spell_id);
void CheckIncreaseSkill(int skill_id, Lua_Mob target, int chance_mod = 0);
void SetLanguageSkill(int language, int value);
int MaxSkill(int spell_id);
bool IsMedding();
Lua_Client GetDuelTarget();
bool IsDueling();
void SetDuelTarget(Lua_Client c);
void SetDueling(bool v);
void ResetAA();
void MemSpell(int spell_id, int slot, bool update_client = true);
void UnmemSpell(int slot, bool update_client = true);
void UnmemSpellAll(bool update_client = true);
void ScribeSpell(int spell_id, int slot, bool update_client = true);
void UnscribeSpell(int slot, bool update_client = true);
void UnscribeSpellAll(bool update_client = true);
void UntrainDisc(int slot, bool update_client = true);
void UntrainDiscAll(bool update_client = true);
bool IsSitting();
void SetFeigned(bool v);
bool GetFeigned();
bool AutoSplitEnabled();
void SetHorseId(int id);
int GetHorseId();
void NukeItem(uint32 item_num, int where_to_check);
void SetTint(int slot_id, uint32 color);
void SetMaterial(int slot_id, uint32 item_id);
void Undye(int slot_id);
int GetItemIDAt(int slot_id);
int GetAugmentIDAt(int slot_id, int aug_slot);
void DeleteItemInInventory(int slot_id, int quantity, bool update_client = true);
void SummonItem(uint32 item_id, int charges = 0, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0,
uint32 aug5 = 0, bool attuned = false, int to_slot = 30);
void SetStats(int type, int value);
void IncStats(int type, int value);
int DropItem(int slot_id);
void BreakInvis();
void LeaveGroup();
bool IsGrouped();
bool IsRaidGrouped();
bool Hungry();
bool Thirsty();
int GetInstrumentMod(int spell_id);
bool DecreaseByID(uint32 type, int amt);
void Escape();
void GoFish();
void ForageItem(bool guarantee = false);
float CalcPriceMod(Lua_Mob other, bool reverse);
void ResetTrade();
bool UseDiscipline(int spell_id, int target_id);
int GetCharacterFactionLevel(int faction_id);
void SetZoneFlag(int zone_id);
void ClearZoneFlag(int zone_id);
bool HasZoneFlag(int zone_id);
void SendZoneFlagInfo(Lua_Client to);
void SetAATitle(const char *title);
int GetClientVersion();
uint32 GetClientVersionBit();
void SetTitleSuffix(const char *text);
void SetAAPoints(int points);
int GetAAPoints();
int GetSpentAA();
void AddAAPoints(int points);
void RefundAA();
int GetModCharacterFactionLevel(int faction);
int GetLDoNWins();
int GetLDoNLosses();
int GetLDoNWinsTheme(int theme);
int GetLDoNLossesTheme(int theme);
Lua_ItemInst GetItemAt(int slot);
int GetStartZone();
void SetStartZone(int zone_id, float x = 0.0f, float y = 0.0f, float z = 0.0f);
void KeyRingAdd(uint32 item);
bool KeyRingCheck(uint32 item);
void AddPVPPoints(uint32 points);
void AddCrystals(uint32 radiant, uint32 ebon);
uint32 GetPVPPoints();
uint32 GetRadiantCrystals();
uint32 GetEbonCrystals();
void ReadBook(const char *text, int type);
void UpdateGroupAAs(int points, uint32 type);
uint32 GetGroupPoints();
uint32 GetRaidPoints();
void LearnRecipe(uint32 recipe);
int GetEndurance();
int GetMaxEndurance();
int GetEndurancePercent();
void SetEndurance(int endur);
void SendOPTranslocateConfirm(Lua_Mob caster, int spell_id);
const char *GetIP();
void AddLevelBasedExp(int exp_pct, int max_level = 0);
void IncrementAA(int aa);
MarkSingleCompassLoc(float in_x, float in_y, float in_z, int count = 1);
int GetFreeSpellBookSlot(int start = 0);
int GetSpellBookSlotBySpellID(int spell_id);
void UpdateTaskActivity(int task, int activity, int count);
void AssignTask(int task, int npc_id);
void FailTask(int task);
bool IsTaskCompleted(int task);
bool IsTaskActive(int task);
bool IsTaskActivityActive(int task, int activty);
int GetCorpseCount();
int GetCorpseID(int corpse);
int GetCorpseItemAt(int corpse, int slot);
void AssignToInstance(int instance_id);
void Freeze();
void UnFreeze();
int GetAggroCount();
uint64 GetCarriedMoney();
uint64 GetAllMoney();
void OpenLFGuildWindow();
void Signal(uint32 id);
void AddAlternateCurrencyValue(uint32 currency, int amount);
void SendWebLink(const char *site);
bool HasSpellScribed(int spell_id);
void SetAccountFlag(std::string flag, std::string val);
std::string value GetAccountFlag(std::string flag);
//unsup features
Lua_Group GetGroup();
Lua_Raid GetRaid();
*/
};

View File

@ -12,20 +12,6 @@ struct Lua_HateList;
class Lua_Item;
class Lua_ItemInst;
//TODO: Remove the error checking by a flag since this adds significant overhead to each c call
#define Lua_Safe_Call_Void() if(!d_) { return; } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Bool() if(!d_) { return false; } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Int() if(!d_) { return 0; } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Real() if(!d_) { return 0.0; } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_String() if(!d_) { return ""; } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Entity() if(!d_) { return Lua_Entity(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Mob() if(!d_) { return Lua_Mob(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_NPC() if(!d_) { return Lua_NPC(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Client() if(!d_) { return Lua_Client(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_HateList() if(!d_) { return Lua_HateList(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Item() if(!d_) { return Lua_Item(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_ItemInst() if(!d_) { return Lua_ItemInst(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
namespace luabind {
struct scope;
}

View File

@ -4,6 +4,10 @@
luabind::scope lua_register_general();
luabind::scope lua_register_events();
luabind::scope lua_register_faction();
luabind::scope lua_register_slot();
luabind::scope lua_register_material();
luabind::scope lua_register_client_version();
#endif
#endif

View File

@ -5,7 +5,6 @@
#include <luabind/object.hpp>
#include "masterentity.h"
#include "lua_entity.h"
#include "lua_item.h"
Lua_Item::Lua_Item(uint32 item_id) {

View File

@ -7,7 +7,6 @@
#include "masterentity.h"
#include "lua_iteminst.h"
#include "lua_item.h"
#include "lua_entity.h"
bool Lua_ItemInst::IsType(int item_class) {
Lua_Safe_Call_Bool();

View File

@ -1682,6 +1682,11 @@ int Lua_Mob::GetFlurryChance() {
return self->GetFlurryChance();
}
int Lua_Mob::GetSkill(int skill) {
Lua_Safe_Call_Int();
return self->GetSkill(static_cast<SkillType>(skill));
}
luabind::scope lua_register_mob() {
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
.def(luabind::constructor<>())
@ -1977,7 +1982,8 @@ luabind::scope lua_register_mob() {
.def("SetDisableMelee", (void(Lua_Mob::*)(bool))&Lua_Mob::SetDisableMelee)
.def("IsMeleeDisabled", (bool(Lua_Mob::*)(void))&Lua_Mob::IsMeleeDisabled)
.def("SetFlurryChance", (void(Lua_Mob::*)(int))&Lua_Mob::SetFlurryChance)
.def("GetFlurryChance", (int(Lua_Mob::*)(void))&Lua_Mob::GetFlurryChance);
.def("GetFlurryChance", (int(Lua_Mob::*)(void))&Lua_Mob::GetFlurryChance)
.def("GetSkill", (int(Lua_Mob::*)(int))&Lua_Mob::GetSkill);
}
#endif

View File

@ -336,6 +336,7 @@ public:
bool IsMeleeDisabled();
void SetFlurryChance(int value);
int GetFlurryChance();
int GetSkill(int skill_id);
};
#endif

View File

@ -806,6 +806,7 @@ void LuaParser::MapFunctions(lua_State *L) {
lua_register_mob(),
lua_register_npc(),
lua_register_client(),
lua_register_inventory_where(),
lua_register_iteminst(),
lua_register_item(),
lua_register_spell(),
@ -946,56 +947,8 @@ void LuaParser::ExportQGlobals(NPC *n, Client *c) {
return;
}
QGlobalCache *npc_c = nullptr;
QGlobalCache *char_c = nullptr;
QGlobalCache *zone_c = nullptr;
uint32 npc_id = 0;
uint32 char_id = 0;
uint32 zone_id = 0;
if(n) {
npc_id = n->GetNPCTypeID();
npc_c = n->GetQGlobals();
}
if(c) {
char_id = c->CharacterID();
char_c = c->GetQGlobals();
}
if(zone) {
zone_id = zone->GetZoneID();
zone_c = zone->GetQGlobals();
}
if(!npc_c && n) {
npc_c = n->CreateQGlobals();
npc_c->LoadByNPCID(npc_id);
}
if(!char_c && c) {
char_c = c->CreateQGlobals();
char_c->LoadByCharID(char_id);
}
if(!zone_c && zone) {
zone_c = zone->CreateQGlobals();
zone_c->LoadByZoneID(zone_id);
zone_c->LoadByGlobalContext();
}
std::list<QGlobal> global_map;
if(npc_c) {
QGlobalCache::Combine(global_map, npc_c->GetBucket(), npc_id, char_id, zone_id);
}
if(char_c) {
QGlobalCache::Combine(global_map, char_c->GetBucket(), npc_id, char_id, zone_id);
}
if(zone_c) {
QGlobalCache::Combine(global_map, zone_c->GetBucket(), npc_id, char_id, zone_id);
}
QGlobalCache::GetQGlobals(global_map, n, c, zone);
auto iter = global_map.begin();
while(iter != global_map.end()) {

View File

@ -2,6 +2,20 @@
#define EQEMU_LUA_PTR_H
#ifdef LUA_EQEMU
//TODO: Remove the error checking by a flag since this adds significant overhead to each c call
#define Lua_Safe_Call_Void() if(!d_) { return; } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Bool() if(!d_) { return false; } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Int() if(!d_) { return 0; } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Real() if(!d_) { return 0.0; } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_String() if(!d_) { return ""; } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Entity() if(!d_) { return Lua_Entity(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Mob() if(!d_) { return Lua_Mob(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_NPC() if(!d_) { return Lua_NPC(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Client() if(!d_) { return Lua_Client(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_HateList() if(!d_) { return Lua_HateList(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_Item() if(!d_) { return Lua_Item(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
#define Lua_Safe_Call_ItemInst() if(!d_) { return Lua_ItemInst(); } NativeType *self = reinterpret_cast<NativeType*>(d_)
template<typename T>
class Lua_Ptr
{

View File

@ -2713,33 +2713,6 @@ XS(XS_Client_SetBecomeNPCLevel)
XSRETURN_EMPTY;
}
XS(XS_Client_LootToStack); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_LootToStack)
{
dXSARGS;
if (items != 2)
Perl_croak(aTHX_ "Usage: Client::LootToStack(THIS, itemid)");
{
Client * THIS;
bool RETVAL;
uint32 itemid = (uint32)SvUV(ST(1));
if (sv_derived_from(ST(0), "Client")) {
IV tmp = SvIV((SV*)SvRV(ST(0)));
THIS = INT2PTR(Client *,tmp);
}
else
Perl_croak(aTHX_ "THIS is not of type Client");
if(THIS == nullptr)
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash.");
RETVAL = THIS->LootToStack(itemid);
ST(0) = boolSV(RETVAL);
sv_2mortal(ST(0));
}
XSRETURN(1);
}
XS(XS_Client_SetFeigned); /* prototype to pass -Wmissing-prototypes */
XS(XS_Client_SetFeigned)
{
@ -5854,7 +5827,6 @@ XS(boot_Client)
newXSproto(strcpy(buf, "GetBecomeNPCLevel"), XS_Client_GetBecomeNPCLevel, file, "$");
newXSproto(strcpy(buf, "SetBecomeNPC"), XS_Client_SetBecomeNPC, file, "$$");
newXSproto(strcpy(buf, "SetBecomeNPCLevel"), XS_Client_SetBecomeNPCLevel, file, "$$");
newXSproto(strcpy(buf, "LootToStack"), XS_Client_LootToStack, file, "$$");
newXSproto(strcpy(buf, "SetFeigned"), XS_Client_SetFeigned, file, "$$");
newXSproto(strcpy(buf, "GetFeigned"), XS_Client_GetFeigned, file, "$");
newXSproto(strcpy(buf, "AutoSplitEnabled"), XS_Client_AutoSplitEnabled, file, "$");