1
0
Fork 0

Added falling block entities. Sand and gravel now properly fall down

Implemented the PACKET_SPAWN_OBJECT packet
Made some things use BLOCKTYPE instead of char

Android: Requests WebAdmin port when pressing the configure button


git-svn-id: http://mc-server.googlecode.com/svn/trunk@915 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
faketruth 2012-09-30 16:37:44 +00:00
parent 1d8921c151
commit ba2a9b6b2c
26 changed files with 254 additions and 70 deletions

View File

@ -15,9 +15,18 @@
#include "ToJava.h"
#include "Root.h"
#include "WebAdmin.h"
#include <android/log.h>
#ifdef _WIN32 // For IntelliSense parsing
typedef void jobject;
typedef int jint;
typedef bool jboolean;
typedef void JavaVM;
typedef void JNIEnv;
#endif
cCriticalSection g_CriticalSection;
JNIEnv* g_CurrentJNIEnv = 0;
@ -61,7 +70,7 @@ cMainThread * pMainThread = NULL;
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
__android_log_print(ANDROID_LOG_ERROR,"MCServer", "%s", "JNI_OnLoad JNI_OnLoad JNI_OnLoad JNI_OnLoad");
//__android_log_print(ANDROID_LOG_ERROR,"MCServer", "%s", "JNI_OnLoad JNI_OnLoad JNI_OnLoad JNI_OnLoad");
g_JavaVM = vm;
return JNI_VERSION_1_4;
}
@ -72,20 +81,11 @@ extern "C" void Java_com_mcserver_MCServerActivity_NativeOnCreate( JNIEnv* env,
g_CriticalSection.Lock();
g_CurrentJNIEnv = env;
g_JavaThread = thiz;
//if( !cLogger::GetSingletonPtr() ) new cLogger();
__android_log_print(ANDROID_LOG_ERROR,"MCServer", "%s", "Logging from C++!");
//__android_log_print(ANDROID_LOG_ERROR,"MCServer", "%s", "Logging from C++!");
g_CriticalSection.Unlock();
//CallJavaFunction_Void_Void(g_JavaActivity, "TestTest" );
//CallJavaFunction_Void_String(g_JavaThread, "AddToLog", "herpderpderp!!" );
mkdir("/sdcard/mcserver", S_IRWXU | S_IRWXG | S_IRWXO);
// __android_log_print(ANDROID_LOG_ERROR,"MCServer", "%s", "Before mainthread");
// pMainThread = new cMainThread();
// pMainThread->Start();
// __android_log_print(ANDROID_LOG_ERROR,"MCServer", "%s", "AFter mainthread");
pRoot = new cRoot();
pRoot->Start();
delete pRoot; pRoot = NULL;
@ -107,8 +107,6 @@ extern "C" void Java_com_mcserver_MCServerActivity_NativeCleanUp( JNIEnv* env,
{
pRoot->ServerCommand("stop");
}
// pMainThread->Stop();
// delete pMainThread; pMainThread = NULL;
}
@ -117,4 +115,16 @@ extern "C" void Java_com_mcserver_MCServerActivity_NativeCleanUp( JNIEnv* env,
extern "C" jboolean Java_com_mcserver_MCServerActivity_NativeIsServerRunning( JNIEnv* env, jobject thiz )
{
return pRoot != NULL;
}
extern "C" jint Java_com_mcserver_MCServerActivity_NativeGetWebAdminPort( JNIEnv* env, jobject thiz )
{
if( pRoot != NULL && pRoot->GetWebAdmin() != NULL )
{
return pRoot->GetWebAdmin()->GetPort();
}
return 0;
}

View File

@ -59,7 +59,7 @@ public class MCServerActivity extends Activity {
((Button)findViewById(R.id.configure_server)).setOnClickListener( new View.OnClickListener() {
public void onClick(View v) {
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://localhost:8081/webadmin/"));
Intent myIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://localhost:" + NativeGetWebAdminPort() + "/webadmin/"));
startActivity( myIntent );
}
});
@ -251,6 +251,7 @@ public class MCServerActivity extends Activity {
public native void NativeOnCreate();
public native void NativeCleanUp();
public native boolean NativeIsServerRunning();
public native int NativeGetWebAdminPort();
}

View File

@ -906,6 +906,14 @@
RelativePath="..\source\Entity.h"
>
</File>
<File
RelativePath="..\source\FallingBlock.cpp"
>
</File>
<File
RelativePath="..\source\FallingBlock.h"
>
</File>
<File
RelativePath="..\source\FurnaceEntity.cpp"
>

View File

@ -1483,6 +1483,14 @@ void cClientHandle::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Blo
void cClientHandle::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, short a_SpeedX, short a_SpeedY, short a_SpeedZ)
{
m_Protocol->SendSpawnObject(a_Entity, a_ObjectType, a_ObjectData, a_SpeedX, a_SpeedY, a_SpeedZ);
}
void cClientHandle::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
{

View File

@ -118,6 +118,7 @@ public:
void SendWindowClose (char a_WindowID);
void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots);
void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ );
void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, short a_SpeedX, short a_SpeedY, short a_SpeedZ);
const AString & GetUsername(void) const; //tolua_export

View File

@ -81,7 +81,7 @@ inline bool IsValidItem( int a_ItemID ) //tolua_export
inline bool IsBlockWater(char a_BlockID)
inline bool IsBlockWater(BLOCKTYPE a_BlockID)
{
return (a_BlockID == E_BLOCK_WATER || a_BlockID == E_BLOCK_STATIONARY_WATER);
}
@ -90,18 +90,18 @@ inline bool IsBlockWater(char a_BlockID)
inline bool IsBlockLava(char a_BlockID)
inline bool IsBlockLava(BLOCKTYPE a_BlockID)
{
return (a_BlockID == E_BLOCK_LAVA || a_BlockID == E_BLOCK_STATIONARY_LAVA);
}
inline bool IsBlockLiquid(char a_BlockID)
inline bool IsBlockLiquid(BLOCKTYPE a_BlockID)
{
return IsBlockWater(a_BlockID) || IsBlockLava(a_BlockID);
}
inline bool IsBlockTypeOfDirt(char a_BlockID)
inline bool IsBlockTypeOfDirt(BLOCKTYPE a_BlockID)
{
switch (a_BlockID)
{

64
source/FallingBlock.cpp Normal file
View File

@ -0,0 +1,64 @@
#include "Globals.h"
#include "FallingBlock.h"
#include "World.h"
#include "ClientHandle.h"
CLASS_DEFINITION( cFallingBlock, cEntity )
cFallingBlock::cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_BlockType)
: super( a_BlockPosition.x + 0.5f, a_BlockPosition.y + 0.5f, a_BlockPosition.z + 0.5f )
, m_BlockType( a_BlockType )
, m_OriginalPosition( a_BlockPosition )
, m_SpeedY( 0 )
{
}
cFallingBlock::~cFallingBlock()
{
}
void cFallingBlock::Initialize(cWorld * a_World)
{
super::Initialize( a_World );
a_World->BroadcastSpawn(*this);
}
void cFallingBlock::SpawnOn(cClientHandle & a_ClientHandle)
{
a_ClientHandle.SendSpawnObject(*this, 70, m_BlockType, 0, 0, 0);
}
void cFallingBlock::Tick(float a_Dt)
{
float MilliDt = a_Dt * 0.001f;
m_SpeedY -= MilliDt * 9.8f;
m_Pos.y += m_SpeedY * MilliDt;
//GetWorld()->BroadcastTeleportEntity(*this); // Testing position
Vector3i BlockPos( m_OriginalPosition.x, (int)(m_Pos.y-0.5), m_OriginalPosition.z );
if( !IsPassable( GetWorld()->GetBlock( BlockPos ) ) )
{
Destroy();
GetWorld()->SetBlock( BlockPos.x, BlockPos.y+1, BlockPos.z, m_BlockType, 0 );
}
}

44
source/FallingBlock.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include "Entity.h"
#include "Defines.h"
class cPlayer;
class cItem;
class cFallingBlock : public cEntity
{
typedef cEntity super;
public:
CLASS_PROTOTYPE();
cFallingBlock(const Vector3i & a_BlockPosition, BLOCKTYPE a_BlockType);
~cFallingBlock();
virtual void Initialize(cWorld * a_World) override;
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void Tick(float a_Dt) override;
private:
BLOCKTYPE m_BlockType;
Vector3i m_OriginalPosition;
float m_SpeedY;
static bool IsPassable( BLOCKTYPE a_BlockType )
{
return a_BlockType == E_BLOCK_AIR || IsBlockLiquid( a_BlockType );
}
};

View File

@ -48,7 +48,7 @@ void cFireSimulator::Simulate( float a_Dt )
}
bool cFireSimulator::IsAllowedBlock( char a_BlockID )
bool cFireSimulator::IsAllowedBlock( BLOCKTYPE a_BlockID )
{
return a_BlockID == E_BLOCK_FIRE
|| IsBlockLava(a_BlockID);
@ -78,12 +78,12 @@ void cFireSimulator::_AddBlock(int a_X, int a_Y, int a_Z)
}
bool cFireSimulator::IsForeverBurnable( char a_BlockID )
bool cFireSimulator::IsForeverBurnable( BLOCKTYPE a_BlockID )
{
return a_BlockID == E_BLOCK_BLOODSTONE;
}
bool cFireSimulator::IsBurnable( char a_BlockID )
bool cFireSimulator::IsBurnable( BLOCKTYPE a_BlockID )
{
return a_BlockID == E_BLOCK_PLANKS
|| a_BlockID == E_BLOCK_LEAVES
@ -95,7 +95,7 @@ bool cFireSimulator::IsBurnable( char a_BlockID )
|| a_BlockID == E_BLOCK_VINES;
}
bool cFireSimulator::FiresForever( char a_BlockID )
bool cFireSimulator::FiresForever( BLOCKTYPE a_BlockID )
{
return a_BlockID != E_BLOCK_FIRE;
}

View File

@ -21,16 +21,16 @@ public:
cFireSimulator( cWorld* a_World );
~cFireSimulator();
virtual void Simulate( float a_Dt );
virtual void Simulate( float a_Dt ) override;
virtual bool IsAllowedBlock( char a_BlockID );
virtual bool IsAllowedBlock( BLOCKTYPE a_BlockID ) override;
virtual bool IsBurnable( char a_BlockID );
virtual bool IsForeverBurnable( char a_BlockID );
virtual bool FiresForever( char a_BlockID );
virtual bool IsBurnable( BLOCKTYPE a_BlockID );
virtual bool IsForeverBurnable( BLOCKTYPE a_BlockID );
virtual bool FiresForever( BLOCKTYPE a_BlockID );
protected:
virtual void AddBlock(int a_X, int a_Y, int a_Z);
virtual void AddBlock(int a_X, int a_Y, int a_Z) override;
virtual void _AddBlock(int a_X, int a_Y, int a_Z);
virtual bool BurnBlockAround(int a_X, int a_Y, int a_Z);
virtual bool BurnBlock(int a_X, int a_Y, int a_Z);

View File

@ -436,7 +436,7 @@ void cFluidSimulator::Simulate( float a_Dt )
bool cFluidSimulator::IsPassableForFluid(char a_BlockID)
bool cFluidSimulator::IsPassableForFluid(BLOCKTYPE a_BlockID)
{
return a_BlockID == E_BLOCK_AIR
|| a_BlockID == E_BLOCK_FIRE
@ -448,7 +448,7 @@ bool cFluidSimulator::IsPassableForFluid(char a_BlockID)
bool cFluidSimulator::IsStationaryBlock (char a_BlockID)
bool cFluidSimulator::IsStationaryBlock (BLOCKTYPE a_BlockID)
{
return a_BlockID == m_StationaryFluidBlock;
}
@ -457,7 +457,7 @@ bool cFluidSimulator::IsStationaryBlock (char a_BlockID)
bool cFluidSimulator::CanWashAway( char a_BlockID )
bool cFluidSimulator::CanWashAway( BLOCKTYPE a_BlockID )
{
switch( a_BlockID )
{
@ -476,7 +476,7 @@ bool cFluidSimulator::CanWashAway( char a_BlockID )
bool cFluidSimulator::IsSolidBlock( char a_BlockID )
bool cFluidSimulator::IsSolidBlock( BLOCKTYPE a_BlockID )
{
return !(a_BlockID == E_BLOCK_AIR
|| a_BlockID == E_BLOCK_FIRE

View File

@ -29,11 +29,11 @@ public:
//Gets the flowing direction. if a_Over is true also the block over the current block affects the direction (standard)
Direction GetFlowingDirection(int a_X, int a_Y, int a_Z, bool a_Over = true);
virtual bool IsAllowedBlock( char a_BlockID ) = 0;
virtual bool IsStationaryBlock( char a_BlockID);
virtual bool IsPassableForFluid( char a_BlockID );
bool CanWashAway( char a_BlockID );
bool IsSolidBlock(char a_BlockID);
virtual bool IsAllowedBlock( BLOCKTYPE a_BlockID ) = 0;
virtual bool IsStationaryBlock( BLOCKTYPE a_BlockID);
virtual bool IsPassableForFluid( BLOCKTYPE a_BlockID );
bool CanWashAway( BLOCKTYPE a_BlockID );
bool IsSolidBlock(BLOCKTYPE a_BlockID);
protected:
virtual void AddBlock( int a_X, int a_Y, int a_Z);
char GetHighestLevelAround( int a_X, int a_Y, int a_Z );
@ -47,8 +47,8 @@ protected:
FluidData* m_Data;
//Customize
char m_FluidBlock;
char m_StationaryFluidBlock;
BLOCKTYPE m_FluidBlock;
BLOCKTYPE m_StationaryFluidBlock;
char m_MaxHeight;
char m_FlowReduction;

View File

@ -14,7 +14,7 @@ cLavaSimulator::cLavaSimulator(cWorld *a_World)
}
bool cLavaSimulator::IsAllowedBlock(char a_BlockID)
bool cLavaSimulator::IsAllowedBlock(BLOCKTYPE a_BlockID)
{
return IsBlockLava(a_BlockID);
}

View File

@ -6,7 +6,7 @@ class cLavaSimulator : public cFluidSimulator
public:
cLavaSimulator( cWorld* a_World );
virtual bool IsAllowedBlock( char a_BlockID );
virtual bool IsAllowedBlock( BLOCKTYPE a_BlockID ) override;
};

View File

@ -85,6 +85,7 @@ public:
virtual void SendWindowClose (char a_WindowID) = 0;
virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) = 0;
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) = 0;
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, short a_SpeedX, short a_SpeedY, short a_SpeedZ) = 0;
/// Returns the ServerID used for authentication through session.minecraft.net
virtual AString GetAuthServerID(void) = 0;

View File

@ -52,7 +52,7 @@ enum
PACKET_PLAYER_SPAWN = 0x14,
PACKET_PICKUP_SPAWN = 0x15,
PACKET_COLLECT_PICKUP = 0x16,
PACKET_ADD_VEHICLE = 0x17,
PACKET_SPAWN_OBJECT = 0x17,
PACKET_SPAWN_MOB = 0x18,
PACKET_DESTROY_ENTITY = 0x1d,
PACKET_ENTITY = 0x1e,
@ -794,6 +794,29 @@ void cProtocol125::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bloc
void cProtocol125::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, short a_SpeedX, short a_SpeedY, short a_SpeedZ)
{
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_SPAWN_OBJECT);
WriteInt (a_Entity.GetUniqueID());
WriteByte(a_ObjectType);
WriteInt ((int)(a_Entity.GetPosX() * 32));
WriteInt ((int)(a_Entity.GetPosY() * 32));
WriteInt ((int)(a_Entity.GetPosZ() * 32));
WriteInt (a_ObjectData);
if( a_ObjectData != 0 )
{
WriteShort( a_SpeedX );
WriteShort( a_SpeedY );
WriteShort( a_SpeedZ );
}
Flush();
}
AString cProtocol125::GetAuthServerID(void)
{
// http://wiki.vg/wiki/index.php?title=Session&oldid=2262

View File

@ -69,6 +69,7 @@ public:
virtual void SendWindowClose (char a_WindowID) override;
virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override;
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override;
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, short a_SpeedX, short a_SpeedY, short a_SpeedZ) override;
virtual AString GetAuthServerID(void) override;

View File

@ -495,6 +495,16 @@ void cProtocolRecognizer::SendUseBed(const cEntity & a_Entity, int a_BlockX, int
void cProtocolRecognizer::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, short a_SpeedX, short a_SpeedY, short a_SpeedZ)
{
ASSERT(m_Protocol != NULL);
m_Protocol->SendSpawnObject(a_Entity, a_ObjectType, a_ObjectData, a_SpeedX, a_SpeedY, a_SpeedZ);
}
AString cProtocolRecognizer::GetAuthServerID(void)
{
ASSERT(m_Protocol != NULL);

View File

@ -80,6 +80,7 @@ public:
virtual void SendWindowClose (char a_WindowID) override;
virtual void SendWindowOpen (char a_WindowID, char a_WindowType, const AString & a_WindowTitle, char a_NumSlots) override;
virtual void SendUseBed (const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ ) override;
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, short a_SpeedX, short a_SpeedY, short a_SpeedZ) override;
virtual AString GetAuthServerID(void) override;

View File

@ -10,10 +10,10 @@ public:
cRedstoneSimulator( cWorld* a_World );
~cRedstoneSimulator();
virtual void Simulate( float a_Dt );
virtual bool IsAllowedBlock( char a_BlockID ) { return true; }
virtual void Simulate( float a_Dt ) override;
virtual bool IsAllowedBlock( BLOCKTYPE a_BlockID ) override { return true; }
virtual void WakeUp( int a_X, int a_Y, int a_Z );
virtual void WakeUp( int a_X, int a_Y, int a_Z ) override;
enum eRedstoneDirection
{

View File

@ -6,7 +6,7 @@
#include "Vector3i.h"
#include "BlockID.h"
#include "Defines.h"
#include "FallingBlock.h"
@ -19,12 +19,20 @@ cSandSimulator::cSandSimulator( cWorld* a_World )
}
cSandSimulator::~cSandSimulator()
{
delete m_Buffer;
delete m_Blocks;
}
void cSandSimulator::Simulate( float a_Dt )
{
m_Buffer->clear();
@ -33,31 +41,39 @@ void cSandSimulator::Simulate( float a_Dt )
for( BlockList::iterator itr = m_Buffer->begin(); itr != m_Buffer->end(); ++itr )
{
Vector3i Pos = *itr;
char BlockID = m_World->GetBlock(Pos.x, Pos.y, Pos.z);
BLOCKTYPE BlockID = m_World->GetBlock(Pos.x, Pos.y, Pos.z);
if(!IsAllowedBlock(BlockID))
continue;
char BottomBlock = m_World->GetBlock( Pos.x, Pos.y - 1, Pos.z );
BLOCKTYPE BottomBlock = m_World->GetBlock( Pos.x, Pos.y - 1, Pos.z );
if( IsPassable(BottomBlock) )
{
m_World->SetBlock( Pos.x, Pos.y, Pos.z, E_BLOCK_AIR, 0 );
m_World->SetBlock( Pos.x, Pos.y - 1, Pos.z, BlockID, 0 );
cFallingBlock * FallingBlock = new cFallingBlock( Pos, BlockID );
FallingBlock->Initialize( m_World );
m_World->SetBlock( Pos.x, Pos.y, Pos.z, E_BLOCK_AIR, 0 );
}
}
}
bool cSandSimulator::IsAllowedBlock( char a_BlockID )
bool cSandSimulator::IsAllowedBlock( BLOCKTYPE a_BlockID )
{
return a_BlockID == E_BLOCK_SAND
|| a_BlockID == E_BLOCK_GRAVEL;
}
void cSandSimulator::AddBlock(int a_X, int a_Y, int a_Z)
{
if(!IsAllowedBlock(m_World->GetBlock(a_X, a_Y, a_Z))) //This should save very much time because it doesn´t have to iterate through all blocks
if(!IsAllowedBlock(m_World->GetBlock(a_X, a_Y, a_Z)))
return;
Vector3i Block(a_X, a_Y, a_Z);
@ -71,21 +87,16 @@ void cSandSimulator::AddBlock(int a_X, int a_Y, int a_Z)
}
m_Blocks->push_back(Block);
}
bool cSandSimulator::IsPassable( char a_BlockID )
bool cSandSimulator::IsPassable( BLOCKTYPE a_BlockID )
{
return a_BlockID == E_BLOCK_AIR
|| IsBlockWater(a_BlockID)
|| IsBlockLava(a_BlockID)
|| a_BlockID == E_BLOCK_FIRE;
}
void cSandSimulator::WakeUp( int a_X, int a_Y, int a_Z )
{
//Nothing else needs to be simulated :D (Bugs not included :s)
AddBlock( a_X, a_Y+1, a_Z );
AddBlock( a_X, a_Y, a_Z );
}

View File

@ -21,14 +21,13 @@ public:
cSandSimulator( cWorld* a_World );
~cSandSimulator();
virtual void Simulate( float a_Dt );
virtual void WakeUp( int a_X, int a_Y, int a_Z );
virtual void Simulate( float a_Dt ) override;
virtual bool IsAllowedBlock( char a_BlockID );
virtual bool IsPassable( char a_BlockID );
virtual bool IsAllowedBlock( BLOCKTYPE a_BlockID ) override;
virtual bool IsPassable( BLOCKTYPE a_BlockID );
protected:
virtual void AddBlock(int a_X, int a_Y, int a_Z);
virtual void AddBlock(int a_X, int a_Y, int a_Z) override;
typedef std::list <Vector3i> BlockList;
BlockList * m_Blocks;

View File

@ -11,7 +11,7 @@ public:
virtual void Simulate( float a_Dt ) = 0;
virtual void WakeUp( int a_X, int a_Y, int a_Z );
virtual bool IsAllowedBlock( char a_BlockID ) = 0;
virtual bool IsAllowedBlock( BLOCKTYPE a_BlockID ) = 0;
protected:
virtual void AddBlock(int a_X, int a_Y, int a_Z) = 0;

View File

@ -15,7 +15,7 @@ cWaterSimulator::cWaterSimulator(cWorld *a_World)
}
bool cWaterSimulator::IsAllowedBlock(char a_BlockID)
bool cWaterSimulator::IsAllowedBlock(BLOCKTYPE a_BlockID)
{
return IsBlockWater(a_BlockID);
}

View File

@ -6,6 +6,6 @@ class cWaterSimulator : public cFluidSimulator
public:
cWaterSimulator( cWorld* a_World );
virtual bool IsAllowedBlock( char a_BlockID );
virtual bool IsAllowedBlock( BLOCKTYPE a_BlockID ) override;
};

View File

@ -43,6 +43,8 @@ public:
PluginList GetPlugins() { return m_Plugins; }
static void Request_Handler(webserver::http_request* r);
int GetPort() { return m_Port; }
private:
#ifdef _WIN32