mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 01:11:29 +00:00
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:
parent
d25d8187b6
commit
79a9d2112a
@ -23,6 +23,7 @@
|
|||||||
#include "Mutex.h"
|
#include "Mutex.h"
|
||||||
#include "op_codes.h"
|
#include "op_codes.h"
|
||||||
#include "CRC16.h"
|
#include "CRC16.h"
|
||||||
|
#include "platform.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
@ -30,13 +31,6 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#if defined(ZONE) || defined(WORLD)
|
|
||||||
#define RETRANSMITS
|
|
||||||
#endif
|
|
||||||
#ifdef RETRANSMITS
|
|
||||||
#include "rulesys.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#else
|
#else
|
||||||
@ -75,17 +69,20 @@ void EQStream::init() {
|
|||||||
BytesWritten=0;
|
BytesWritten=0;
|
||||||
SequencedBase = 0;
|
SequencedBase = 0;
|
||||||
NextSequencedSend = 0;
|
NextSequencedSend = 0;
|
||||||
#ifdef RETRANSMITS
|
|
||||||
retransmittimer = Timer::GetCurrentTime();
|
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
|
||||||
retransmittimeout = 500 * RuleR(EQStream, RetransmitTimeoutMult); //use 500ms as base before we have connection stats
|
retransmittimer = Timer::GetCurrentTime();
|
||||||
#endif
|
retransmittimeout = 500 * RETRANSMIT_TIMEOUT_MULT;
|
||||||
|
}
|
||||||
|
|
||||||
OpMgr = nullptr;
|
OpMgr = nullptr;
|
||||||
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
|
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);
|
_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(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)
|
EQRawApplicationPacket *EQStream::MakeApplicationPacket(EQProtocolPacket *p)
|
||||||
@ -118,7 +115,7 @@ EQProtocolPacket *EQStream::MakeProtocolPacket(const unsigned char *buf, uint32
|
|||||||
|
|
||||||
void EQStream::ProcessPacket(EQProtocolPacket *p)
|
void EQStream::ProcessPacket(EQProtocolPacket *p)
|
||||||
{
|
{
|
||||||
uint32 processed=0,subpacket_length=0;
|
uint32 processed=0, subpacket_length=0;
|
||||||
if (p == nullptr)
|
if (p == nullptr)
|
||||||
return;
|
return;
|
||||||
// Raw Application packet
|
// Raw Application packet
|
||||||
@ -304,9 +301,10 @@ uint32 processed=0,subpacket_length=0;
|
|||||||
#ifndef COLLECTOR
|
#ifndef COLLECTOR
|
||||||
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
|
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
|
||||||
AckPackets(seq);
|
AckPackets(seq);
|
||||||
#ifdef RETRANSMITS
|
|
||||||
retransmittimer = Timer::GetCurrentTime();
|
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
|
||||||
#endif
|
retransmittimer = Timer::GetCurrentTime();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -409,19 +407,24 @@ uint32 processed=0,subpacket_length=0;
|
|||||||
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
|
uint16 seq=ntohs(*(uint16 *)(p->pBuffer));
|
||||||
MOutboundQueue.lock();
|
MOutboundQueue.lock();
|
||||||
|
|
||||||
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
|
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);
|
_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(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 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) {
|
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,
|
_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);
|
seq, SequencedBase, SequencedBase+NextSequencedSend);
|
||||||
#ifdef RETRANSMITS
|
|
||||||
if (!RuleB(EQStream, RetransmitAckedPackets)) {
|
bool retransmit_acked_packets = false;
|
||||||
#endif
|
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
|
||||||
|
retransmit_acked_packets = RETRANSMIT_ACKED_PACKETS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!retransmit_acked_packets) {
|
||||||
uint16 sqsize = SequencedQueue.size();
|
uint16 sqsize = SequencedQueue.size();
|
||||||
uint16 index = seq - SequencedBase;
|
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);
|
_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 += index;
|
||||||
(*sitr)->acked = true;
|
(*sitr)->acked = true;
|
||||||
}
|
}
|
||||||
#ifdef RETRANSMITS
|
|
||||||
}
|
}
|
||||||
if (RuleR(EQStream, RetransmitTimeoutMult)) { // only choose new behavior if multiplier is set
|
|
||||||
|
if(RETRANSMIT_TIMEOUT_MULT) {
|
||||||
retransmittimer = Timer::GetCurrentTime();
|
retransmittimer = Timer::GetCurrentTime();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
NextSequencedSend = 0;
|
NextSequencedSend = 0;
|
||||||
} else {
|
} else {
|
||||||
_log(NET__NET_TRACE, _L "Received OP_OutOfOrderAck for out-of-window %d. Window (%d->%d)." __L, seq, SequencedBase, NextOutSeq);
|
_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(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(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();
|
MOutboundQueue.unlock();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -468,19 +473,21 @@ if(NextSequencedSend > SequencedQueue.size()) {
|
|||||||
Stats->packets_sent=x;
|
Stats->packets_sent=x;
|
||||||
NonSequencedPush(new EQProtocolPacket(OP_SessionStatResponse,p->pBuffer,p->size));
|
NonSequencedPush(new EQProtocolPacket(OP_SessionStatResponse,p->pBuffer,p->size));
|
||||||
AdjustRates(ntohl(Stats->average_delta));
|
AdjustRates(ntohl(Stats->average_delta));
|
||||||
#ifdef RETRANSMITS
|
|
||||||
if (RuleR(EQStream, RetransmitTimeoutMult) && ntohl(Stats->average_delta)) {
|
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
|
||||||
//recalculate retransmittimeout using the larger of the last rtt or average rtt, which is multiplied by the rule value
|
if(RETRANSMIT_TIMEOUT_MULT && ntohl(Stats->average_delta)) {
|
||||||
if((ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta)) > (ntohl(Stats->average_delta) * 2)) {
|
//recalculate retransmittimeout using the larger of the last rtt or average rtt, which is multiplied by the rule value
|
||||||
retransmittimeout = (ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta)) * RuleR(EQStream, RetransmitTimeoutMult);
|
if((ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta)) > (ntohl(Stats->average_delta) * 2)) {
|
||||||
} else {
|
retransmittimeout = (ntohl(Stats->last_local_delta) + ntohl(Stats->last_remote_delta))
|
||||||
retransmittimeout = ntohl(Stats->average_delta) * 2 * RuleR(EQStream, RetransmitTimeoutMult);
|
* 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
|
#endif
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -527,16 +534,6 @@ void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req)
|
|||||||
|
|
||||||
uint16 opcode = (*OpMgr)->EmuToEQ(pack->emu_opcode);
|
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);
|
_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) {
|
if (!ack_req) {
|
||||||
@ -549,8 +546,8 @@ void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req)
|
|||||||
|
|
||||||
void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
|
void EQStream::SendPacket(uint16 opcode, EQApplicationPacket *p)
|
||||||
{
|
{
|
||||||
uint32 chunksize,used;
|
uint32 chunksize,used;
|
||||||
uint32 length;
|
uint32 length;
|
||||||
|
|
||||||
// Convert the EQApplicationPacket to 1 or more EQProtocolPackets
|
// Convert the EQApplicationPacket to 1 or more EQProtocolPackets
|
||||||
if (p->size>(MaxLen-8)) { // proto-op(2), seq(2), app-op(2) ... data ... crc(2)
|
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)
|
void EQStream::Write(int eq_fd)
|
||||||
{
|
{
|
||||||
std::queue<EQProtocolPacket *> ReadyToSend;
|
std::queue<EQProtocolPacket *> ReadyToSend;
|
||||||
bool SeqEmpty=false,NonSeqEmpty=false;
|
bool SeqEmpty=false, NonSeqEmpty=false;
|
||||||
std::deque<EQProtocolPacket *>::iterator sitr;
|
std::deque<EQProtocolPacket *>::iterator sitr;
|
||||||
|
|
||||||
// Check our rate to make sure we can send more
|
// Check our rate to make sure we can send more
|
||||||
MRate.lock();
|
MRate.lock();
|
||||||
@ -673,14 +670,16 @@ std::deque<EQProtocolPacket *>::iterator sitr;
|
|||||||
// Place to hold the base packet t combine into
|
// Place to hold the base packet t combine into
|
||||||
EQProtocolPacket *p=nullptr;
|
EQProtocolPacket *p=nullptr;
|
||||||
|
|
||||||
#ifdef RETRANSMITS
|
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 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())) {
|
if (RETRANSMIT_TIMEOUT_MULT && !SequencedQueue.empty() && NextSequencedSend &&
|
||||||
_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);
|
(GetState()==ESTABLISHED) && ((retransmittimer+retransmittimeout) < Timer::GetCurrentTime())) {
|
||||||
NextSequencedSend = 0;
|
_log(NET__NET_TRACE, _L "Timeout since last ack received, starting retransmit at the start of our unacked "
|
||||||
retransmittimer = Timer::GetCurrentTime(); // don't want to endlessly retransmit the first packet
|
"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"
|
// Find the next sequenced packet to send from the "queue"
|
||||||
sitr = SequencedQueue.begin();
|
sitr = SequencedQueue.begin();
|
||||||
@ -723,65 +722,87 @@ std::deque<EQProtocolPacket *>::iterator sitr;
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sitr!=SequencedQueue.end()) {
|
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,
|
if(uint16(SequencedBase + SequencedQueue.size()) != NextOutSeq) {
|
||||||
// SequencedQueue.size(), SequencedBase, NextSequencedSend, NonSequencedQueue.size());
|
_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(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 (BytesWritten > threshold) {
|
if(NextSequencedSend > SequencedQueue.size()) {
|
||||||
// Sent enough this round, lets stop to be fair
|
_log(NET__ERROR, _L "Pre-Send Next Send Sequence is beyond the end of the queue NSS %d > SQ %d" __L, NextSequencedSend, SequencedQueue.size());
|
||||||
_log(NET__RATES, _L "Exceeded write threshold in seq (%d > %d)" __L, BytesWritten, threshold);
|
}
|
||||||
break;
|
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 {
|
} else {
|
||||||
// Combine worked
|
if (!p) {
|
||||||
_log(NET__NET_COMBINE, _L "Combined seq packet %d of len %d, yeilding %d combined." __L, seq_send, (*sitr)->size, p->size);
|
// If we don't have a packet to try to combine into, use this one as the base
|
||||||
sitr++;
|
// Copy it first as it will still live until it is acked
|
||||||
NextSequencedSend++;
|
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 {
|
} else {
|
||||||
// No more sequenced packets
|
// No more sequenced packets
|
||||||
SeqEmpty=true;
|
SeqEmpty=true;
|
||||||
@ -1379,20 +1400,27 @@ void EQStream::Decay()
|
|||||||
|
|
||||||
void EQStream::AdjustRates(uint32 average_delta)
|
void EQStream::AdjustRates(uint32 average_delta)
|
||||||
{
|
{
|
||||||
#ifdef RETRANSMITS
|
if(GetExecutablePlatform() == ExePlatformWorld || GetExecutablePlatform() == ExePlatformZone) {
|
||||||
if (average_delta && (average_delta <= RuleI(EQStream, AverageDeltaMax))) {
|
if (average_delta && (average_delta <= AVERAGE_DELTA_MAX)) {
|
||||||
#else
|
MRate.lock();
|
||||||
if (average_delta) {
|
RateThreshold=RATEBASE/average_delta;
|
||||||
#endif
|
DecayRate=DECAYBASE/average_delta;
|
||||||
MRate.lock();
|
_log(NET__RATES, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L,
|
||||||
RateThreshold=RATEBASE/average_delta;
|
RateThreshold, DecayRate, average_delta);
|
||||||
DecayRate=DECAYBASE/average_delta;
|
MRate.unlock();
|
||||||
_log(NET__RATES, _L "Adjusting data rate to thresh %d, decay %d based on avg delta %d" __L, RateThreshold, DecayRate, average_delta);
|
} else {
|
||||||
MRate.unlock();
|
_log(NET__RATES, _L "Not adjusting data rate because avg delta over max (%d > %d)" __L,
|
||||||
#ifdef RETRANSMITS
|
average_delta, AVERAGE_DELTA_MAX);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
_log(NET__RATES, _L "Not adjusting data rate because avg delta over max (%d > %d)" __L, average_delta, RuleI(EQStream, AverageDeltaMax));
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,11 @@
|
|||||||
#define RATEBASE 1048576 // 1 MB
|
#define RATEBASE 1048576 // 1 MB
|
||||||
#define DECAYBASE 78642 // RATEBASE/10
|
#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)
|
#pragma pack(1)
|
||||||
struct SessionRequest {
|
struct SessionRequest {
|
||||||
uint32 UnknownA;
|
uint32 UnknownA;
|
||||||
|
|||||||
@ -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_INT ( Console, SessionTimeOut, 600000 ) // Amount of time in ms for the console session to time out
|
||||||
RULE_CATEGORY_END()
|
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_CATEGORY( QueryServ )
|
||||||
RULE_BOOL( QueryServ, PlayerChatLogging, false) // Logs Player Chat
|
RULE_BOOL( QueryServ, PlayerChatLogging, false) // Logs Player Chat
|
||||||
RULE_BOOL( QueryServ, PlayerLogTrades, false) // Logs Player Trades
|
RULE_BOOL( QueryServ, PlayerLogTrades, false) // Logs Player Trades
|
||||||
|
|||||||
@ -7114,13 +7114,13 @@ const char* Client::GetClassPlural(Client* client) {
|
|||||||
|
|
||||||
void Client::SendWebLink(const char *website)
|
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) + len);
|
||||||
EQApplicationPacket* outapp = new EQApplicationPacket(OP_Weblink, sizeof(Weblink_Struct) + str.length() + 1);
|
|
||||||
Weblink_Struct *wl = (Weblink_Struct*)outapp->pBuffer;
|
Weblink_Struct *wl = (Weblink_Struct*)outapp->pBuffer;
|
||||||
memcpy(wl->weblink, str.c_str(), str.length() + 1);
|
memcpy(wl->weblink, website, len);
|
||||||
wl->weblink[str.length() + 1] = '\0';
|
wl->weblink[len] = '\0';
|
||||||
|
|
||||||
FastQueuePacket(&outapp);
|
FastQueuePacket(&outapp);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -687,7 +687,6 @@ public:
|
|||||||
inline uint8 GetBecomeNPCLevel() const { return npclevel; }
|
inline uint8 GetBecomeNPCLevel() const { return npclevel; }
|
||||||
inline void SetBecomeNPC(bool flag) { npcflag = flag; }
|
inline void SetBecomeNPC(bool flag) { npcflag = flag; }
|
||||||
inline void SetBecomeNPCLevel(uint8 level) { npclevel = level; }
|
inline void SetBecomeNPCLevel(uint8 level) { npclevel = level; }
|
||||||
bool LootToStack(uint32 itemid);
|
|
||||||
void SetFeigned(bool in_feigned);
|
void SetFeigned(bool in_feigned);
|
||||||
/// this cures timing issues cuz dead animation isn't done but server side feigning is?
|
/// this cures timing issues cuz dead animation isn't done but server side feigning is?
|
||||||
inline bool GetFeigned() const { return(feigned); }
|
inline bool GetFeigned() const { return(feigned); }
|
||||||
|
|||||||
@ -1914,50 +1914,6 @@ uint32 Client::GetEquipmentColor(uint8 material_slot) const
|
|||||||
return 0;
|
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)
|
// Send an item packet (including all subitems of the item)
|
||||||
void Client::SendItemPacket(int16 slot_id, const ItemInst* inst, ItemPacketType packet_type)
|
void Client::SendItemPacket(int16 slot_id, const ItemInst* inst, ItemPacketType packet_type)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -6,10 +6,25 @@
|
|||||||
|
|
||||||
#include "masterentity.h"
|
#include "masterentity.h"
|
||||||
#include "lua_client.h"
|
#include "lua_client.h"
|
||||||
|
#include "../common/item.h"
|
||||||
|
|
||||||
|
struct InventoryWhere { };
|
||||||
|
|
||||||
luabind::scope lua_register_client() {
|
luabind::scope lua_register_client() {
|
||||||
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
return luabind::class_<Lua_Client, Lua_Mob>("Client")
|
||||||
.def(luabind::constructor<>());
|
.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
|
#endif
|
||||||
|
|||||||
@ -11,6 +11,7 @@ namespace luabind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
luabind::scope lua_register_client();
|
luabind::scope lua_register_client();
|
||||||
|
luabind::scope lua_register_inventory_where();
|
||||||
|
|
||||||
class Lua_Client : public Lua_Mob
|
class Lua_Client : public Lua_Mob
|
||||||
{
|
{
|
||||||
@ -39,206 +40,189 @@ public:
|
|||||||
void Kick();
|
void Kick();
|
||||||
void Disconnect();
|
void Disconnect();
|
||||||
bool IsLD();
|
bool IsLD();
|
||||||
WorldKick
|
void WorldKick();
|
||||||
GetAnon
|
bool GetAnon();
|
||||||
Duck
|
void Duck();
|
||||||
Stand
|
void Stand();
|
||||||
SetGM
|
void SetGM(bool v);
|
||||||
SetPVP
|
void SetPVP(bool v);
|
||||||
GetPVP
|
bool GetPVP();
|
||||||
GetGM
|
bool GetGM();
|
||||||
SetBaseClass
|
void SetBaseClass(int v);
|
||||||
SetBaseRace
|
void SetBaseRace(int v);
|
||||||
SetBaseGender
|
void SetBaseGender(int v);
|
||||||
GetBaseFace
|
int GetBaseFace();
|
||||||
GetLanguageSkill
|
int GetLanguageSkill();
|
||||||
GetLastName
|
int GetLastName();
|
||||||
GetLDoNPointsTheme
|
int GetLDoNPointsTheme();
|
||||||
GetBaseSTR
|
int GetBaseSTR();
|
||||||
GetBaseSTA
|
int GetBaseSTA();
|
||||||
GetBaseCHA
|
int GetBaseCHA();
|
||||||
GetBaseDEX
|
int GetBaseDEX();
|
||||||
GetBaseINT
|
int GetBaseINT();
|
||||||
GetBaseAGI
|
int GetBaseAGI();
|
||||||
GetBaseWIS
|
int GetBaseWIS();
|
||||||
GetWeight
|
int GetWeight();
|
||||||
GetEXP
|
uint32 GetEXP();
|
||||||
GetAAExp
|
uint32 GetAAExp();
|
||||||
GetTotalSecondsPlayed
|
uint32 GetTotalSecondsPlayed();
|
||||||
UpdateLDoNPoints
|
void UpdateLDoNPoints(int points, uint32 theme);
|
||||||
SetDeity
|
void SetDeity(int v);
|
||||||
AddEXP
|
void AddEXP(uint32 add_exp, int conlevel = 255, bool resexp = false);
|
||||||
SetEXP
|
void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp = false);
|
||||||
SetBindPoint
|
SetBindPoint(int to_zone = -1, float new_x = 0.0f, float new_y = 0.0f, float new_z = 0.0f);
|
||||||
GetBindX
|
float GetBindX(int index = 0);
|
||||||
GetBindY
|
float GetBindY(int index = 0);
|
||||||
GetBindZ
|
float GetBindZ(int index = 0);
|
||||||
GetBindHeading
|
float GetBindHeading(int index = 0);
|
||||||
GetBindZoneID
|
uint32 GetBindZoneID(int index = 0);
|
||||||
MovePC
|
void MovePC(int zone, float x, float y, float z, float heading);
|
||||||
MovePCInstance
|
void MovePCInstance(int zone, int instance, float x, float y, float z, float heading);
|
||||||
ChangeLastName
|
void ChangeLastName(const char *in);
|
||||||
GetFactionLevel
|
int GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 race, uint32 class, uint32 deity, uint32 faction, Lua_NPC npc);
|
||||||
SetFactionLevel
|
void SetFactionLevel(uint32 char_id, uint32 npc_id, int char_class, int char_race, int char_deity);
|
||||||
SetFactionLevel2
|
void SetFactionLevel2(uint32 char_id, int faction_id, int char_class, int char_race, int char_deity, int value, int temp);
|
||||||
GetRawItemAC
|
int GetRawItemAC();
|
||||||
AccountID
|
uint32 AccountID();
|
||||||
AccountName
|
const char *AccountName();
|
||||||
Admin
|
bool Admin();
|
||||||
CharacterID
|
uint32 CharacterID();
|
||||||
UpdateAdmin
|
int GuildRank();
|
||||||
UpdateWho
|
uint32 GuildID();
|
||||||
GuildRank
|
int GetFace();
|
||||||
GuildID
|
bool TakeMoneyFromPP(uint64 copper, bool update_client = false);
|
||||||
GetFace
|
void AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 platinum, bool update_client = false);
|
||||||
TakeMoneyFromPP
|
bool TGB();
|
||||||
AddMoneyToPP
|
int GetSkillPoints();
|
||||||
TGB
|
void SetSkillPoints(int skill);
|
||||||
GetSkillPoints
|
void IncreaseSkill(int skill_id, int value);
|
||||||
SetSkillPoints
|
void IncreaseLanguageSkill(int skill_id, int value);
|
||||||
IncreaseSkill
|
int GetRawSkill(int skill_id);
|
||||||
IncreaseLanguageSkill
|
bool HasSkill(int skill_id);
|
||||||
GetSkill
|
bool CanHaveSkill(int skill_id);
|
||||||
GetRawSkill
|
void SetSkill(int skill_id, int value);
|
||||||
HasSkill
|
void AddSkill(int skill_id, int value);
|
||||||
CanHaveSkill
|
void CheckSpecializeIncrease(int spell_id);
|
||||||
SetSkill
|
void CheckIncreaseSkill(int skill_id, Lua_Mob target, int chance_mod = 0);
|
||||||
AddSkill
|
void SetLanguageSkill(int language, int value);
|
||||||
CheckSpecializeIncrease
|
int MaxSkill(int spell_id);
|
||||||
CheckIncreaseSkill
|
bool IsMedding();
|
||||||
SetLanguageSkill
|
Lua_Client GetDuelTarget();
|
||||||
MaxSkill
|
bool IsDueling();
|
||||||
GMKill
|
void SetDuelTarget(Lua_Client c);
|
||||||
IsMedding
|
void SetDueling(bool v);
|
||||||
GetDuelTarget
|
void ResetAA();
|
||||||
IsDueling
|
void MemSpell(int spell_id, int slot, bool update_client = true);
|
||||||
SetDuelTarget
|
void UnmemSpell(int slot, bool update_client = true);
|
||||||
SetDueling
|
void UnmemSpellAll(bool update_client = true);
|
||||||
ResetAA
|
void ScribeSpell(int spell_id, int slot, bool update_client = true);
|
||||||
MemSpell
|
void UnscribeSpell(int slot, bool update_client = true);
|
||||||
UnmemSpell
|
void UnscribeSpellAll(bool update_client = true);
|
||||||
UnmemSpellAll
|
void UntrainDisc(int slot, bool update_client = true);
|
||||||
ScribeSpell
|
void UntrainDiscAll(bool update_client = true);
|
||||||
UnscribeSpell
|
bool IsSitting();
|
||||||
UnscribeSpellAll
|
void SetFeigned(bool v);
|
||||||
UntrainDisc
|
bool GetFeigned();
|
||||||
UntrainDiscAll
|
bool AutoSplitEnabled();
|
||||||
IsSitting
|
void SetHorseId(int id);
|
||||||
IsBecomeNPC
|
int GetHorseId();
|
||||||
GetBecomeNPCLevel
|
void NukeItem(uint32 item_num, int where_to_check);
|
||||||
SetBecomeNPC
|
void SetTint(int slot_id, uint32 color);
|
||||||
SetBecomeNPCLevel
|
void SetMaterial(int slot_id, uint32 item_id);
|
||||||
LootToStack
|
void Undye(int slot_id);
|
||||||
SetFeigned
|
int GetItemIDAt(int slot_id);
|
||||||
GetFeigned
|
int GetAugmentIDAt(int slot_id, int aug_slot);
|
||||||
AutoSplitEnabled
|
void DeleteItemInInventory(int slot_id, int quantity, bool update_client = true);
|
||||||
SetHorseId
|
void SummonItem(uint32 item_id, int charges = 0, uint32 aug1 = 0, uint32 aug2 = 0, uint32 aug3 = 0, uint32 aug4 = 0,
|
||||||
GetHorseId
|
uint32 aug5 = 0, bool attuned = false, int to_slot = 30);
|
||||||
NukeItem
|
void SetStats(int type, int value);
|
||||||
SetTint
|
void IncStats(int type, int value);
|
||||||
SetMaterial
|
int DropItem(int slot_id);
|
||||||
Undye
|
void BreakInvis();
|
||||||
GetItemIDAt
|
void LeaveGroup();
|
||||||
GetAugmentIDAt
|
bool IsGrouped();
|
||||||
DeleteItemInInventory
|
bool IsRaidGrouped();
|
||||||
SummonItem
|
bool Hungry();
|
||||||
SetStats
|
bool Thirsty();
|
||||||
IncStats
|
int GetInstrumentMod(int spell_id);
|
||||||
DropItem
|
bool DecreaseByID(uint32 type, int amt);
|
||||||
BreakInvis
|
void Escape();
|
||||||
GetGroup
|
void GoFish();
|
||||||
LeaveGroup
|
void ForageItem(bool guarantee = false);
|
||||||
GetRaid
|
float CalcPriceMod(Lua_Mob other, bool reverse);
|
||||||
IsGrouped
|
void ResetTrade();
|
||||||
IsRaidGrouped
|
bool UseDiscipline(int spell_id, int target_id);
|
||||||
Hungry
|
int GetCharacterFactionLevel(int faction_id);
|
||||||
Thirsty
|
void SetZoneFlag(int zone_id);
|
||||||
GetInstrumentMod
|
void ClearZoneFlag(int zone_id);
|
||||||
DecreaseByID
|
bool HasZoneFlag(int zone_id);
|
||||||
SlotConvert2
|
void SendZoneFlagInfo(Lua_Client to);
|
||||||
Escape
|
void SetAATitle(const char *title);
|
||||||
RemoveNoRent
|
int GetClientVersion();
|
||||||
GoFish
|
uint32 GetClientVersionBit();
|
||||||
ForageItem
|
void SetTitleSuffix(const char *text);
|
||||||
CalcPriceMod
|
void SetAAPoints(int points);
|
||||||
ResetTrade
|
int GetAAPoints();
|
||||||
UseDiscipline
|
int GetSpentAA();
|
||||||
GetCharacterFactionLevel
|
void AddAAPoints(int points);
|
||||||
SetZoneFlag
|
void RefundAA();
|
||||||
ClearZoneFlag
|
int GetModCharacterFactionLevel(int faction);
|
||||||
HasZoneFlag
|
int GetLDoNWins();
|
||||||
SendZoneFlagInfo
|
int GetLDoNLosses();
|
||||||
LoadZoneFlags
|
int GetLDoNWinsTheme(int theme);
|
||||||
SetAATitle
|
int GetLDoNLossesTheme(int theme);
|
||||||
GetClientVersion
|
Lua_ItemInst GetItemAt(int slot);
|
||||||
GetClientVersionBit
|
int GetStartZone();
|
||||||
SetTitleSuffix
|
void SetStartZone(int zone_id, float x = 0.0f, float y = 0.0f, float z = 0.0f);
|
||||||
SetAAPoints
|
void KeyRingAdd(uint32 item);
|
||||||
GetAAPoints
|
bool KeyRingCheck(uint32 item);
|
||||||
GetSpentAA
|
void AddPVPPoints(uint32 points);
|
||||||
AddAAPoints
|
void AddCrystals(uint32 radiant, uint32 ebon);
|
||||||
RefundAA
|
uint32 GetPVPPoints();
|
||||||
GetModCharacterFactionLevel
|
uint32 GetRadiantCrystals();
|
||||||
GetLDoNWins
|
uint32 GetEbonCrystals();
|
||||||
GetLDoNLosses
|
void ReadBook(const char *text, int type);
|
||||||
GetLDoNWinsTheme
|
void UpdateGroupAAs(int points, uint32 type);
|
||||||
GetLDoNLossesTheme
|
uint32 GetGroupPoints();
|
||||||
GetItemAt
|
uint32 GetRaidPoints();
|
||||||
GetAugmentAt
|
void LearnRecipe(uint32 recipe);
|
||||||
GetStartZone
|
int GetEndurance();
|
||||||
SetStartZone
|
int GetMaxEndurance();
|
||||||
KeyRingAdd
|
int GetEndurancePercent();
|
||||||
KeyRingCheck
|
void SetEndurance(int endur);
|
||||||
AddPVPPoints
|
void SendOPTranslocateConfirm(Lua_Mob caster, int spell_id);
|
||||||
AddCrystals
|
const char *GetIP();
|
||||||
GetPVPPoints
|
void AddLevelBasedExp(int exp_pct, int max_level = 0);
|
||||||
GetRadiantCrystals
|
void IncrementAA(int aa);
|
||||||
GetEbonCrystals
|
MarkSingleCompassLoc(float in_x, float in_y, float in_z, int count = 1);
|
||||||
ReadBook
|
int GetFreeSpellBookSlot(int start = 0);
|
||||||
UpdateGroupAAs
|
int GetSpellBookSlotBySpellID(int spell_id);
|
||||||
GetGroupPoints
|
void UpdateTaskActivity(int task, int activity, int count);
|
||||||
GetRaidPoints
|
void AssignTask(int task, int npc_id);
|
||||||
LearnRecipe
|
void FailTask(int task);
|
||||||
GetEndurance
|
bool IsTaskCompleted(int task);
|
||||||
GetMaxEndurance
|
bool IsTaskActive(int task);
|
||||||
GetEnduranceRatio
|
bool IsTaskActivityActive(int task, int activty);
|
||||||
SetEndurance
|
int GetCorpseCount();
|
||||||
SendOPTranslocateConfirm
|
int GetCorpseID(int corpse);
|
||||||
NPCSpawn
|
int GetCorpseItemAt(int corpse, int slot);
|
||||||
GetIP
|
void AssignToInstance(int instance_id);
|
||||||
AddLevelBasedExp
|
void Freeze();
|
||||||
IncrementAA
|
void UnFreeze();
|
||||||
GetAALevel
|
int GetAggroCount();
|
||||||
MarkCompassLoc
|
uint64 GetCarriedMoney();
|
||||||
ClearCompassMark
|
uint64 GetAllMoney();
|
||||||
GetFreeSpellBookSlot
|
void OpenLFGuildWindow();
|
||||||
GetSpellBookSlotBySpellID
|
void Signal(uint32 id);
|
||||||
UpdateTaskActivity
|
void AddAlternateCurrencyValue(uint32 currency, int amount);
|
||||||
AssignTask
|
void SendWebLink(const char *site);
|
||||||
FailTask
|
bool HasSpellScribed(int spell_id);
|
||||||
IsTaskCompleted
|
void SetAccountFlag(std::string flag, std::string val);
|
||||||
IsTaskActive
|
std::string value GetAccountFlag(std::string flag);
|
||||||
IsTaskActivityActive
|
|
||||||
GetCorpseCount
|
//unsup features
|
||||||
GetCorpseID
|
Lua_Group GetGroup();
|
||||||
GetCorpseItemAt
|
Lua_Raid GetRaid();
|
||||||
AssignToInstance
|
|
||||||
Freeze
|
|
||||||
UnFreeze
|
|
||||||
GetAggroCount
|
|
||||||
GetCarriedMoney
|
|
||||||
GetAllMoney
|
|
||||||
GetItemInInventory
|
|
||||||
SetCustomItemData
|
|
||||||
GetCustomItemData
|
|
||||||
OpenLFGuildWindow
|
|
||||||
SignalClient
|
|
||||||
AddAlternateCurrencyValue
|
|
||||||
SendWebLink
|
|
||||||
GetInstanceID
|
|
||||||
HasSpellScribed
|
|
||||||
SetAccountFlag
|
|
||||||
GetAccountFlag
|
|
||||||
*/
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -12,20 +12,6 @@ struct Lua_HateList;
|
|||||||
class Lua_Item;
|
class Lua_Item;
|
||||||
class Lua_ItemInst;
|
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 {
|
namespace luabind {
|
||||||
struct scope;
|
struct scope;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,10 @@
|
|||||||
|
|
||||||
luabind::scope lua_register_general();
|
luabind::scope lua_register_general();
|
||||||
luabind::scope lua_register_events();
|
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
|
||||||
#endif
|
#endif
|
||||||
@ -5,7 +5,6 @@
|
|||||||
#include <luabind/object.hpp>
|
#include <luabind/object.hpp>
|
||||||
|
|
||||||
#include "masterentity.h"
|
#include "masterentity.h"
|
||||||
#include "lua_entity.h"
|
|
||||||
#include "lua_item.h"
|
#include "lua_item.h"
|
||||||
|
|
||||||
Lua_Item::Lua_Item(uint32 item_id) {
|
Lua_Item::Lua_Item(uint32 item_id) {
|
||||||
|
|||||||
@ -7,7 +7,6 @@
|
|||||||
#include "masterentity.h"
|
#include "masterentity.h"
|
||||||
#include "lua_iteminst.h"
|
#include "lua_iteminst.h"
|
||||||
#include "lua_item.h"
|
#include "lua_item.h"
|
||||||
#include "lua_entity.h"
|
|
||||||
|
|
||||||
bool Lua_ItemInst::IsType(int item_class) {
|
bool Lua_ItemInst::IsType(int item_class) {
|
||||||
Lua_Safe_Call_Bool();
|
Lua_Safe_Call_Bool();
|
||||||
|
|||||||
@ -1682,6 +1682,11 @@ int Lua_Mob::GetFlurryChance() {
|
|||||||
return self->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() {
|
luabind::scope lua_register_mob() {
|
||||||
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
|
return luabind::class_<Lua_Mob, Lua_Entity>("Mob")
|
||||||
.def(luabind::constructor<>())
|
.def(luabind::constructor<>())
|
||||||
@ -1977,7 +1982,8 @@ luabind::scope lua_register_mob() {
|
|||||||
.def("SetDisableMelee", (void(Lua_Mob::*)(bool))&Lua_Mob::SetDisableMelee)
|
.def("SetDisableMelee", (void(Lua_Mob::*)(bool))&Lua_Mob::SetDisableMelee)
|
||||||
.def("IsMeleeDisabled", (bool(Lua_Mob::*)(void))&Lua_Mob::IsMeleeDisabled)
|
.def("IsMeleeDisabled", (bool(Lua_Mob::*)(void))&Lua_Mob::IsMeleeDisabled)
|
||||||
.def("SetFlurryChance", (void(Lua_Mob::*)(int))&Lua_Mob::SetFlurryChance)
|
.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
|
#endif
|
||||||
|
|||||||
@ -336,6 +336,7 @@ public:
|
|||||||
bool IsMeleeDisabled();
|
bool IsMeleeDisabled();
|
||||||
void SetFlurryChance(int value);
|
void SetFlurryChance(int value);
|
||||||
int GetFlurryChance();
|
int GetFlurryChance();
|
||||||
|
int GetSkill(int skill_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -806,6 +806,7 @@ void LuaParser::MapFunctions(lua_State *L) {
|
|||||||
lua_register_mob(),
|
lua_register_mob(),
|
||||||
lua_register_npc(),
|
lua_register_npc(),
|
||||||
lua_register_client(),
|
lua_register_client(),
|
||||||
|
lua_register_inventory_where(),
|
||||||
lua_register_iteminst(),
|
lua_register_iteminst(),
|
||||||
lua_register_item(),
|
lua_register_item(),
|
||||||
lua_register_spell(),
|
lua_register_spell(),
|
||||||
@ -946,56 +947,8 @@ void LuaParser::ExportQGlobals(NPC *n, Client *c) {
|
|||||||
return;
|
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;
|
std::list<QGlobal> global_map;
|
||||||
if(npc_c) {
|
QGlobalCache::GetQGlobals(global_map, n, c, zone);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto iter = global_map.begin();
|
auto iter = global_map.begin();
|
||||||
while(iter != global_map.end()) {
|
while(iter != global_map.end()) {
|
||||||
|
|||||||
@ -2,6 +2,20 @@
|
|||||||
#define EQEMU_LUA_PTR_H
|
#define EQEMU_LUA_PTR_H
|
||||||
#ifdef LUA_EQEMU
|
#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>
|
template<typename T>
|
||||||
class Lua_Ptr
|
class Lua_Ptr
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2713,33 +2713,6 @@ XS(XS_Client_SetBecomeNPCLevel)
|
|||||||
XSRETURN_EMPTY;
|
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); /* prototype to pass -Wmissing-prototypes */
|
||||||
XS(XS_Client_SetFeigned)
|
XS(XS_Client_SetFeigned)
|
||||||
{
|
{
|
||||||
@ -5854,7 +5827,6 @@ XS(boot_Client)
|
|||||||
newXSproto(strcpy(buf, "GetBecomeNPCLevel"), XS_Client_GetBecomeNPCLevel, file, "$");
|
newXSproto(strcpy(buf, "GetBecomeNPCLevel"), XS_Client_GetBecomeNPCLevel, file, "$");
|
||||||
newXSproto(strcpy(buf, "SetBecomeNPC"), XS_Client_SetBecomeNPC, file, "$$");
|
newXSproto(strcpy(buf, "SetBecomeNPC"), XS_Client_SetBecomeNPC, file, "$$");
|
||||||
newXSproto(strcpy(buf, "SetBecomeNPCLevel"), XS_Client_SetBecomeNPCLevel, 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, "SetFeigned"), XS_Client_SetFeigned, file, "$$");
|
||||||
newXSproto(strcpy(buf, "GetFeigned"), XS_Client_GetFeigned, file, "$");
|
newXSproto(strcpy(buf, "GetFeigned"), XS_Client_GetFeigned, file, "$");
|
||||||
newXSproto(strcpy(buf, "AutoSplitEnabled"), XS_Client_AutoSplitEnabled, file, "$");
|
newXSproto(strcpy(buf, "AutoSplitEnabled"), XS_Client_AutoSplitEnabled, file, "$");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user