mirror of
https://github.com/therealKyp/Earth-and-Beyond-server
synced 2026-08-13 22:23:03 -04:00
1056 lines
27 KiB
C++
1056 lines
27 KiB
C++
// SectorManager.cpp
|
|
//
|
|
// Used by the Sector Server to manage a single sector
|
|
//
|
|
|
|
#include "Net7.h"
|
|
#include "SectorManager.h"
|
|
#include "Opcodes.h"
|
|
#include "PacketStructures.h"
|
|
#include "Connection.h"
|
|
#include "TcpListener.h"
|
|
#include "ServerManager.h"
|
|
#include "ItemBase.h"
|
|
#include "SectorData.h"
|
|
#include "MemoryHandler.h"
|
|
#include "ObjectManager.h"
|
|
#include "UDPConnection.h"
|
|
#include <float.h>
|
|
|
|
// There is one instance of this class for each sector
|
|
|
|
SectorManager::SectorManager(ServerManager *server_mgr)
|
|
{
|
|
m_ServerMgr = server_mgr;
|
|
m_SectorData = NULL;
|
|
m_SectorConnection = NULL;
|
|
m_SectorID = -1;
|
|
m_TcpPort = -1;
|
|
m_IsSectorServerReady = false;
|
|
m_EffectID = 0; // Set effect ID to start at 0
|
|
m_ShutDownMark = 0;
|
|
|
|
m_LongTermTimeNodes.clear();
|
|
|
|
//need to start up a timer thread
|
|
m_SectorThreadRunning = false;
|
|
m_MemoryMgr = new MemoryHandler(BROADCAST_SLOTS);
|
|
//m_MemoryMgr->InitializeMemory(BROADCAST_SLOTS); //NB slots can be expanded if the sector is busy
|
|
memset(m_EventSlotHead, 0, sizeof(m_EventSlotHead));
|
|
m_EventSlotIndex = 0;
|
|
m_Greetings = (0);
|
|
m_ObjectMgr = (0);
|
|
|
|
memset(m_PlayerList, 0, sizeof(m_PlayerList));
|
|
m_PlayerCount = 0;
|
|
}
|
|
|
|
SectorManager::~SectorManager()
|
|
{
|
|
m_MemoryMgr->~MemoryHandler();
|
|
}
|
|
|
|
long SectorManager::GetSectorNextObjID()
|
|
{
|
|
return (m_ObjectMgr->GetAvailableSectorID());
|
|
}
|
|
|
|
void SectorManager::SetBoundaries(int sector)
|
|
{
|
|
if (!m_SectorData)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_xmax = m_SectorData->m_xmax + 10000.0f;
|
|
m_xmin = m_SectorData->m_xmin - 10000.0f;
|
|
m_ymax = m_SectorData->m_ymax + 10000.0f;
|
|
m_ymin = m_SectorData->m_ymin - 10000.0f;
|
|
|
|
m_xctr = (m_xmax + m_xmin)/2;
|
|
m_yctr = (m_ymax + m_ymin)/2;
|
|
|
|
LogMessage("Sector: %d. X: %.2f Y: %.2f\n", sector, m_xmax-m_xmin, m_ymax-m_ymin);
|
|
}
|
|
|
|
long SectorManager::GetSectorID()
|
|
{
|
|
return m_SectorID;
|
|
}
|
|
|
|
short SectorManager::GetTcpPort()
|
|
{
|
|
return m_TcpPort;
|
|
}
|
|
|
|
bool SectorManager::IsSectorServerReady()
|
|
{
|
|
return m_IsSectorServerReady;
|
|
}
|
|
|
|
void SectorManager::SetSectorServerReady(bool ready)
|
|
{
|
|
m_IsSectorServerReady = ready;
|
|
}
|
|
|
|
// This must be called for each instance of the sector manager
|
|
void SectorManager::StartListener(short port)
|
|
{
|
|
m_TcpPort = port;
|
|
m_SectorConnection = new UDP_Connection(port, m_ServerMgr, CONNECTION_TYPE_SECTOR_SERVER_TO_PROXY);;
|
|
}
|
|
|
|
bool SectorManager::SetupSectorServer(long sector_id)
|
|
{
|
|
bool success = true;
|
|
m_SectorID = sector_id;
|
|
|
|
if (sector_id < 9999)
|
|
{
|
|
m_SectorData = g_ServerMgr->m_SectorContent.GetSectorData(sector_id);
|
|
}
|
|
else
|
|
{
|
|
m_SectorData = g_ServerMgr->m_SectorContent.GetSectorData(sector_id/10);
|
|
}
|
|
|
|
if (!m_SectorData)
|
|
{
|
|
LogMessage("SetupSectorServer sector_id=%d failed\n", sector_id);
|
|
success = false;
|
|
}
|
|
else
|
|
{
|
|
m_SectorName = m_SectorData->name;
|
|
m_SystemName = m_SectorData->system_name;
|
|
m_SystemID = m_SectorData->system_id;
|
|
m_ObjectMgr = m_SectorData->obj_manager;
|
|
m_ParentSectorName = m_SectorData->system_name;
|
|
if (sector_id < 9999)
|
|
{
|
|
m_ObjectMgr->SetSectorManager(this); //now we have a link to the sector manager via object manager
|
|
m_ObjectMgr->InitialiseResourceContent();
|
|
}
|
|
else
|
|
{
|
|
StationTemplate *station = g_ServerMgr->m_StationMgr.GetStation(sector_id);
|
|
m_ParentSectorName = 0;
|
|
if (station)
|
|
{
|
|
if (station->WelcomeMessage) m_Greetings = station->WelcomeMessage;
|
|
SectorData *parent_sector = g_ServerMgr->m_SectorContent.GetSectorData(sector_id / 10);
|
|
if (parent_sector)
|
|
{
|
|
m_ParentSectorName = parent_sector->name;
|
|
m_SystemName = parent_sector->system_name;
|
|
}
|
|
m_SectorName = station->Name;
|
|
}
|
|
else
|
|
{
|
|
LogMessage("data for station id %d seems to be missing\n", sector_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Timed calls for manufacturing/refining need to be mad from within stations
|
|
#ifdef WIN32
|
|
_beginthread(&RunEventThreadAPI, 0, this);
|
|
#else
|
|
pthread_create(&m_SectorManagerThreadHandle, NULL, RunEventThreadAPI, (void *) this);
|
|
#endif
|
|
|
|
return (success);
|
|
}
|
|
|
|
Object *SectorManager::GetObject(long object_id)
|
|
{
|
|
return (m_ObjectMgr->GetObjectFromID(object_id));
|
|
}
|
|
|
|
Object *SectorManager::GetObject(char *object_name) //NB object_name must be in string manager
|
|
{
|
|
return (m_ObjectMgr->GetObjectFromName(object_name));
|
|
}
|
|
|
|
ServerParameters *SectorManager::GetSectorParams()
|
|
{
|
|
return (&m_SectorData->server_params);
|
|
}
|
|
|
|
void SectorManager::SendServerParameters(Player *player)
|
|
{
|
|
ServerParameters parameters;
|
|
memset(¶meters, 0, sizeof(parameters));
|
|
|
|
parameters.ZBandMin = m_SectorData->server_params.ZBandMin;
|
|
parameters.ZBandMax = m_SectorData->server_params.ZBandMax;
|
|
parameters.XMin = m_SectorData->server_params.XMin;
|
|
parameters.YMin = m_SectorData->server_params.YMin;
|
|
parameters.XMax = m_SectorData->server_params.XMax;
|
|
parameters.YMax = m_SectorData->server_params.YMax;
|
|
|
|
parameters.FogNear = m_SectorData->server_params.FogNear;
|
|
parameters.FogFar = m_SectorData->server_params.FogFar;
|
|
parameters.DebrisMode = m_SectorData->server_params.DebrisMode;
|
|
parameters.LightBackdrop = m_SectorData->server_params.LightBackdrop; //false;
|
|
parameters.FogBackdrop = m_SectorData->server_params.FogBackdrop;
|
|
parameters.SwapBackdrop = m_SectorData->server_params.SwapBackdrop;
|
|
parameters.BackdropFogNear = m_SectorData->server_params.BackdropFogNear;// 0.0;
|
|
parameters.BackdropFogFar = m_SectorData->server_params.BackdropFogFar;// 0.0;
|
|
parameters.MaxTilt = m_SectorData->server_params.MaxTilt;
|
|
parameters.AutoLevel = m_SectorData->server_params.AutoLevel;
|
|
parameters.ImpulseRate = m_SectorData->server_params.ImpulseRate;
|
|
parameters.DecayVelocity = 9.33033f;
|
|
parameters.DecaySpin = 9.33033f;
|
|
parameters.SectorNum = m_SectorID;
|
|
parameters.BackdropBaseAsset = m_SectorData->server_params.BackdropBaseAsset;
|
|
|
|
player->SendOpcode(ENB_OPCODE_0042_SERVER_PARAMETERS, (unsigned char *) ¶meters, sizeof(parameters));
|
|
}
|
|
|
|
void SectorManager::HandleSectorLogin2(Player *player)
|
|
{
|
|
if (m_SectorID > 9999)
|
|
{
|
|
StationLogin2(player);
|
|
}
|
|
else
|
|
{
|
|
SectorLogin2(player);
|
|
}
|
|
|
|
if (!player->ToBeRemoved())
|
|
{
|
|
AddPlayerToSectorList(player);
|
|
}
|
|
|
|
player->SetLoginStage(0);
|
|
}
|
|
|
|
bool SectorManager::HandleSectorLogin(Player *player)
|
|
{
|
|
if (m_SectorID > 9999)
|
|
{
|
|
StationLogin(player);
|
|
}
|
|
else
|
|
{
|
|
SectorLogin(player);
|
|
}
|
|
|
|
player->SetLoginStage(2);
|
|
|
|
return true;
|
|
}
|
|
|
|
void SectorManager::SectorLogin(Player *player)
|
|
{
|
|
long GameID = player->GameID();
|
|
|
|
player->SendGalaxyMap(m_SystemName, m_SectorName, "");
|
|
player->SetManufactureID(0);
|
|
|
|
player->SendClientType(m_SectorData->sector_type);
|
|
|
|
player->PlayerIndex()->SetSectorName(m_SectorName);
|
|
player->PlayerIndex()->SetSectorNum(m_SectorID);
|
|
player->SendPlayerInfo();
|
|
|
|
/*player->SendLoginShipData();
|
|
|
|
int SpeedFactor = (m_SectorData->sector_type == ST_SPACE) ? 1 : 2;
|
|
player->SendShipInfo(GameID, SpeedFactor);
|
|
|
|
//player->SendDataFileToClient("ServerParameters.dat");
|
|
SendServerParameters(player);
|
|
|
|
// Send Navs
|
|
if (m_SectorData)
|
|
{
|
|
m_ObjectMgr->SendAllNavs(player);
|
|
}
|
|
else
|
|
{
|
|
player->SendDataFileToClient("EarthSector.dat");
|
|
player->SendDataFileToClient("EarthSectorObjects.dat");
|
|
}
|
|
|
|
player->SendVaMessage("We have entered %s Sector (%s System).", m_SectorName, m_SystemName);
|
|
|
|
player->SendStart(player->CharacterID());*/
|
|
}
|
|
|
|
void SectorManager::SectorLogin2(Player *player)
|
|
{
|
|
long GameID = player->GameID();
|
|
|
|
player->SendLoginShipData();
|
|
|
|
int SpeedFactor = (m_SectorData->sector_type == ST_SPACE) ? 1 : 2;
|
|
player->SendShipInfo(GameID, SpeedFactor);
|
|
|
|
//player->SendDataFileToClient("ServerParameters.dat");
|
|
SendServerParameters(player);
|
|
|
|
// Send Navs
|
|
if (m_SectorData)
|
|
{
|
|
m_ObjectMgr->SendAllNavs(player);
|
|
}
|
|
else
|
|
{
|
|
player->SendDataFileToClient("EarthSector.dat");
|
|
player->SendDataFileToClient("EarthSectorObjects.dat");
|
|
}
|
|
|
|
player->SendVaMessage("We have entered %s Sector (%s System).", m_SectorName, m_SystemName);
|
|
|
|
player->SendStart(player->CharacterID());
|
|
}
|
|
|
|
void SectorManager::AddPlayerToSectorList(Player *player)
|
|
{
|
|
PlayerList::iterator itrPList;
|
|
bool found = false;
|
|
|
|
m_Mutex.Lock();
|
|
u32 player_num = player->GameID() & 0x0000FFFF;
|
|
|
|
if (!GetIndex(player_num))
|
|
{
|
|
SetIndex(player_num);
|
|
m_PlayerCount++;
|
|
}
|
|
|
|
m_Mutex.Unlock();
|
|
}
|
|
|
|
//only do this at the end of each sector processing cycle.
|
|
void SectorManager::RemovePlayerFromSectorList(Player *player)
|
|
{
|
|
m_Mutex.Lock();
|
|
u32 player_num = player->GameID() & 0x0000FFFF;
|
|
|
|
//see if it's set
|
|
if (GetIndex(player_num))
|
|
{
|
|
UnSetIndex(player_num);
|
|
m_PlayerCount--;
|
|
}
|
|
|
|
m_Mutex.Unlock();
|
|
}
|
|
|
|
//object index methods
|
|
void SectorManager::SetIndex(u32 index)
|
|
{
|
|
u32 *entry = (u32*) (m_PlayerList + (index/(sizeof(u32)*8)));
|
|
|
|
//now set the specific bit
|
|
*entry |= (1 << index%32);
|
|
}
|
|
|
|
void SectorManager::UnSetIndex(u32 index)
|
|
{
|
|
u32 *entry = (u32*) (m_PlayerList + (index/(sizeof(u32)*8)));
|
|
|
|
//now unset the specific bit
|
|
*entry &= (0xFFFFFFFF ^ (1 << index%32));
|
|
}
|
|
|
|
bool SectorManager::GetIndex(u32 index)
|
|
{
|
|
u32 *entry = (u32*) (m_PlayerList + (index/(sizeof(u32)*8)));
|
|
|
|
//now get the specific bit
|
|
if (*entry & (1 << index%32))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
u32* SectorManager::GetSectorPlayerList()
|
|
{
|
|
return m_PlayerList;
|
|
}
|
|
|
|
void SectorManager::StationLogin(Player *player)
|
|
{
|
|
long GameID = player->GameID();
|
|
long ManuID = player->ManuID();
|
|
|
|
//LogMessage("Station Login: %d %s\n", m_SectorID, m_SectorName);
|
|
|
|
//player->SendGalaxyMap(m_SystemName, m_ParentSectorName, m_SectorName);
|
|
|
|
// TODO: Send ClientChatEvent packet for the 'local' channel
|
|
|
|
// This is the manufacturing lab
|
|
player->ManuIndex()->SetGameID(ManuID);
|
|
player->ManuIndex()->TerminalReset(0);
|
|
|
|
player->SetManufactureID(ntohl(ManuID));
|
|
player->SetInSpace(false);
|
|
|
|
player->SendCreate(ManuID, 1.0, -1, CREATE_MANU_LAB);
|
|
player->SendRelationship(ManuID, RELATIONSHIP_FRIENDLY, false);
|
|
player->SendConstantPositionalUpdate(ManuID, 0, 0, 0);
|
|
player->SendAuxManu(true);
|
|
|
|
// Repair ship if needed
|
|
if (player->ShipIndex()->GetMaxHullPoints() != player->ShipIndex()->GetHullPoints())
|
|
{
|
|
player->ShipIndex()->SetHullPoints(player->ShipIndex()->GetMaxHullPoints());
|
|
}
|
|
|
|
player->PlayerIndex()->SetSectorName(m_SectorName);
|
|
player->PlayerIndex()->SetSectorNum(m_SectorID);
|
|
player->SendPlayerInfo();
|
|
|
|
player->SendLoginShipData();
|
|
|
|
// TODO: send ClientChatEvent to enable the station channel
|
|
|
|
// TODO: send ClientChatList to show which friends are online
|
|
}
|
|
|
|
void SectorManager::StationLogin2(Player *player)
|
|
{
|
|
long GameID = player->GameID();
|
|
|
|
player->SendShipInfo(GameID, 1);
|
|
|
|
player->SendMessageString(m_Greetings);
|
|
player->SendStarbaseSet(0, 0);
|
|
|
|
char lounge_npc[MAX_PATH];
|
|
long lounge_npc_id = player->TryLoungeFile(m_SectorID);
|
|
sprintf(lounge_npc, "LoungeNPC_%ld.dat", lounge_npc_id);
|
|
|
|
if (!player->SendLoungeNPC(m_SectorID))
|
|
{ // if we cant find it in MySQL load from file
|
|
LogMessage("Can't load from MySQL Loading from file (%d)\n", m_SectorID);
|
|
player->SendDataFileToClient(lounge_npc);
|
|
}
|
|
|
|
player->SendStart(player->CharacterID());
|
|
|
|
// TODO: send ClientChatEvent to enable the station channel
|
|
|
|
// TODO: send ClientChatList to show which friends are online
|
|
}
|
|
|
|
void SectorManager::LaunchIntoSpace(Player *player)
|
|
{
|
|
char launch_msg[256];
|
|
player->SendStarbaseSet(1, 0);
|
|
player->SetManufactureID(0);
|
|
if (g_ServerMgr->m_StationMgr.GetStation(m_SectorID))
|
|
{
|
|
sprintf(launch_msg, "This is %s control... you are cleared for departure.", g_ServerMgr->m_StationMgr.GetStation(m_SectorID)->Name);
|
|
player->SendMessageString(launch_msg);
|
|
}
|
|
|
|
// TODO: ClientChatEvent to cancel the station channel
|
|
long to_sector_id = m_SectorID / 10;
|
|
if (m_SectorID < 9999) to_sector_id = m_SectorID;
|
|
m_ServerMgr->m_PlayerMgr.DropPlayerFromSector(player);
|
|
player->PlayerIndex()->SetSectorNum(to_sector_id);
|
|
player->SendServerHandoff(m_SectorID, to_sector_id, m_SectorName, "", m_ParentSectorName, m_SystemName);
|
|
}
|
|
|
|
void SectorManager::SectorServerHandoff(Player *player, int new_sector_id)
|
|
{
|
|
char from_sector[128];
|
|
char *to_sector = g_ServerMgr->GetSectorName(new_sector_id);
|
|
char *to_system = g_ServerMgr->GetSystemName(new_sector_id);
|
|
player->SetActive(false);
|
|
sprintf(from_sector, "%s (%s System)", m_SectorName, m_SystemName);
|
|
m_ServerMgr->m_PlayerMgr.DropPlayerFromSector(player);
|
|
player->PlayerIndex()->SetSectorNum(new_sector_id);
|
|
player->SendServerHandoff(m_SectorID, new_sector_id, from_sector, m_SystemName, to_sector, to_system);
|
|
}
|
|
|
|
void SectorManager::Dock(Player *player, long target)
|
|
{
|
|
//cancel warp
|
|
player->TerminateWarp(true);
|
|
Object * obj = GetObject(target);
|
|
//LogMessage("Player requested docking at %s\n", obj->Name());
|
|
|
|
long destination = obj->Destination();
|
|
if (destination < 900)
|
|
{
|
|
player->SendVaMessage("Station has no destination set - Please add station destination in DASE.");
|
|
return;
|
|
}
|
|
if (!m_ServerMgr->GetSectorManager(destination))
|
|
{
|
|
player->SendVaMessage("Station is offline, no access permitted.");
|
|
return;
|
|
}
|
|
|
|
//TODO: add field to Station DB for docking message, use that here
|
|
char dock_message[128];
|
|
|
|
_snprintf(dock_message,128,"%s CONTROL: Docking clearance granted.", obj->Name());
|
|
|
|
player->SendMessageString(dock_message);
|
|
|
|
player->SendCameraControl(0x05000000, ntohl(target));
|
|
|
|
player->SetVelocity(100.0f);
|
|
player->SendContrailsRL(true);
|
|
|
|
player->LogDockCoords();
|
|
}
|
|
|
|
void SectorManager::GateActivate(Player *player, long target)
|
|
{
|
|
Gate(player, target);
|
|
}
|
|
|
|
void SectorManager::Gate(Player *player, long target)
|
|
{
|
|
// Initiate Gating
|
|
//LogMessage("Player requested Gate\n");
|
|
|
|
// determine the destination
|
|
Object *gate = m_ObjectMgr->GetObjectFromID(target);
|
|
player->SetStargateDestination(gate->Destination());
|
|
|
|
if (gate->Destination() == 0)
|
|
{
|
|
player->SendVaMessage("Gate Malfunction. Destination coordinates unsafe.");
|
|
return;
|
|
}
|
|
|
|
if (!m_ServerMgr->GetSectorManager(gate->Destination()))
|
|
{
|
|
LogMessage("SECTOR OFFLINE. Gate Inoperative.\n");
|
|
player->SendVaMessage("Destination sector is offline. Gate inoperative.");
|
|
return;
|
|
}
|
|
|
|
if (gate->Destination() < 900 || gate->Destination() > 5000)
|
|
{
|
|
LogMessage("Stargate '%s' has invalid destination: %d\n", gate->Name(), gate->Destination());
|
|
player->SetStargateDestination(1060); //something's gone wrong, send player to earth sector
|
|
}
|
|
|
|
player->OpenStargate(target);
|
|
player->SendClientSound("sfx_generic_gate_thrust 1",0,0);
|
|
player->SendContrailsRL(true);
|
|
player->MoveToward(gate, 20.0f);
|
|
|
|
//LogMessage("GATE HANDOFF SEQUENCE COMPLETE\n");
|
|
//add timer to gate cam operation
|
|
AddTimedCall(player, B_CAMERA_CONTROL, 5800, 0, 0x04000000, ntohl(gate->GameID()) );
|
|
}
|
|
|
|
char * SectorManager::GetSystemName(long sector_id)
|
|
{
|
|
char *server_name = "Unknown";
|
|
SectorData *p = g_ServerMgr->m_SectorContent.GetSectorData(sector_id);
|
|
if (p)
|
|
{
|
|
server_name = p->system_name;
|
|
}
|
|
return (server_name);
|
|
}
|
|
|
|
char *SectorManager::GetSectorName(long sector_id)
|
|
{
|
|
char *sector_name = "Unknown";
|
|
SectorData *p = g_ServerMgr->m_SectorContent.GetSectorData(sector_id);
|
|
if (p)
|
|
{
|
|
sector_name = p->name;
|
|
}
|
|
|
|
return (sector_name);
|
|
}
|
|
|
|
long SectorManager::GetSectorIDFromName(char *sector_name)
|
|
{
|
|
long sector_id = 0;
|
|
//loop through all the sectors
|
|
SectorData *p = g_ServerMgr->m_SectorContent.GetSectorData(sector_name);
|
|
if (p)
|
|
{
|
|
sector_id = p->sector_id;
|
|
}
|
|
|
|
return (sector_id);
|
|
}
|
|
|
|
//given a pointer to an array of bits and an index into them, return true if the bit is set
|
|
bool SectorManager::GetBitEntry(long *bit_array, long index)
|
|
{
|
|
long *entry = (long*) (bit_array + (index/(sizeof(long)*8)));
|
|
|
|
//now get the specific bit
|
|
if (*entry & (1 << index%32))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//given a pointer to an array of bits and an index into them, return true if the bit is set
|
|
void SectorManager::SetBitEntry(long *bit_array, long index)
|
|
{
|
|
long *entry = (long*) (bit_array + (index/(sizeof(long)*8)));
|
|
|
|
//now set the specific bit
|
|
*entry |= (1 << index%32);
|
|
}
|
|
|
|
void SectorManager::UnsetBitEntry(long *bit_array, long index)
|
|
{
|
|
long *entry = (long*) (bit_array + (index/(sizeof(long)*8)));
|
|
|
|
//now unset the specific bit
|
|
*entry &= (0xFFFFFFFF ^ (1 << index%32));
|
|
}
|
|
|
|
void SectorManager::RechargeReactor(Player *player)
|
|
{
|
|
player->RechargeReactor();
|
|
}
|
|
|
|
void SectorManager::RechargeShield(Player *player)
|
|
{
|
|
player->RechargeShield();
|
|
}
|
|
|
|
void SectorManager::ForceLogout(Player *player)
|
|
{
|
|
player->ForceLogout();
|
|
}
|
|
|
|
void SectorManager::BuffTimeout(Player *player)
|
|
{
|
|
// TODO: This needs to be reworked
|
|
|
|
/*
|
|
if (player->connection)
|
|
{
|
|
for(int x=0;x<16;x++)
|
|
{
|
|
// Remove expired buffs
|
|
if (player->player->m_AuxShip.m_BuffArray.Buffs[x].BuffRemovalTime < (signed) GetNet7TickCount()
|
|
&& !player->player->m_AuxShip.m_BuffArray.Buffs[x].IsPermanent)
|
|
{
|
|
// Remove effect
|
|
//player->player->SendResponse(ENB_OPCODE_000F_REMOVE_EFFECT, (unsigned char *)&player->player->m_AuxShip.m_BuffArray.Buffs[x].Elements[0].Magnitude, sizeof(int));
|
|
// Send to sector to remove effect
|
|
m_ServerMgr->m_PlayerMgr.SendToSector(player, ENB_OPCODE_000F_REMOVE_EFFECT,
|
|
(unsigned char *)&player->player->m_AuxShip.m_BuffArray.Buffs[x].Elements[0].Magnitude, sizeof(int));
|
|
// Remove buff from memory
|
|
memset(&player->player->m_AuxShip.m_BuffArray.Buffs[x],0,sizeof(player->player->m_AuxShip.m_BuffArray.Buffs[x]));
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
#define SECTOR_THREAD_INTERVAL 100
|
|
void SectorManager::RunSectorEventThread()
|
|
{
|
|
m_SectorThreadRunning = true;
|
|
unsigned long current_tick;
|
|
long sleep_time;
|
|
unsigned long check_tick = m_SectorID;
|
|
ObjectList stations;
|
|
ObjectList::iterator itrOList;
|
|
|
|
if (m_ObjectMgr == (0)) return;
|
|
|
|
ObjectList * mob_list;
|
|
long mob_index = 0;
|
|
|
|
//TODO: don't need an object manager for stations, but we do need an event thread.
|
|
|
|
if (m_SectorID < 9999)
|
|
{
|
|
mob_list = m_ObjectMgr->GetMOBList();
|
|
m_ObjectMgr->SectorSetup(stations);
|
|
m_ObjectMgr->SetSectorManager(this);
|
|
}
|
|
|
|
do
|
|
{
|
|
current_tick = GetNet7TickCount();
|
|
|
|
if (m_SectorID < 9999) //only MOBs and object effects for space & planet sectors
|
|
{
|
|
ProcessMOBs(current_tick, check_tick, true);
|
|
|
|
//send station broadcasts
|
|
for (itrOList = stations.begin(); itrOList != stations.end(); ++itrOList)
|
|
{
|
|
(*itrOList)->SendSoundBroadcast(check_tick);
|
|
}
|
|
}
|
|
|
|
if (m_PlayerCount > 0) //only need to process timeslots if there are players present (for now - interacting MOBs will require time slots)
|
|
{
|
|
//first make the event calls for this node
|
|
CallSlotEvents(m_EventSlotIndex);
|
|
CallLongTermEvents(m_EventSlotIndex);
|
|
|
|
//increment the slot index
|
|
m_EventSlotIndex++;
|
|
if (m_EventSlotIndex == (TIMESLOT_DURATION*10)) m_EventSlotIndex = 0;
|
|
}
|
|
|
|
check_tick++;
|
|
sleep_time = current_tick - GetNet7TickCount() + SECTOR_THREAD_INTERVAL;
|
|
if (check_tick > 128) check_tick = 0;
|
|
if (sleep_time < 0) sleep_time = 0;
|
|
Sleep(sleep_time);
|
|
|
|
} while (!g_ServerShutdown);
|
|
|
|
m_SectorThreadRunning = false;
|
|
}
|
|
|
|
void SectorManager::ProcessMOBs(u32 current_tick, long check_tick, bool handle_attacks)
|
|
{
|
|
u32 index = 0;
|
|
|
|
//update MOBs
|
|
if (check_tick % 5 == 0) //update every 500ms
|
|
{
|
|
ObjectList *olist = m_ObjectMgr->GetMOBList();
|
|
u32 mob_size = olist->size();
|
|
|
|
Object *obj;
|
|
|
|
while (index < mob_size && mob_size == olist->size())
|
|
{
|
|
obj = (*olist)[index];
|
|
|
|
switch (obj->ObjectType())
|
|
{
|
|
case OT_MOB:
|
|
((MOB*)obj)->UpdateMOB(current_tick, handle_attacks);
|
|
break;
|
|
|
|
case OT_MOBSPAWN:
|
|
index += ((MOBSpawn*)obj)->UpdateSpawn(current_tick, handle_attacks);
|
|
break;
|
|
|
|
default:
|
|
LogMessage("Unknown object in MOB list: '%s' type '%d'\n",obj->Name(), obj->ObjectType());
|
|
break;
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool SectorManager::CallSlotEvents(long index)
|
|
{
|
|
bool called_event = false;
|
|
TimeNodeVec::iterator itrTNode;
|
|
|
|
//traverse this node list and call all the nodes
|
|
for (itrTNode = m_EventSlotHead[index].begin(); itrTNode < m_EventSlotHead[index].end(); ++itrTNode)
|
|
{
|
|
MakeTimedCall(*itrTNode);
|
|
called_event = true;
|
|
}
|
|
|
|
m_EventSlotHead[index].clear();
|
|
|
|
return called_event;
|
|
}
|
|
|
|
bool SectorManager::CallLongTermEvents(long index)
|
|
{
|
|
bool called_event = false;
|
|
TimeNodeVec::iterator itrTNode;
|
|
|
|
//now check for long term time nodes, check every 5 seconds, and only pull one off at a time
|
|
if ( (index % 50 == 0) && (m_LongTermTimeNodes.size() > 0) )
|
|
{
|
|
for (itrTNode = m_LongTermTimeNodes.begin(); itrTNode < m_LongTermTimeNodes.end(); ++itrTNode)
|
|
{
|
|
if ( (*itrTNode)->event_time > GetNet7TickCount() )
|
|
{
|
|
MakeTimedCall(*itrTNode);
|
|
m_LongTermTimeNodes.erase(itrTNode);
|
|
called_event = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return called_event;
|
|
}
|
|
|
|
void SectorManager::AddTimedCallPNode(TimeNode *node, unsigned long time_offset)
|
|
{
|
|
SlotTimedCall(node, time_offset);
|
|
}
|
|
|
|
void SectorManager::AddTimedCallPNode(TimeNode *this_node, broadcast_function func, long time_offset, Object *obj, long i1, long i2, long i3, long i4, char *ch, float a)
|
|
{
|
|
//store params in node
|
|
m_Mutex.Lock();
|
|
|
|
memset ((void*)this_node, 0, sizeof(TimeNode));
|
|
|
|
this_node->func = func;
|
|
this_node->obj = obj;
|
|
this_node->i1 = i1;
|
|
this_node->i2 = i2;
|
|
this_node->i3 = i3;
|
|
this_node->i4 = i4;
|
|
if (ch != 0)
|
|
{
|
|
this_node->ch = g_StringMgr->GetStr(ch);
|
|
}
|
|
else
|
|
{
|
|
this_node->ch = 0;
|
|
}
|
|
this_node->a = a;
|
|
m_Mutex.Unlock();
|
|
|
|
SlotTimedCall(this_node, time_offset);
|
|
}
|
|
|
|
TimeNode * SectorManager::AddTimedCall(Player *player, broadcast_function func, long time_offset, Object *obj, long i1, long i2, long i3, long i4, char *ch, float a)
|
|
{
|
|
//store params in node
|
|
TimeNode * this_node = m_MemoryMgr->GetBroadcastNodeSlot();
|
|
|
|
m_Mutex.Lock();
|
|
|
|
memset ((void*)this_node, 0, sizeof(TimeNode));
|
|
|
|
this_node->func = func;
|
|
this_node->obj = obj;
|
|
this_node->i1 = i1;
|
|
this_node->i2 = i2;
|
|
this_node->i3 = i3;
|
|
this_node->i4 = i4;
|
|
if (ch != 0)
|
|
{
|
|
this_node->ch = g_StringMgr->GetStr(ch);
|
|
}
|
|
else
|
|
{
|
|
this_node->ch = 0;
|
|
}
|
|
this_node->a = a;
|
|
|
|
if (player == 0)
|
|
{
|
|
this_node->player_id = SECTOR_SERVER_CONNECTIONLESS_NODE;
|
|
}
|
|
else
|
|
{
|
|
this_node->player_id = player->GameID();
|
|
}
|
|
m_Mutex.Unlock();
|
|
|
|
SlotTimedCall(this_node, time_offset);
|
|
|
|
|
|
return (this_node);
|
|
}
|
|
|
|
long SectorManager::GetSlotIndex(long time_offset)
|
|
{
|
|
long index;
|
|
//work out required number of slots ahead we need
|
|
long slots = ((time_offset+50) / 100);
|
|
|
|
if (slots < 2) slots = 2; //Ensure we never crash into CallSlotEvents call
|
|
|
|
m_Mutex.Lock();
|
|
index = (m_EventSlotIndex + slots) % (TIMESLOT_DURATION * 10);
|
|
m_Mutex.Unlock();
|
|
|
|
return index;
|
|
}
|
|
|
|
void SectorManager::SlotTimedCall(TimeNode *this_node, unsigned long time_offset)
|
|
{
|
|
if (m_EventSlotHead)
|
|
{
|
|
this_node->event_time = time_offset + GetNet7TickCount();
|
|
|
|
if (time_offset < (TIMESLOT_DURATION * 1000)) //use the slotted system
|
|
{
|
|
//slot call into appropriate vector slot
|
|
long index = GetSlotIndex(time_offset);
|
|
this_node->EventIndex = (short)index;
|
|
m_EventSlotHead[index].push_back(this_node);
|
|
}
|
|
else //use long term slot system
|
|
{
|
|
this_node->EventIndex = -1;
|
|
m_LongTermTimeNodes.push_back(this_node);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LogMessage("*** FATAL ERROR: TimeSlots not available in sector %d %s\n", this->m_SectorNumber, this->m_SectorName);
|
|
}
|
|
}
|
|
|
|
void SectorManager::MakeTimedCall(TimeNode *this_node)
|
|
{
|
|
TimeNode node;
|
|
memcpy(&node, this_node, sizeof(TimeNode));
|
|
RemoveTimedCall(this_node);
|
|
|
|
int ShutdownTimes[] = { 15, 10, 5 };
|
|
|
|
Player *p = g_PlayerMgr->GetPlayer(node.player_id);
|
|
|
|
if ((node.player_id != NODE_NO_LONGER_NEEDED) &&
|
|
((node.player_id == SECTOR_SERVER_CONNECTIONLESS_NODE) || p) )
|
|
{
|
|
switch(node.func)
|
|
{
|
|
case B_WARP_BROADCAST:
|
|
p->StartWarp();
|
|
break;
|
|
case B_DESTROY_RESOURCE:
|
|
m_ObjectMgr->DestroyObject(node.obj, 0, node.i1);
|
|
break;
|
|
case B_WARP_RESET:
|
|
p->FinalWarpReset();
|
|
break;
|
|
case B_WARP_TERMINATE:
|
|
p->TerminateWarp();
|
|
break;
|
|
case B_MINE_RESOURCE://(time_to_drain, obj, stack_val, slot);
|
|
p->PullOreFromResource(node.obj, node.i1, node.i2, node.i3, node.i4);
|
|
break;
|
|
case B_COLLECT_RESOURCE:
|
|
p->TakeOreOnboard(node.obj, node.i3);
|
|
break;
|
|
case B_MOB_DAMAGE:
|
|
node.obj->DamageMOB(node.i1, node.i2, node.a, node.i3);
|
|
break;
|
|
case B_SHIP_DAMAGE:
|
|
p->ShipDamage(node.i1, node.a, (short)node.i2);
|
|
break;
|
|
case B_RECHARGE_REACTOR:
|
|
RechargeReactor(p);
|
|
break;
|
|
case B_RECHARGE_SHIELD:
|
|
RechargeShield(p);
|
|
break;
|
|
case B_FORCE_LOGOUT:
|
|
ForceLogout(p);
|
|
break;
|
|
case B_BUFF_TIMEOUT:
|
|
BuffTimeout(p);
|
|
break;
|
|
case B_CAMERA_CONTROL:
|
|
p->SendCameraControl(node.i1, node.i2);
|
|
break;
|
|
case B_MANUFACTURE_ACTION:
|
|
p->ManufactureTimedReturn(node.i1);
|
|
break;
|
|
case B_ITEM_INSTALL:
|
|
p->m_Equip[node.i1].FinishInstall();
|
|
break;
|
|
case B_ITEM_COOLDOWN:
|
|
p->m_Equip[node.i1].CoolDown();
|
|
break;
|
|
case B_TEST_MESSAGE:
|
|
p->SendVaMessage("Test Message time: %d [%d]",node.event_time, node.i1);
|
|
break;
|
|
case B_ABILITY_REMOVE:
|
|
p->AbilityRemove(node.i1);
|
|
break;
|
|
case B_PLAYER_BUFFS:
|
|
p->m_Buffs.Update(node.i1);
|
|
break;
|
|
case B_SHOOT_AMMO:
|
|
p->m_Equip[node.i1].ShootAmmo(node.i2);
|
|
break;
|
|
case B_SERVER_SHUTDOWN:
|
|
char Msg[60];
|
|
sprintf(Msg, "Server shutdown in %d seconds!", ShutdownTimes[m_ShutDownMark]);
|
|
g_ServerMgr->m_PlayerMgr.GlobalAdminMessage(Msg);
|
|
AddTimedCall(0, B_SERVER_SHUTDOWN, ShutdownTimes[m_ShutDownMark] * 1000, NULL);
|
|
m_ShutDownMark++;
|
|
if (m_ShutDownMark > 2)
|
|
{
|
|
// Shutdown the server
|
|
g_ServerShutdown = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SectorManager::RemoveTimedCall(TimeNode *node, bool force)
|
|
{
|
|
m_Mutex.Lock();
|
|
if (force)
|
|
{
|
|
TimeNodeVec::iterator itrTNode;
|
|
if (node->EventIndex == -1)
|
|
{
|
|
for (itrTNode = m_LongTermTimeNodes.begin(); itrTNode < m_LongTermTimeNodes.end(); ++itrTNode)
|
|
{
|
|
if (*itrTNode == node)
|
|
{
|
|
LogMessage("Long term TimeNode erased\n");
|
|
m_LongTermTimeNodes.erase(itrTNode);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (itrTNode = m_EventSlotHead[node->EventIndex].begin(); itrTNode < m_EventSlotHead[node->EventIndex].end(); ++itrTNode)
|
|
{
|
|
if (*itrTNode == node)
|
|
{
|
|
LogMessage("TimeNode erased\n");
|
|
m_EventSlotHead[node->EventIndex].erase(itrTNode);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
memset(node, 0, sizeof(TimeNode)); //erase node contents.
|
|
m_Mutex.Unlock();
|
|
}
|
|
|
|
// This helper function is referenced by _beginthread to launch the TCP thread.
|
|
#ifdef WIN32
|
|
void __cdecl RunEventThreadAPI(void *arg)
|
|
{
|
|
SectorManager * mgr = (SectorManager *) arg;
|
|
mgr->RunSectorEventThread();
|
|
_endthread();
|
|
}
|
|
#else // Linux
|
|
void * RunEventThreadAPI(void *arg)
|
|
{
|
|
SectorManager * mgr = (SectorManager *) arg;
|
|
mgr->RunSectorEventThread();
|
|
return NULL;
|
|
}
|
|
#endif
|