Updated client, read more

It seems like the project as a whole is fairly stable now. I'm prepping to
merge this into master, despite the lack of monsters ATM. Hopefully this
break hasn't affected the stability too much.
This commit is contained in:
Kayne Ruse
2015-02-14 23:39:56 +11:00
parent e71d0b3a09
commit 18b144fa46
15 changed files with 476 additions and 329 deletions
+3 -3
View File
@@ -37,7 +37,7 @@
#include "main_menu.hpp" #include "main_menu.hpp"
#include "options_menu.hpp" #include "options_menu.hpp"
#include "lobby_menu.hpp" #include "lobby_menu.hpp"
#include "in_world.hpp" #include "world.hpp"
#include "disconnected_screen.hpp" #include "disconnected_screen.hpp"
//------------------------- //-------------------------
@@ -185,8 +185,8 @@ void ClientApplication::LoadScene(SceneList sceneIndex) {
case SceneList::LOBBYMENU: case SceneList::LOBBYMENU:
activeScene = new LobbyMenu(&clientIndex, &accountIndex); activeScene = new LobbyMenu(&clientIndex, &accountIndex);
break; break;
case SceneList::INWORLD: case SceneList::WORLD:
activeScene = new InWorld(&clientIndex, &accountIndex); activeScene = new World(&clientIndex, &accountIndex);
break; break;
case SceneList::DISCONNECTEDSCREEN: case SceneList::DISCONNECTEDSCREEN:
activeScene = new DisconnectedScreen(); activeScene = new DisconnectedScreen();
@@ -1,264 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "in_world.hpp"
#include "channels.hpp"
#include "ip_operators.hpp"
#include "terminal_error.hpp"
#include <chrono>
#include <sstream>
#include <stdexcept>
//-------------------------
//Basic connections
//-------------------------
void InWorld::HandlePacket(SerialPacket* const argPacket) {
switch(argPacket->type) {
//heartbeat system
case SerialPacketType::PING:
HandlePing(static_cast<ServerPacket*>(argPacket));
break;
case SerialPacketType::PONG:
HandlePong(static_cast<ServerPacket*>(argPacket));
break;
//game server connections
case SerialPacketType::LOGOUT_RESPONSE:
HandleLogoutResponse(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::DISCONNECT_RESPONSE:
HandleDisconnectResponse(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::DISCONNECT_FORCED:
HandleDisconnectForced(static_cast<ClientPacket*>(argPacket));
break;
//map management
case SerialPacketType::REGION_CONTENT:
HandleRegionContent(static_cast<RegionPacket*>(argPacket));
break;
//character management
case SerialPacketType::CHARACTER_CREATE:
HandleCharacterCreate(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_DELETE:
HandleCharacterDelete(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_CHARACTER_EXISTS:
HandleCharacterQueryExists(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_MOVEMENT:
HandleCharacterMovement(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_ATTACK:
HandleCharacterAttack(static_cast<CharacterPacket*>(argPacket));
break;
//monster management
case SerialPacketType::MONSTER_CREATE:
HandleMonsterCreate(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::MONSTER_DELETE:
HandleMonsterDelete(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_MONSTER_EXISTS:
HandleMonsterQueryExists(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::MONSTER_MOVEMENT:
HandleMonsterMovement(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::MONSTER_ATTACK:
HandleMonsterAttack(static_cast<MonsterPacket*>(argPacket));
break;
//rejection messages
case SerialPacketType::REGION_REJECTION:
case SerialPacketType::CHARACTER_REJECTION:
throw(terminal_error(static_cast<TextPacket*>(argPacket)->text));
break;
case SerialPacketType::SHUTDOWN_REJECTION:
throw(std::runtime_error(static_cast<TextPacket*>(argPacket)->text));
break;
//errors
default: {
std::ostringstream msg;
msg << "Unknown SerialPacketType encountered in InWorld: " << static_cast<int>(argPacket->type);
throw(std::runtime_error(msg.str()));
}
break;
}
}
void InWorld::HandlePing(ServerPacket* const argPacket) {
ServerPacket newPacket;
newPacket.type = SerialPacketType::PONG;
network.SendTo(argPacket->srcAddress, &newPacket);
}
void InWorld::HandlePong(ServerPacket* const argPacket) {
if (*network.GetIPAddress(Channels::SERVER) != argPacket->srcAddress) {
throw(std::runtime_error("Heartbeat message received from an unknown source"));
}
attemptedBeats = 0;
lastBeat = Clock::now();
}
//-------------------------
//Connection control
//-------------------------
void InWorld::SendLogoutRequest() {
ClientPacket newPacket;
//send a logout request
newPacket.type = SerialPacketType::LOGOUT_REQUEST;
newPacket.accountIndex = accountIndex;
network.SendTo(Channels::SERVER, &newPacket);
}
void InWorld::SendDisconnectRequest() {
ClientPacket newPacket;
//send a disconnect request
newPacket.type = SerialPacketType::DISCONNECT_REQUEST;
newPacket.clientIndex = clientIndex;
network.SendTo(Channels::SERVER, &newPacket);
}
void InWorld::SendShutdownRequest() {
ClientPacket newPacket;
//send a shutdown request
newPacket.type = SerialPacketType::SHUTDOWN_REQUEST;
newPacket.accountIndex = accountIndex;
network.SendTo(Channels::SERVER, &newPacket);
}
void InWorld::HandleLogoutResponse(ClientPacket* const argPacket) {
if (localCharacter) {
characterMap.erase(characterIndex);
localCharacter = nullptr;
}
accountIndex = -1;
characterIndex = -1;
//reset the camera
camera.marginX = camera.marginY = 0;
//because, why not? I guess...
SendDisconnectRequest();
}
void InWorld::HandleDisconnectResponse(ClientPacket* const argPacket) {
HandleLogoutResponse(argPacket);//shortcut
SetNextScene(SceneList::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have successfully logged out";
}
void InWorld::HandleDisconnectForced(ClientPacket* const argPacket) {
HandleDisconnectResponse(argPacket);//shortcut
SetNextScene(SceneList::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have been forcibly disconnected by the server";
}
void InWorld::CheckHeartBeat() {
//check the connection (heartbeat)
if (Clock::now() - lastBeat > std::chrono::seconds(3)) {
if (attemptedBeats > 2) {
//escape to the disconnect screen
SendDisconnectRequest();
SetNextScene(SceneList::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "Error: Lost connection to the server";
}
else {
ServerPacket newPacket;
newPacket.type = SerialPacketType::PING;
network.SendTo(Channels::SERVER, &newPacket);
attemptedBeats++;
lastBeat = Clock::now();
}
}
}
//-------------------------
//map management
//-------------------------
void InWorld::SendRegionRequest(int roomIndex, int x, int y) {
RegionPacket packet;
//pack the region's data
packet.type = SerialPacketType::REGION_REQUEST;
packet.roomIndex = roomIndex;
packet.x = x;
packet.y = y;
network.SendTo(Channels::SERVER, &packet);
}
void InWorld::HandleRegionContent(RegionPacket* const argPacket) {
//replace existing regions
regionPager.UnloadIf([&](Region const& region) -> bool {
return region.GetX() == argPacket->x && region.GetY() == argPacket->y;
});
regionPager.PushRegion(argPacket->region);
//clean up after the serial code
delete argPacket->region;
argPacket->region = nullptr;
}
void InWorld::UpdateMap() {
if (roomIndex == -1) {
return;
}
//these represent the zone of regions that the client needs loaded, including the mandatory buffers (+1/-1)
int xStart = snapToBase(REGION_WIDTH, camera.x/tileSheet.GetTileW()) - REGION_WIDTH;
int xEnd = snapToBase(REGION_WIDTH, (camera.x+camera.width)/tileSheet.GetTileW()) + REGION_WIDTH;
int yStart = snapToBase(REGION_HEIGHT, camera.y/tileSheet.GetTileH()) - REGION_HEIGHT;
int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT;
//prune distant regions
regionPager.GetContainer()->remove_if([&](Region const& region) -> bool {
return region.GetX() < xStart || region.GetX() > xEnd || region.GetY() < yStart || region.GetY() > yEnd;
});
//request empty regions within this zone
for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
if (!regionPager.FindRegion(i, j)) {
SendRegionRequest(roomIndex, i, j);
}
}
}
}
@@ -49,11 +49,11 @@
#include <chrono> #include <chrono>
class InWorld : public BaseScene { class World: public BaseScene {
public: public:
//Public access members //Public access members
InWorld(int* const argClientIndex, int* const argAccountIndex); World(int* const argClientIndex, int* const argAccountIndex);
~InWorld(); ~World();
protected: protected:
//Frame loop //Frame loop
@@ -71,42 +71,56 @@ protected:
void KeyDown(SDL_KeyboardEvent const&); void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&); void KeyUp(SDL_KeyboardEvent const&);
//Basic connections //handle incoming traffic
void HandlePacket(SerialPacket* const); void HandlePacket(SerialPacket* const);
void HandlePing(ServerPacket* const);
void HandlePong(ServerPacket* const);
//Connection control //heartbeat system
void SendLogoutRequest(); void hPing(ServerPacket* const);
void SendDisconnectRequest(); void hPong(ServerPacket* const);
void SendShutdownRequest();
void HandleLogoutResponse(ClientPacket* const);
void HandleDisconnectResponse(ClientPacket* const);
void HandleDisconnectForced(ClientPacket* const);
void CheckHeartBeat(); void CheckHeartBeat();
//basic connections
void SendLogoutRequest();
void SendDisconnectRequest();
void SendAdminDisconnectForced();
void SendAdminShutdownRequest();
void hLogoutResponse(ClientPacket* const);
void hDisconnectResponse(ClientPacket* const);
void hAdminDisconnectForced(ClientPacket* const);
//map management //map management
void SendRegionRequest(int roomIndex, int x, int y); void SendRegionRequest(int roomIndex, int x, int y);
void HandleRegionContent(RegionPacket* const); void hRegionContent(RegionPacket* const);
void UpdateMap(); void UpdateMap();
//character management //character management
void HandleCharacterCreate(CharacterPacket* const); void hCharacterCreate(CharacterPacket* const);
void HandleCharacterDelete(CharacterPacket* const); void hCharacterDelete(CharacterPacket* const);
void HandleCharacterQueryExists(CharacterPacket* const); void hQueryCharacterExists(CharacterPacket* const);
void HandleCharacterMovement(CharacterPacket* const); void hQueryCharacterStats(CharacterPacket* const);
void HandleCharacterAttack(CharacterPacket* const); void hQueryCharacterLocation(CharacterPacket* const);
void hCharacterMovement(CharacterPacket* const);
void hCharacterAttack(CharacterPacket* const);
void hCharacterDamage(CharacterPacket* const);
//monster management //monster management
void HandleMonsterCreate(MonsterPacket* const); void hMonsterCreate(MonsterPacket* const);
void HandleMonsterDelete(MonsterPacket* const); void hMonsterDelete(MonsterPacket* const);
void HandleMonsterQueryExists(MonsterPacket* const); void hQueryMonsterExists(MonsterPacket* const);
void HandleMonsterMovement(MonsterPacket* const); void hQueryMonsterStats(MonsterPacket* const);
void HandleMonsterAttack(MonsterPacket* const); void hQueryMonsterLocation(MonsterPacket* const);
void hMonsterMovement(MonsterPacket* const);
void hMonsterAttack(MonsterPacket* const);
void hMonsterDamage(MonsterPacket* const);
//player movement //chat
void hTextBroadcast(TextPacket* const);
void hTextSpeech(TextPacket* const);
void hTextWhisper(TextPacket* const);
//general gameplay
void SendLocalCharacterMovement(); void SendLocalCharacterMovement();
std::list<BoundingBox> GenerateCollisionGrid(Entity*, int tileWidth, int tileHeight); std::list<BoundingBox> GenerateCollisionGrid(Entity*, int tileWidth, int tileHeight);
@@ -19,7 +19,7 @@
* 3. This notice may not be removed or altered from any source * 3. This notice may not be removed or altered from any source
* distribution. * distribution.
*/ */
#include "in_world.hpp" #include "world.hpp"
#include "channels.hpp" #include "channels.hpp"
@@ -35,7 +35,7 @@
//DOCS: new characters will result in create messages //DOCS: new characters will result in create messages
//DOCS: this client's character will exist in both (skipped) //DOCS: this client's character will exist in both (skipped)
void InWorld::HandleCharacterCreate(CharacterPacket* const argPacket) { void World::hCharacterCreate(CharacterPacket* const argPacket) {
//prevent double message //prevent double message
if (characterMap.find(argPacket->characterIndex) != characterMap.end()) { if (characterMap.find(argPacket->characterIndex) != characterMap.end()) {
std::ostringstream msg; std::ostringstream msg;
@@ -74,7 +74,7 @@ void InWorld::HandleCharacterCreate(CharacterPacket* const argPacket) {
std::cout << "Character Create, total: " << characterMap.size() << std::endl; std::cout << "Character Create, total: " << characterMap.size() << std::endl;
} }
void InWorld::HandleCharacterDelete(CharacterPacket* const argPacket) { void World::hCharacterDelete(CharacterPacket* const argPacket) {
//ignore if this character doesn't exist //ignore if this character doesn't exist
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex); std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
if (characterIt == characterMap.end()) { if (characterIt == characterMap.end()) {
@@ -100,7 +100,7 @@ void InWorld::HandleCharacterDelete(CharacterPacket* const argPacket) {
std::cout << "Character Delete, total: " << characterMap.size() << std::endl; std::cout << "Character Delete, total: " << characterMap.size() << std::endl;
} }
void InWorld::HandleCharacterQueryExists(CharacterPacket* const argPacket) { void World::hQueryCharacterExists(CharacterPacket* const argPacket) {
//prevent a double message about this player's character //prevent a double message about this player's character
if (argPacket->accountIndex == accountIndex) { if (argPacket->accountIndex == accountIndex) {
return; return;
@@ -127,7 +127,15 @@ void InWorld::HandleCharacterQueryExists(CharacterPacket* const argPacket) {
std::cout << "Character Query, total: " << characterMap.size() << std::endl; std::cout << "Character Query, total: " << characterMap.size() << std::endl;
} }
void InWorld::HandleCharacterMovement(CharacterPacket* const argPacket) { void World::hQueryCharacterStats(CharacterPacket* const argPacket) {
//TODO: empty
}
void World::hQueryCharacterLocation(CharacterPacket* const argPacket) {
//TODO: empty
}
void World::hCharacterMovement(CharacterPacket* const argPacket) {
//TODO: (1) Authentication //TODO: (1) Authentication
if (argPacket->characterIndex == characterIndex) { if (argPacket->characterIndex == characterIndex) {
return; return;
@@ -143,15 +151,19 @@ void InWorld::HandleCharacterMovement(CharacterPacket* const argPacket) {
} }
} }
void InWorld::HandleCharacterAttack(CharacterPacket* const argPacket) { void World::hCharacterAttack(CharacterPacket* const argPacket) {
//TODO: (1) attack animation
}
void World::hCharacterDamage(CharacterPacket* const argPacket) {
//TODO: (1) attack animation //TODO: (1) attack animation
} }
//------------------------- //-------------------------
//player movement //player movement & collision
//------------------------- //-------------------------
void InWorld::SendLocalCharacterMovement() { void World::SendLocalCharacterMovement() {
CharacterPacket newPacket; CharacterPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_MOVEMENT; newPacket.type = SerialPacketType::CHARACTER_MOVEMENT;
@@ -164,7 +176,7 @@ void InWorld::SendLocalCharacterMovement() {
network.SendTo(Channels::SERVER, &newPacket); network.SendTo(Channels::SERVER, &newPacket);
} }
std::list<BoundingBox> InWorld::GenerateCollisionGrid(Entity* ptr, int tileWidth, int tileHeight) { std::list<BoundingBox> World::GenerateCollisionGrid(Entity* ptr, int tileWidth, int tileHeight) {
//prepare for collisions //prepare for collisions
BoundingBox wallBounds = {0, 0, tileWidth, tileHeight}; BoundingBox wallBounds = {0, 0, tileWidth, tileHeight};
std::list<BoundingBox> boxList; std::list<BoundingBox> boxList;
+39
View File
@@ -0,0 +1,39 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "world.hpp"
//-------------------------
//chat
//-------------------------
void World::hTextBroadcast(TextPacket* const argPacket) {
//TODO: (1) empty
}
void World::hTextSpeech(TextPacket* const argPacket) {
//TODO: (1) empty
}
void World::hTextWhisper(TextPacket* const argPacket) {
//TODO: (1) empty
}
@@ -0,0 +1,135 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "world.hpp"
#include "channels.hpp"
#include "ip_operators.hpp"
#include <chrono>
#include <sstream>
#include <stdexcept>
//-------------------------
//heartbeat system
//-------------------------
void World::hPing(ServerPacket* const argPacket) {
ServerPacket newPacket;
newPacket.type = SerialPacketType::PONG;
network.SendTo(argPacket->srcAddress, &newPacket);
}
void World::hPong(ServerPacket* const argPacket) {
if (*network.GetIPAddress(Channels::SERVER) != argPacket->srcAddress) {
throw(std::runtime_error("Heartbeat message received from an unknown source"));
}
attemptedBeats = 0;
lastBeat = Clock::now();
}
void World::CheckHeartBeat() {
//check the connection (heartbeat)
if (Clock::now() - lastBeat > std::chrono::seconds(3)) {
if (attemptedBeats > 2) {
//escape to the disconnect screen
SendDisconnectRequest();
SetNextScene(SceneList::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "Error: Lost connection to the server";
}
else {
ServerPacket newPacket;
newPacket.type = SerialPacketType::PING;
network.SendTo(Channels::SERVER, &newPacket);
attemptedBeats++;
lastBeat = Clock::now();
}
}
}
//-------------------------
//Connection control
//-------------------------
void World::SendLogoutRequest() {
ClientPacket newPacket;
//send a logout request
newPacket.type = SerialPacketType::LOGOUT_REQUEST;
newPacket.accountIndex = accountIndex;
network.SendTo(Channels::SERVER, &newPacket);
}
void World::SendDisconnectRequest() {
ClientPacket newPacket;
//send a disconnect request
newPacket.type = SerialPacketType::DISCONNECT_REQUEST;
newPacket.clientIndex = clientIndex;
network.SendTo(Channels::SERVER, &newPacket);
}
void World::SendAdminDisconnectForced() {
//TODO: empty
}
void World::SendAdminShutdownRequest() {
ClientPacket newPacket;
//send a shutdown request
newPacket.type = SerialPacketType::ADMIN_SHUTDOWN_REQUEST;
newPacket.accountIndex = accountIndex;
network.SendTo(Channels::SERVER, &newPacket);
}
void World::hLogoutResponse(ClientPacket* const argPacket) {
if (localCharacter) {
characterMap.erase(characterIndex);
localCharacter = nullptr;
}
accountIndex = -1;
characterIndex = -1;
//reset the camera
camera.marginX = camera.marginY = 0;
//because, why not? I guess...
SendDisconnectRequest();
}
void World::hDisconnectResponse(ClientPacket* const argPacket) {
hLogoutResponse(argPacket);//shortcut
SetNextScene(SceneList::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have successfully logged out";
}
void World::hAdminDisconnectForced(ClientPacket* const argPacket) {
hDisconnectResponse(argPacket);//shortcut
SetNextScene(SceneList::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "You have been forcibly disconnected by the server";
}
@@ -19,7 +19,7 @@
* 3. This notice may not be removed or altered from any source * 3. This notice may not be removed or altered from any source
* distribution. * distribution.
*/ */
#include "in_world.hpp" #include "world.hpp"
#include "channels.hpp" #include "channels.hpp"
@@ -34,7 +34,7 @@
//Public access members //Public access members
//------------------------- //-------------------------
InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex): World::World(int* const argClientIndex, int* const argAccountIndex):
clientIndex(*argClientIndex), clientIndex(*argClientIndex),
accountIndex(*argAccountIndex) accountIndex(*argAccountIndex)
{ {
@@ -75,8 +75,8 @@ InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex):
memset(&newPacket, 0, MAX_PACKET_SIZE); memset(&newPacket, 0, MAX_PACKET_SIZE);
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS; newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
network.SendTo(Channels::SERVER, &newPacket); network.SendTo(Channels::SERVER, &newPacket);
// newPacket.type = SerialPacketType::QUERY_MONSTER_EXISTS; newPacket.type = SerialPacketType::QUERY_MONSTER_EXISTS;
// network.SendTo(Channels::SERVER, &newPacket); network.SendTo(Channels::SERVER, &newPacket);
//set the camera's values //set the camera's values
camera.width = GetScreen()->w; camera.width = GetScreen()->w;
@@ -86,7 +86,7 @@ InWorld::InWorld(int* const argClientIndex, int* const argAccountIndex):
// //
} }
InWorld::~InWorld() { World::~World() {
//unload the local data //unload the local data
characterMap.clear(); characterMap.clear();
monsterMap.clear(); monsterMap.clear();
@@ -96,11 +96,11 @@ InWorld::~InWorld() {
//Frame loop //Frame loop
//------------------------- //-------------------------
void InWorld::FrameStart() { void World::FrameStart() {
// //
} }
void InWorld::Update() { void World::Update() {
//create and zero the buffer //create and zero the buffer
SerialPacket* packetBuffer = reinterpret_cast<SerialPacket*>(new char[MAX_PACKET_SIZE]); SerialPacket* packetBuffer = reinterpret_cast<SerialPacket*>(new char[MAX_PACKET_SIZE]);
memset(packetBuffer, 0, MAX_PACKET_SIZE); memset(packetBuffer, 0, MAX_PACKET_SIZE);
@@ -154,18 +154,18 @@ void InWorld::Update() {
camera.y = localCharacter->GetOrigin().y - camera.marginY; camera.y = localCharacter->GetOrigin().y - camera.marginY;
} }
void InWorld::FrameEnd() { void World::FrameEnd() {
// //
} }
void InWorld::RenderFrame() { void World::RenderFrame() {
// SDL_FillRect(GetScreen(), 0, 0); // SDL_FillRect(GetScreen(), 0, 0);
Render(GetScreen()); Render(GetScreen());
SDL_Flip(GetScreen()); SDL_Flip(GetScreen());
fps.Calculate(); fps.Calculate();
} }
void InWorld::Render(SDL_Surface* const screen) { void World::Render(SDL_Surface* const screen) {
//draw the map //draw the map
for (std::list<Region>::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) { for (std::list<Region>::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y); tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y);
@@ -192,32 +192,32 @@ void InWorld::Render(SDL_Surface* const screen) {
//Event handlers //Event handlers
//------------------------- //-------------------------
void InWorld::QuitEvent() { void World::QuitEvent() {
//two-step logout //two-step logout
SendDisconnectRequest(); SendDisconnectRequest();
SetNextScene(SceneList::QUIT); SetNextScene(SceneList::QUIT);
} }
void InWorld::MouseMotion(SDL_MouseMotionEvent const& motion) { void World::MouseMotion(SDL_MouseMotionEvent const& motion) {
disconnectButton.MouseMotion(motion); disconnectButton.MouseMotion(motion);
shutDownButton.MouseMotion(motion); shutDownButton.MouseMotion(motion);
} }
void InWorld::MouseButtonDown(SDL_MouseButtonEvent const& button) { void World::MouseButtonDown(SDL_MouseButtonEvent const& button) {
disconnectButton.MouseButtonDown(button); disconnectButton.MouseButtonDown(button);
shutDownButton.MouseButtonDown(button); shutDownButton.MouseButtonDown(button);
} }
void InWorld::MouseButtonUp(SDL_MouseButtonEvent const& button) { void World::MouseButtonUp(SDL_MouseButtonEvent const& button) {
if (disconnectButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) { if (disconnectButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) {
SendLogoutRequest(); SendLogoutRequest();
} }
if (shutDownButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) { if (shutDownButton.MouseButtonUp(button) == Button::State::HOVER && button.button == SDL_BUTTON_LEFT) {
SendShutdownRequest(); SendAdminShutdownRequest();
} }
} }
void InWorld::KeyDown(SDL_KeyboardEvent const& key) { void World::KeyDown(SDL_KeyboardEvent const& key) {
//hotkeys //hotkeys
switch(key.keysym.sym) { switch(key.keysym.sym) {
case SDLK_ESCAPE: case SDLK_ESCAPE:
@@ -258,7 +258,7 @@ void InWorld::KeyDown(SDL_KeyboardEvent const& key) {
SendLocalCharacterMovement(); SendLocalCharacterMovement();
} }
void InWorld::KeyUp(SDL_KeyboardEvent const& key) { void World::KeyUp(SDL_KeyboardEvent const& key) {
//character movement //character movement
if (!localCharacter) { if (!localCharacter) {
return; return;
@@ -303,3 +303,116 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) {
localCharacter->CorrectSprite(); localCharacter->CorrectSprite();
SendLocalCharacterMovement(); SendLocalCharacterMovement();
} }
//-------------------------
//Direct incoming traffic
//-------------------------
void World::HandlePacket(SerialPacket* const argPacket) {
switch(argPacket->type) {
//heartbeat system
case SerialPacketType::PING:
hPing(static_cast<ServerPacket*>(argPacket));
break;
case SerialPacketType::PONG:
hPong(static_cast<ServerPacket*>(argPacket));
break;
//game server connections
case SerialPacketType::LOGOUT_RESPONSE:
hLogoutResponse(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::DISCONNECT_RESPONSE:
hDisconnectResponse(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::ADMIN_DISCONNECT_FORCED:
hAdminDisconnectForced(static_cast<ClientPacket*>(argPacket));
break;
//map management
case SerialPacketType::REGION_CONTENT:
hRegionContent(static_cast<RegionPacket*>(argPacket));
break;
//character management
case SerialPacketType::CHARACTER_CREATE:
hCharacterCreate(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_DELETE:
hCharacterDelete(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_CHARACTER_EXISTS:
hQueryCharacterExists(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_CHARACTER_STATS:
hQueryCharacterStats(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_CHARACTER_LOCATION:
hQueryCharacterLocation(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_MOVEMENT:
hCharacterMovement(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_ATTACK:
hCharacterAttack(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_DAMAGE:
hCharacterDamage(static_cast<CharacterPacket*>(argPacket));
break;
//monster management
case SerialPacketType::MONSTER_CREATE:
hMonsterCreate(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::MONSTER_DELETE:
hMonsterDelete(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_MONSTER_EXISTS:
hQueryMonsterExists(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_MONSTER_STATS:
hQueryMonsterStats(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::QUERY_MONSTER_LOCATION:
hQueryMonsterLocation(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::MONSTER_MOVEMENT:
hMonsterMovement(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::MONSTER_ATTACK:
hMonsterAttack(static_cast<MonsterPacket*>(argPacket));
break;
case SerialPacketType::MONSTER_DAMAGE:
hMonsterDamage(static_cast<MonsterPacket*>(argPacket));
break;
//chat
case SerialPacketType::TEXT_BROADCAST:
hTextBroadcast(static_cast<TextPacket*>(argPacket));
break;
case SerialPacketType::TEXT_SPEECH:
hTextSpeech(static_cast<TextPacket*>(argPacket));
break;
case SerialPacketType::TEXT_WHISPER:
hTextWhisper(static_cast<TextPacket*>(argPacket));
break;
//general rejection messages
case SerialPacketType::REGION_REJECTION:
case SerialPacketType::CHARACTER_REJECTION:
case SerialPacketType::QUERY_REJECTION:
throw(terminal_error(static_cast<TextPacket*>(argPacket)->text));
break;
case SerialPacketType::SHUTDOWN_REJECTION:
throw(std::runtime_error(static_cast<TextPacket*>(argPacket)->text));
break;
//errors
default: {
std::ostringstream msg;
msg << "Unknown SerialPacketType encountered in World: " << static_cast<int>(argPacket->type);
throw(std::runtime_error(msg.str()));
}
break;
}
}
+79
View File
@@ -0,0 +1,79 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "world.hpp"
#include "channels.hpp"
//-------------------------
//map management
//-------------------------
void World::SendRegionRequest(int roomIndex, int x, int y) {
RegionPacket packet;
//pack the region's data
packet.type = SerialPacketType::REGION_REQUEST;
packet.roomIndex = roomIndex;
packet.x = x;
packet.y = y;
network.SendTo(Channels::SERVER, &packet);
}
void World::hRegionContent(RegionPacket* const argPacket) {
//replace existing regions
regionPager.UnloadIf([&](Region const& region) -> bool {
return region.GetX() == argPacket->x && region.GetY() == argPacket->y;
});
regionPager.PushRegion(argPacket->region);
//clean up after the serial code
delete argPacket->region;
argPacket->region = nullptr;
}
void World::UpdateMap() {
if (roomIndex == -1) {
return;
}
//these represent the zone of regions that the client needs loaded, including the mandatory buffers (+1/-1)
int xStart = snapToBase(REGION_WIDTH, camera.x/tileSheet.GetTileW()) - REGION_WIDTH;
int xEnd = snapToBase(REGION_WIDTH, (camera.x+camera.width)/tileSheet.GetTileW()) + REGION_WIDTH;
int yStart = snapToBase(REGION_HEIGHT, camera.y/tileSheet.GetTileH()) - REGION_HEIGHT;
int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT;
//prune distant regions
regionPager.GetContainer()->remove_if([&](Region const& region) -> bool {
return region.GetX() < xStart || region.GetX() > xEnd || region.GetY() < yStart || region.GetY() > yEnd;
});
//request empty regions within this zone
for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
if (!regionPager.FindRegion(i, j)) {
SendRegionRequest(roomIndex, i, j);
}
}
}
}
@@ -19,7 +19,7 @@
* 3. This notice may not be removed or altered from any source * 3. This notice may not be removed or altered from any source
* distribution. * distribution.
*/ */
#include "in_world.hpp" #include "world.hpp"
#include "channels.hpp" #include "channels.hpp"
@@ -31,7 +31,7 @@
//monster management //monster management
//------------------------- //-------------------------
void InWorld::HandleMonsterCreate(MonsterPacket* const argPacket) { void World::hMonsterCreate(MonsterPacket* const argPacket) {
//check for logic errors //check for logic errors
if (monsterMap.find(argPacket->monsterIndex) != monsterMap.end()) { if (monsterMap.find(argPacket->monsterIndex) != monsterMap.end()) {
std::ostringstream msg; std::ostringstream msg;
@@ -64,7 +64,7 @@ void InWorld::HandleMonsterCreate(MonsterPacket* const argPacket) {
std::cout << "Monster Create, total: " << monsterMap.size() << std::endl; std::cout << "Monster Create, total: " << monsterMap.size() << std::endl;
} }
void InWorld::HandleMonsterDelete(MonsterPacket* const argPacket) { void World::hMonsterDelete(MonsterPacket* const argPacket) {
//ignore if this monster doesn't exist //ignore if this monster doesn't exist
std::map<int, BaseMonster>::iterator monsterIt = monsterMap.find(argPacket->monsterIndex); std::map<int, BaseMonster>::iterator monsterIt = monsterMap.find(argPacket->monsterIndex);
if (monsterIt == monsterMap.end()) { if (monsterIt == monsterMap.end()) {
@@ -78,7 +78,7 @@ void InWorld::HandleMonsterDelete(MonsterPacket* const argPacket) {
std::cout << "Monster Delete, total: " << monsterMap.size() << std::endl; std::cout << "Monster Delete, total: " << monsterMap.size() << std::endl;
} }
void InWorld::HandleMonsterQueryExists(MonsterPacket* const argPacket) { void World::hQueryMonsterExists(MonsterPacket* const argPacket) {
//ignore monsters in a different room (sub-optimal) //ignore monsters in a different room (sub-optimal)
if (argPacket->roomIndex != roomIndex) { if (argPacket->roomIndex != roomIndex) {
return; return;
@@ -98,7 +98,15 @@ void InWorld::HandleMonsterQueryExists(MonsterPacket* const argPacket) {
std::cout << "Monster Query, total: " << monsterMap.size() << std::endl; std::cout << "Monster Query, total: " << monsterMap.size() << std::endl;
} }
void InWorld::HandleMonsterMovement(MonsterPacket* const argPacket) { void World::hQueryMonsterStats(MonsterPacket* const argPacket) {
//TODO: empty
}
void World::hQueryMonsterLocation(MonsterPacket* const argPacket) {
//TODO: empty
}
void World::hMonsterMovement(MonsterPacket* const argPacket) {
//ignore if this monster doesn't exist //ignore if this monster doesn't exist
std::map<int, BaseMonster>::iterator monsterIt = monsterMap.find(argPacket->monsterIndex); std::map<int, BaseMonster>::iterator monsterIt = monsterMap.find(argPacket->monsterIndex);
if (monsterIt == monsterMap.end()) { if (monsterIt == monsterMap.end()) {
@@ -109,6 +117,10 @@ void InWorld::HandleMonsterMovement(MonsterPacket* const argPacket) {
monsterIt->second.SetOrigin(argPacket->motion); monsterIt->second.SetOrigin(argPacket->motion);
} }
void InWorld::HandleMonsterAttack(MonsterPacket* const argPacket) { void World::hMonsterAttack(MonsterPacket* const argPacket) {
//TODO: (1) HandleMonsterAttack //TODO: (1) HandleMonsterAttack
} }
void World::hMonsterDamage(MonsterPacket* const argPacket) {
//TODO: (1) empty
}
+1 -1
View File
@@ -248,7 +248,7 @@ void LobbyMenu::HandleLoginResponse(ClientPacket* const argPacket) {
throw(std::runtime_error("Client index invalid during login")); throw(std::runtime_error("Client index invalid during login"));
} }
accountIndex = argPacket->accountIndex; accountIndex = argPacket->accountIndex;
SetNextScene(SceneList::INWORLD); SetNextScene(SceneList::WORLD);
} }
void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) { void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) {
+5 -1
View File
@@ -125,5 +125,9 @@ void MainMenu::KeyDown(SDL_KeyboardEvent const& key) {
} }
void MainMenu::KeyUp(SDL_KeyboardEvent const& key) { void MainMenu::KeyUp(SDL_KeyboardEvent const& key) {
// switch(key.keysym.sym) {
case SDLK_ESCAPE:
QuitEvent();
break;
}
} }
+1 -1
View File
@@ -33,7 +33,7 @@ enum class SceneList {
MAINMENU, MAINMENU,
OPTIONSMENU, OPTIONSMENU,
LOBBYMENU, LOBBYMENU,
INWORLD, WORLD,
DISCONNECTEDSCREEN, DISCONNECTEDSCREEN,
}; };
+1
View File
@@ -141,6 +141,7 @@ enum class SerialPacketType {
CHARACTER_REJECTION, CHARACTER_REJECTION,
MONSTER_REJECTION, MONSTER_REJECTION,
SHUTDOWN_REJECTION, SHUTDOWN_REJECTION,
QUERY_REJECTION,
//------------------------- //-------------------------
//not used //not used
+2
View File
@@ -100,6 +100,7 @@ void serializePacket(void* buffer, SerialPacketBase* packet) {
case SerialPacketType::CHARACTER_REJECTION: case SerialPacketType::CHARACTER_REJECTION:
case SerialPacketType::MONSTER_REJECTION: case SerialPacketType::MONSTER_REJECTION:
case SerialPacketType::SHUTDOWN_REJECTION: case SerialPacketType::SHUTDOWN_REJECTION:
case SerialPacketType::QUERY_REJECTION:
serializeText(buffer, static_cast<TextPacket*>(packet)); serializeText(buffer, static_cast<TextPacket*>(packet));
break; break;
} }
@@ -164,6 +165,7 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) {
case SerialPacketType::CHARACTER_REJECTION: case SerialPacketType::CHARACTER_REJECTION:
case SerialPacketType::MONSTER_REJECTION: case SerialPacketType::MONSTER_REJECTION:
case SerialPacketType::SHUTDOWN_REJECTION: case SerialPacketType::SHUTDOWN_REJECTION:
case SerialPacketType::QUERY_REJECTION:
deserializeText(buffer, static_cast<TextPacket*>(packet)); deserializeText(buffer, static_cast<TextPacket*>(packet));
break; break;
} }
+1 -1
View File
@@ -213,7 +213,7 @@ void ServerApplication::Quit() {
} }
//------------------------- //-------------------------
//direct incoming traffic //handle incoming traffic
//------------------------- //-------------------------
void ServerApplication::HandlePacket(SerialPacket* const argPacket) { void ServerApplication::HandlePacket(SerialPacket* const argPacket) {