Merge branch 'client-fix' into develop (read more)

Summary of changes:
* Changed the way I handle packets
* RoomManager is now functional
* Split RegionPager into two classes
* Fixed several major and minor bugs
This commit is contained in:
Kayne Ruse
2014-06-14 04:03:55 +10:00
24 changed files with 487 additions and 394 deletions
+4 -3
View File
@@ -86,10 +86,11 @@ void InCombat::FrameStart() {
void InCombat::Update(double delta) {
//suck in and process all waiting packets
char packetBuffer[MAX_PACKET_SIZE];
while(network.Receive(reinterpret_cast<SerialPacket*>(packetBuffer))) {
HandlePacket(reinterpret_cast<SerialPacket*>(packetBuffer));
SerialPacket* packetBuffer = static_cast<SerialPacket*>(malloc(MAX_PACKET_SIZE));
while(network.Receive(packetBuffer)) {
HandlePacket(packetBuffer);
}
free(static_cast<void*>(packetBuffer));
//TODO: more
}
+18 -14
View File
@@ -95,10 +95,11 @@ void InWorld::FrameStart() {
void InWorld::Update(double delta) {
//suck in and process all waiting packets
char packetBuffer[MAX_PACKET_SIZE];
while(network.Receive(reinterpret_cast<SerialPacket*>(packetBuffer))) {
HandlePacket(reinterpret_cast<SerialPacket*>(packetBuffer));
SerialPacket* packetBuffer = static_cast<SerialPacket*>(malloc(MAX_PACKET_SIZE));
while(network.Receive(packetBuffer)) {
HandlePacket(packetBuffer);
}
free(static_cast<void*>(packetBuffer));
//update the characters
for (auto& it : characterMap) {
@@ -127,9 +128,9 @@ void InWorld::RenderFrame() {
}
void InWorld::Render(SDL_Surface* const screen) {
//draw the map
for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
tileSheet.DrawRegionTo(screen, *it, camera.x, camera.y);
//draw the map0
for (std::list<Region>::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y);
}
//draw characters
@@ -254,16 +255,16 @@ void InWorld::HandlePacket(SerialPacket* const argPacket) {
HandleDisconnect(argPacket);
break;
case SerialPacketType::CHARACTER_NEW:
HandleCharacterNew(dynamic_cast<CharacterPacket*>(argPacket));
HandleCharacterNew(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_DELETE:
HandleCharacterDelete(dynamic_cast<CharacterPacket*>(argPacket));
HandleCharacterDelete(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_UPDATE:
HandleCharacterUpdate(dynamic_cast<CharacterPacket*>(argPacket));
HandleCharacterUpdate(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::REGION_CONTENT:
HandleRegionContent(dynamic_cast<RegionPacket*>(argPacket));
HandleRegionContent(static_cast<RegionPacket*>(argPacket));
break;
//handle errors
default:
@@ -342,6 +343,9 @@ void InWorld::HandleRegionContent(RegionPacket* const argPacket) {
//replace existing regions
regionPager.UnloadRegion(argPacket->x, argPacket->y);
regionPager.PushRegion(argPacket->region);
//clean up after the serial code
delete argPacket->region;
argPacket->region = nullptr;
}
@@ -430,13 +434,13 @@ void InWorld::UpdateMap() {
int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT;
//prune distant regions
for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); /* EMPTY */) {
for (std::list<Region>::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); /* EMPTY */) {
//check if the region is outside off this area
if ((*it)->GetX() < xStart || (*it)->GetX() > xEnd || (*it)->GetY() < yStart || (*it)->GetY() > yEnd) {
if (it->GetX() < xStart || it->GetX() > xEnd || it->GetY() < yStart || it->GetY() > yEnd) {
//clunky, but the alternative was time consuming
int tmpX = (*it)->GetX();
int tmpY = (*it)->GetY();
int tmpX = it->GetX();
int tmpY = it->GetY();
++it;
regionPager.UnloadRegion(tmpX, tmpY);
+2 -2
View File
@@ -23,7 +23,7 @@
#define INWORLD_HPP_
//maps
#include "region_pager.hpp"
#include "region_pager_base.hpp"
//networking
#include "udp_network_utility.hpp"
@@ -110,7 +110,7 @@ protected:
TileSheet tileSheet;
//map
RegionPager regionPager;
RegionPagerBase regionPager;
//UI
Button disconnectButton;
+6 -5
View File
@@ -85,10 +85,11 @@ void LobbyMenu::FrameStart() {
void LobbyMenu::Update(double delta) {
//suck in and process all waiting packets
char packetBuffer[MAX_PACKET_SIZE];
while(network.Receive(reinterpret_cast<SerialPacket*>(packetBuffer))) {
HandlePacket(reinterpret_cast<SerialPacket*>(packetBuffer));
SerialPacket* packetBuffer = static_cast<SerialPacket*>(malloc(MAX_PACKET_SIZE));
while(network.Receive(packetBuffer)) {
HandlePacket(packetBuffer);
}
free(static_cast<void*>(packetBuffer));
}
void LobbyMenu::FrameEnd() {
@@ -204,10 +205,10 @@ void LobbyMenu::KeyUp(SDL_KeyboardEvent const& key) {
void LobbyMenu::HandlePacket(SerialPacket* const argPacket) {
switch(argPacket->type) {
case SerialPacketType::BROADCAST_RESPONSE:
HandleBroadcastResponse(dynamic_cast<ServerPacket*>(argPacket));
HandleBroadcastResponse(static_cast<ServerPacket*>(argPacket));
break;
case SerialPacketType::JOIN_RESPONSE:
HandleJoinResponse(dynamic_cast<ClientPacket*>(argPacket));
HandleJoinResponse(static_cast<ClientPacket*>(argPacket));
break;
//handle errors
default:
+10 -10
View File
@@ -21,42 +21,42 @@
*/
#include "pager_api.hpp"
#include "region_pager.hpp"
#include "region_pager_lua.hpp"
#include "region.hpp"
#include <stdexcept>
#include <string>
static int setTile(lua_State* L) {
RegionPager* pager = reinterpret_cast<RegionPager*>(lua_touserdata(L, 1));
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
int ret = pager->SetTile(lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4), lua_tointeger(L, 5));
lua_pushinteger(L, ret);
return 1;
}
static int getTile(lua_State* L) {
RegionPager* pager = reinterpret_cast<RegionPager*>(lua_touserdata(L, 1));
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
int ret = pager->GetTile(lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4));
lua_pushinteger(L, ret);
return 1;
}
static int getRegion(lua_State* L) {
RegionPager* pager = reinterpret_cast<RegionPager*>(lua_touserdata(L, 1));
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
Region* region = pager->GetRegion(lua_tointeger(L, 2), lua_tointeger(L, 3));
lua_pushlightuserdata(L, region);
return 1;
}
static int setDirectory(lua_State* L) {
RegionPager* pager = reinterpret_cast<RegionPager*>(lua_touserdata(L, 1));
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
std::string s = pager->SetDirectory(lua_tostring(L, 2));
lua_pushstring(L, s.c_str());
return 1;
}
static int getDirectory(lua_State* L) {
RegionPager* pager = reinterpret_cast<RegionPager*>(lua_touserdata(L, 1));
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
std::string s = pager->GetDirectory();
lua_pushstring(L, s.c_str());
return 1;
@@ -64,7 +64,7 @@ static int getDirectory(lua_State* L) {
static int loadRegion(lua_State* L) {
//get the parameters
RegionPager* pager = reinterpret_cast<RegionPager*>(lua_touserdata(L, 1));
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
Region* region = pager->GetRegion(lua_tointeger(L, 2), lua_tointeger(L, 3));
std::string s = pager->GetDirectory();
@@ -83,7 +83,7 @@ static int loadRegion(lua_State* L) {
static int saveRegion(lua_State* L) {
//get the parameters
RegionPager* pager = reinterpret_cast<RegionPager*>(lua_touserdata(L, 1));
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
Region* region = pager->GetRegion(lua_tointeger(L, 2), lua_tointeger(L, 3));
std::string s = pager->GetDirectory();
@@ -102,7 +102,7 @@ static int saveRegion(lua_State* L) {
static int createRegion(lua_State* L) {
//get the parameters
RegionPager* pager = reinterpret_cast<RegionPager*>(lua_touserdata(L, 1));
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
Region* region = pager->GetRegion(lua_tointeger(L, 2), lua_tointeger(L, 3));
//push the parameters
@@ -120,7 +120,7 @@ static int createRegion(lua_State* L) {
static int unloadRegion(lua_State* L) {
//get the parameters
RegionPager* pager = reinterpret_cast<RegionPager*>(lua_touserdata(L, 1));
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
Region* region = pager->GetRegion(lua_tointeger(L, 2), lua_tointeger(L, 3));
std::string s = pager->GetDirectory();
+13 -6
View File
@@ -21,13 +21,20 @@
*/
#include "region.hpp"
Region::Region(int argX, int argY):
x(argX),
y(argY)
{
for (register int i = 0; i < REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH; ++i) {
*(reinterpret_cast<type_t*>(tiles) + i) = 0;
#include "utility.hpp"
#include <stdexcept>
#include <cstring>
Region::Region(int argX, int argY): x(argX), y(argY) {
if (x != snapToBase(REGION_WIDTH, x) || y != snapToBase(REGION_HEIGHT, y)) {
throw(std::invalid_argument("Region location is off grid"));
}
memset(tiles, 0, REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH*sizeof(type_t));
}
Region::Region(Region const& rhs): x(rhs.x), y(rhs.y) {
memcpy(tiles, rhs.tiles, REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH*sizeof(type_t));
}
Region::type_t Region::SetTile(int x, int y, int z, type_t v) {
+1
View File
@@ -32,6 +32,7 @@ public:
Region() = delete;
Region(int x, int y);
Region(Region const&);
~Region() = default;
type_t SetTile(int x, int y, int z, type_t v);
-205
View File
@@ -1,205 +0,0 @@
/* Copyright: (c) Kayne Ruse 2014
*
* 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 "region_pager.hpp"
#include "utility.hpp"
#include <stdexcept>
Region::type_t RegionPager::SetTile(int x, int y, int z, Region::type_t v) {
Region* ptr = GetRegion(x, y);
return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v);
}
Region::type_t RegionPager::GetTile(int x, int y, int z) {
Region* ptr = GetRegion(x, y);
return ptr->GetTile(x - ptr->GetX(), y - ptr->GetY(), z);
}
Region* RegionPager::GetRegion(int x, int y) {
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//get the region by various means
Region* ptr = nullptr;
ptr = FindRegion(x, y);
if (ptr) return ptr;
ptr = LoadRegion(x, y);
if (ptr) return ptr;
return CreateRegion(x, y);
}
Region* RegionPager::FindRegion(int x, int y) {
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//find the region
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); it++) {
if ((*it)->GetX() == x && (*it)->GetY() == y) {
return *it;
}
}
return nullptr;
}
Region* RegionPager::PushRegion(Region* const region) {
if (
region->GetX() != snapToBase(REGION_WIDTH, region->GetX()) ||
region->GetY() != snapToBase(REGION_HEIGHT, region->GetY())
)
{
throw(std::runtime_error("Pushed region does not conform to the region grid"));
}
regionList.push_front(region);
return regionList.front();
}
Region* RegionPager::LoadRegion(int x, int y) {
//only work if using lua
if (!luaState) {
throw(std::runtime_error("RegionPager::luaState is null"));
}
//load the region if possible
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//overwrite?
Region* ptr = FindRegion(x, y);
if (!ptr) {
ptr = new Region(x, y);
}
//API hook
lua_getglobal(luaState, "region");
lua_getfield(luaState, -1, "load");
lua_pushlightuserdata(luaState, ptr);
lua_pushstring(luaState, directory.c_str());
if (lua_pcall(luaState, 2, 1, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) ));
}
if (lua_toboolean(luaState, -1)) {
regionList.push_front(ptr);
}
else {
delete ptr;
ptr = nullptr;
}
lua_pop(luaState, 2);
return ptr;
}
Region* RegionPager::SaveRegion(int x, int y) {
//only work if using lua
if (!luaState) {
throw(std::runtime_error("RegionPager::luaState is null"));
}
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//find & save the region
Region* ptr = FindRegion(x, y);
if (ptr) {
//API hook
lua_getglobal(luaState, "region");
lua_getfield(luaState, -1, "save");
lua_pushlightuserdata(luaState, ptr);
lua_pushstring(luaState, directory.c_str());
if (lua_pcall(luaState, 2, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) ));
}
lua_pop(luaState, 1);
}
return ptr;
}
Region* RegionPager::CreateRegion(int x, int y) {
//only work if using lua
if (!luaState) {
throw(std::runtime_error("RegionPager::luaState is null"));
}
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//overwrite?
Region* ptr = FindRegion(x, y);
if (!ptr) {
ptr = new Region(x, y);
}
//API hook
lua_getglobal(luaState, "region");
lua_getfield(luaState, -1, "create");
lua_pushlightuserdata(luaState, ptr);
//TODO: parameters
if (lua_pcall(luaState, 1, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) ));
}
lua_pop(luaState, 1);
regionList.push_front(ptr);
return ptr;
}
void RegionPager::UnloadRegion(int x, int y) {
//only work if using lua
if (!luaState) {
throw(std::runtime_error("RegionPager::luaState is null"));
}
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
lua_getglobal(luaState, "region");
//custom loop, not FindRegion()
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); /* EMPTY */) {
if ((*it)->GetX() == x && (*it)->GetY() == y) {
//API hook
lua_getfield(luaState, -1, "unload");
lua_pushlightuserdata(luaState, *it);
lua_pushstring(luaState, directory.c_str());
if (lua_pcall(luaState, 2, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) ));
}
delete (*it);
it = regionList.erase(it);
continue;
}
++it;
}
lua_pop(luaState, 1);
}
+87
View File
@@ -0,0 +1,87 @@
/* Copyright: (c) Kayne Ruse 2014
*
* 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 "region_pager_base.hpp"
#include "utility.hpp"
#include <stdexcept>
#include <algorithm>
Region::type_t RegionPagerBase::SetTile(int x, int y, int z, Region::type_t v) {
Region* ptr = GetRegion(x, y);
return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v);
}
Region::type_t RegionPagerBase::GetTile(int x, int y, int z) {
Region* ptr = GetRegion(x, y);
return ptr->GetTile(x - ptr->GetX(), y - ptr->GetY(), z);
}
Region* RegionPagerBase::GetRegion(int x, int y) {
//get the region by various means
Region* ptr = nullptr;
ptr = FindRegion(x, y);
if (ptr) return ptr;
ptr = LoadRegion(x, y);
if (ptr) return ptr;
return CreateRegion(x, y);
}
Region* RegionPagerBase::FindRegion(int x, int y) {
//find the region
std::list<Region>::iterator it = find_if(regionList.begin(), regionList.end(), [x, y](Region& region) -> bool {
return region.GetX() == x && region.GetY() == y;
});
return it != regionList.end() ? &(*it) : nullptr;
}
Region* RegionPagerBase::PushRegion(Region* const ptr) {
regionList.push_front(*ptr);
return &regionList.front();
}
Region* RegionPagerBase::LoadRegion(int x, int y) {
//TODO: load the region if possible
return nullptr;
}
Region* RegionPagerBase::SaveRegion(int x, int y) {
//TODO: find & save the region
return nullptr;
}
Region* RegionPagerBase::CreateRegion(int x, int y) {
if (FindRegion(x, y)) {
throw(std::logic_error("Cannot overwrite an existing region"));
}
regionList.emplace_front(x, y);
return &regionList.front();
}
void RegionPagerBase::UnloadRegion(int x, int y) {
//custom loop, not FindRegion()
regionList.remove_if([x, y](Region& region) -> bool { return region.GetX() == x && region.GetY() == y; });
}
void RegionPagerBase::UnloadAll() {
regionList.clear();
}
+56
View File
@@ -0,0 +1,56 @@
/* Copyright: (c) Kayne Ruse 2014
*
* 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.
*/
#ifndef REGIONPAGERBASE_HPP_
#define REGIONPAGERBASE_HPP_
#include "region.hpp"
#include <list>
class RegionPagerBase {
public:
RegionPagerBase() = default;
virtual ~RegionPagerBase() { UnloadAll(); };
//tile manipulation
virtual Region::type_t SetTile(int x, int y, int z, Region::type_t v);
virtual Region::type_t GetTile(int x, int y, int z);
//region manipulation
virtual Region* GetRegion(int x, int y);
virtual Region* FindRegion(int x, int y);
virtual Region* PushRegion(Region* const);
virtual Region* LoadRegion(int x, int y);
virtual Region* SaveRegion(int x, int y);
virtual Region* CreateRegion(int x, int y);
virtual void UnloadRegion(int x, int y);
virtual void UnloadAll();
//accessors & mutators
std::list<Region>* GetContainer() { return &regionList; }
protected:
std::list<Region> regionList;
};
#endif
+126
View File
@@ -0,0 +1,126 @@
/* Copyright: (c) Kayne Ruse 2014
*
* 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 "region_pager_lua.hpp"
#include "utility.hpp"
#include <stdexcept>
Region* RegionPagerLua::LoadRegion(int x, int y) {
//load the region if possible
//something to work on
regionList.emplace_front(x, y);
//API hook
lua_getglobal(luaState, "region");
lua_getfield(luaState, -1, "load");
lua_pushlightuserdata(luaState, &regionList.front());
lua_pushstring(luaState, directory.c_str());
if (lua_pcall(luaState, 2, 1, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) ));
}
//success or failure
if (!lua_toboolean(luaState, -1)) {
lua_pop(luaState, 2);
regionList.pop_front();
return nullptr;
}
lua_pop(luaState, 2);
return &regionList.front();
}
Region* RegionPagerLua::SaveRegion(int x, int y) {
//find & save the region
Region* ptr = FindRegion(x, y);
if (ptr) {
//API hook
lua_getglobal(luaState, "region");
lua_getfield(luaState, -1, "save");
lua_pushlightuserdata(luaState, ptr);
lua_pushstring(luaState, directory.c_str());
if (lua_pcall(luaState, 2, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) ));
}
lua_pop(luaState, 1);
}
return ptr;
}
Region* RegionPagerLua::CreateRegion(int x, int y) {
if (FindRegion(x, y)) {
throw(std::logic_error("Cannot overwrite an existing region"));
}
//something to work on
regionList.emplace_front(x, y);
//API hook
lua_getglobal(luaState, "region");
lua_getfield(luaState, -1, "create");
lua_pushlightuserdata(luaState, &regionList.front());
//TODO: parameters
if (lua_pcall(luaState, 1, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) ));
}
lua_pop(luaState, 1);
return &regionList.front();;
}
void RegionPagerLua::UnloadRegion(int x, int y) {
lua_getglobal(luaState, "region");
regionList.remove_if([&](Region& region) -> bool {
if (region.GetX() == x && region.GetY() == y) {
//API hook
lua_getfield(luaState, -1, "unload");
lua_pushlightuserdata(luaState, &region);
lua_pushstring(luaState, directory.c_str());
if (lua_pcall(luaState, 2, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) ));
}
return true;
}
return false;
});
lua_pop(luaState, 1);
}
void RegionPagerLua::UnloadAll() {
lua_getglobal(luaState, "region");
for (auto& it : regionList) {
//API hook
lua_getfield(luaState, -1, "unload");
lua_pushlightuserdata(luaState, &it);
lua_pushstring(luaState, directory.c_str());
if (lua_pcall(luaState, 2, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(luaState, -1) ));
}
}
lua_pop(luaState, 1);
regionList.clear();
}
@@ -19,47 +19,34 @@
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef REGIONPAGER_HPP_
#define REGIONPAGER_HPP_
#ifndef REGIONPAGERLUA_HPP_
#define REGIONPAGERLUA_HPP_
#include "region.hpp"
#include "region_pager_base.hpp"
#include "lua/lua.hpp"
#include <list>
#include <string>
//TODO: split this into two: "RegionPagerBase" and "RegionPagerLua"
class RegionPager {
class RegionPagerLua : public RegionPagerBase {
public:
RegionPager() = default;
~RegionPager() = default;
//tile manipulation
Region::type_t SetTile(int x, int y, int z, Region::type_t v);
Region::type_t GetTile(int x, int y, int z);
RegionPagerLua() = default;
~RegionPagerLua() = default;
//region manipulation
Region* GetRegion(int x, int y);
Region* FindRegion(int x, int y);
Region* PushRegion(Region* const);
Region* LoadRegion(int x, int y) override;
Region* SaveRegion(int x, int y) override;
Region* CreateRegion(int x, int y) override;
void UnloadRegion(int x, int y) override;
Region* LoadRegion(int x, int y);
Region* SaveRegion(int x, int y);
Region* CreateRegion(int x, int y);
void UnloadRegion(int x, int y);
//accessors & mutators
std::list<Region*>* GetContainer() { return &regionList; }
void UnloadAll() override;
std::string SetDirectory(std::string s) { return directory = s; }
std::string GetDirectory() { return directory; }
lua_State* SetLuaState(lua_State* L) { return luaState = L; }
lua_State* GetLuaState() { return luaState; }
private:
std::list<Region*> regionList;
protected:
std::string directory;
lua_State* luaState = nullptr;
};
+32 -32
View File
@@ -32,77 +32,77 @@ enum class SerialPacketType {
//keep alive
//ping => pong
PING,
PONG,
PING = 1,
PONG = 2,
//search for the server list
//none => server name, player count, version info (and source address)
BROADCAST_REQUEST,
BROADCAST_RESPONSE,
BROADCAST_REQUEST = 3,
BROADCAST_RESPONSE = 4,
//try to join the server
//username, and password => client index, account index
JOIN_REQUEST,
JOIN_RESPONSE,
JOIN_REJECTION,
JOIN_REQUEST = 5,
JOIN_RESPONSE = 6,
JOIN_REJECTION = 7,
//mass update of all surrounding content
//character.x, character.y => packet barrage
SYNCHRONIZE,
SYNCHRONIZE = 8,
//disconnect from the server
//autentication, account index => disconnect that account
DISCONNECT,
DISCONNECT = 9,
//shut down the server
//autentication => disconnect, shutdown
SHUTDOWN,
SHUTDOWN = 10,
//map data
//room index, region.x, region.y => room index, region.x, region.y, region content
REGION_REQUEST,
REGION_CONTENT,
REGION_REQUEST = 11,
REGION_CONTENT = 12,
//combat data
//TODO: system incomplete
COMBAT_NEW,
COMBAT_DELETE,
COMBAT_UPDATE,
COMBAT_NEW = 13,
COMBAT_DELETE = 14,
COMBAT_UPDATE = 15,
COMBAT_ENTER_REQUEST,
COMBAT_ENTER_RESPONSE,
COMBAT_ENTER_REQUEST = 16,
COMBAT_ENTER_RESPONSE = 17,
COMBAT_EXIT_REQUEST,
COMBAT_EXIT_RESPONSE,
COMBAT_EXIT_REQUEST = 18,
COMBAT_EXIT_RESPONSE = 19,
//TODO: COMBAT info
COMBAT_REJECTION,
COMBAT_REJECTION = 20,
//character data
//character data => etc.
CHARACTER_NEW,
CHARACTER_DELETE,
CHARACTER_UPDATE,
CHARACTER_NEW = 21,
CHARACTER_DELETE = 22,
CHARACTER_UPDATE = 23,
//authentication, character index => character stats
CHARACTER_STATS_REQUEST,
CHARACTER_STATS_RESPONSE,
CHARACTER_STATS_REQUEST= 24,
CHARACTER_STATS_RESPONSE = 25,
//character new => character rejection, disconnect?
CHARACTER_REJECTION,
CHARACTER_REJECTION = 26,
//enemy data
//enemy data => etc.
ENEMY_NEW,
ENEMY_DELETE,
ENEMY_UPDATE,
ENEMY_NEW = 27,
ENEMY_DELETE = 28,
ENEMY_UPDATE = 29,
ENEMY_STATS_REQUEST,
ENEMY_STATS_RESPONSE,
ENEMY_STATS_REQUEST = 30,
ENEMY_STATS_RESPONSE = 31,
//enemy index => enemy doens't exist
ENEMY_REJECTION,
ENEMY_REJECTION= 32,
//NOTE: more packet types go here
+14 -14
View File
@@ -56,7 +56,7 @@ void serializePacket(SerialPacketBase* packet, void* buffer) {
case SerialPacketType::CHARACTER_UPDATE:
case SerialPacketType::CHARACTER_STATS_REQUEST:
case SerialPacketType::CHARACTER_STATS_RESPONSE:
serializeCharacter(dynamic_cast<CharacterPacket*>(packet), buffer);
serializeCharacter(static_cast<CharacterPacket*>(packet), buffer);
break;
//client info
@@ -65,7 +65,7 @@ void serializePacket(SerialPacketBase* packet, void* buffer) {
case SerialPacketType::SYNCHRONIZE:
case SerialPacketType::DISCONNECT:
case SerialPacketType::SHUTDOWN:
serializeClient(dynamic_cast<ClientPacket*>(packet), buffer);
serializeClient(static_cast<ClientPacket*>(packet), buffer);
break;
//combat info
@@ -79,7 +79,7 @@ void serializePacket(SerialPacketBase* packet, void* buffer) {
case SerialPacketType::COMBAT_EXIT_REQUEST:
case SerialPacketType::COMBAT_EXIT_RESPONSE:
serializeCombat(dynamic_cast<CombatPacket*>(packet), buffer);
serializeCombat(static_cast<CombatPacket*>(packet), buffer);
break;
//enemy info
@@ -88,21 +88,21 @@ void serializePacket(SerialPacketBase* packet, void* buffer) {
case SerialPacketType::ENEMY_UPDATE:
case SerialPacketType::ENEMY_STATS_REQUEST:
case SerialPacketType::ENEMY_STATS_RESPONSE:
serializeEnemy(dynamic_cast<EnemyPacket*>(packet), buffer);
serializeEnemy(static_cast<EnemyPacket*>(packet), buffer);
break;
//region info
case SerialPacketType::REGION_REQUEST:
serializeRegionFormat(dynamic_cast<RegionPacket*>(packet), buffer);
serializeRegionFormat(static_cast<RegionPacket*>(packet), buffer);
break;
case SerialPacketType::REGION_CONTENT:
serializeRegionContent(dynamic_cast<RegionPacket*>(packet), buffer);
serializeRegionContent(static_cast<RegionPacket*>(packet), buffer);
break;
//server info
case SerialPacketType::BROADCAST_RESPONSE:
serializeServer(dynamic_cast<ServerPacket*>(packet), buffer);
serializeServer(static_cast<ServerPacket*>(packet), buffer);
break;
}
}
@@ -132,7 +132,7 @@ void deserializePacket(SerialPacketBase* packet, void* buffer) {
case SerialPacketType::CHARACTER_UPDATE:
case SerialPacketType::CHARACTER_STATS_REQUEST:
case SerialPacketType::CHARACTER_STATS_RESPONSE:
deserializeCharacter(dynamic_cast<CharacterPacket*>(packet), buffer);
deserializeCharacter(static_cast<CharacterPacket*>(packet), buffer);
break;
//client info
@@ -141,7 +141,7 @@ void deserializePacket(SerialPacketBase* packet, void* buffer) {
case SerialPacketType::SYNCHRONIZE:
case SerialPacketType::DISCONNECT:
case SerialPacketType::SHUTDOWN:
deserializeClient(dynamic_cast<ClientPacket*>(packet), buffer);
deserializeClient(static_cast<ClientPacket*>(packet), buffer);
break;
//combat info
@@ -155,7 +155,7 @@ void deserializePacket(SerialPacketBase* packet, void* buffer) {
case SerialPacketType::COMBAT_EXIT_REQUEST:
case SerialPacketType::COMBAT_EXIT_RESPONSE:
serializeCombat(dynamic_cast<CombatPacket*>(packet), buffer);
serializeCombat(static_cast<CombatPacket*>(packet), buffer);
break;
//enemy info
@@ -164,21 +164,21 @@ void deserializePacket(SerialPacketBase* packet, void* buffer) {
case SerialPacketType::ENEMY_UPDATE:
case SerialPacketType::ENEMY_STATS_REQUEST:
case SerialPacketType::ENEMY_STATS_RESPONSE:
serializeEnemy(dynamic_cast<EnemyPacket*>(packet), buffer);
serializeEnemy(static_cast<EnemyPacket*>(packet), buffer);
break;
//region info
case SerialPacketType::REGION_REQUEST:
deserializeRegionFormat(dynamic_cast<RegionPacket*>(packet), buffer);
deserializeRegionFormat(static_cast<RegionPacket*>(packet), buffer);
break;
case SerialPacketType::REGION_CONTENT:
deserializeRegionContent(dynamic_cast<RegionPacket*>(packet), buffer);
deserializeRegionContent(static_cast<RegionPacket*>(packet), buffer);
break;
//server info
case SerialPacketType::BROADCAST_RESPONSE:
deserializeServer(dynamic_cast<ServerPacket*>(packet), buffer);
deserializeServer(static_cast<ServerPacket*>(packet), buffer);
break;
}
}
+1 -2
View File
@@ -3,8 +3,7 @@
#MKDIR=mkdir
#RM=del /y
CXXFLAGS+=-static-libgcc -static-libstdc++
CFLAGS+=-static-libgcc
CXXFLAGS+=-static-libgcc -static-libstdc++ -g
export
+8 -11
View File
@@ -36,16 +36,6 @@ static const char* DELETE_USER_ACCOUNT = "DELETE FROM Accounts WHERE uid = ?;";
//Define the public methods
//-------------------------
AccountManager::AccountManager() {
//
}
AccountManager::~AccountManager() {
for (auto& it : accountMap) {
SaveAccount(it.first);
}
}
int AccountManager::CreateAccount(std::string username, int clientIndex) {
//create this user account, failing if it exists, leave this account in memory
sqlite3_stmt* statement = nullptr;
@@ -202,6 +192,13 @@ void AccountManager::DeleteAccount(int uid) {
accountMap.erase(uid);
}
void AccountManager::UnloadAll() {
for (auto& it : accountMap) {
SaveAccount(it.first);
}
accountMap.clear();
}
//-------------------------
//Define the accessors and mutators
//-------------------------
@@ -226,4 +223,4 @@ sqlite3* AccountManager::SetDatabase(sqlite3* db) {
sqlite3* AccountManager::GetDatabase() {
return database;
}
}
+4 -2
View File
@@ -30,8 +30,8 @@
class AccountManager {
public:
AccountManager();
~AccountManager();
AccountManager() = default;
~AccountManager() { UnloadAll(); };
//public access methods
int CreateAccount(std::string username, int clientIndex);
@@ -40,6 +40,8 @@ public:
void UnloadAccount(int uid);
void DeleteAccount(int uid);
void UnloadAll();
//accessors and mutators
AccountData* GetAccount(int uid);
std::map<int, AccountData>* GetContainer();
+7 -10
View File
@@ -58,16 +58,6 @@ static const char* DELETE_CHARACTER = "DELETE FROM Characters WHERE uid = ?;";
//Define the methods
//-------------------------
CharacterManager::CharacterManager() {
//
}
CharacterManager::~CharacterManager() {
for (auto& it : characterMap) {
SaveCharacter(it.first);
}
}
//TODO: default stats as a parameter? This would be good for differing beggining states or multiple classes
int CharacterManager::CreateCharacter(int owner, std::string handle, std::string avatar) {
//Create the character, failing if it exists
@@ -294,6 +284,13 @@ void CharacterManager::UnloadCharacterIf(std::function<bool(std::map<int, Charac
}
}
void CharacterManager::UnloadAll() {
for (auto& it : characterMap) {
SaveCharacter(it.first);
}
characterMap.clear();
}
//-------------------------
//Define the accessors and mutators
//-------------------------
+4 -2
View File
@@ -31,8 +31,8 @@
class CharacterManager {
public:
CharacterManager();
~CharacterManager();
CharacterManager() = default;
~CharacterManager() { UnloadAll(); };
//public access methods
int CreateCharacter(int owner, std::string handle, std::string avatar);
@@ -43,6 +43,8 @@ public:
void UnloadCharacterIf(std::function<bool(std::map<int, CharacterData>::iterator)> f);
void UnloadAll();
//accessors and mutators
CharacterData* GetCharacter(int uid);
std::map<int, CharacterData>* GetContainer();
+7 -7
View File
@@ -23,19 +23,19 @@
#define ROOMDATA_HPP_
//map system
#include "region_pager.hpp"
#include "region_pager_lua.hpp"
struct RoomData {
enum class RoomType {
OVERWORLD,
RUINS,
TOWERS,
FORESTS,
CAVES,
OVERWORLD = 0,
RUINS = 1,
TOWERS = 2,
FORESTS = 3,
CAVE = 4,
};
//members
RegionPager pager;
RegionPagerLua pager;
RoomType type;
//TODO: collision map
+35 -17
View File
@@ -21,34 +21,52 @@
*/
#include "room_manager.hpp"
#include <stdexcept>
//-------------------------
//public access methods
//-------------------------
//TODO
RoomData* RoomManager::CreateRoom(int uid) {
//don't overwrite existing rooms
std::map<int, RoomData*>::iterator it = roomMap.find(uid);
if (it != roomMap.end()) {
throw(std::runtime_error("Cannot overwrite an existing room"));
}
roomMap[uid] = new RoomData();
//TODO: create room in the API
if (luaState) {
roomMap[uid]->pager.SetLuaState(luaState);
}
return roomMap[uid];
}
//-------------------------
//accessors and mutators
//-------------------------
RoomData* RoomManager::UnloadRoom(int uid) {
//TODO: unload room in the API
delete roomMap[uid];
roomMap.erase(uid);
}
RoomData* RoomManager::GetRoom(int uid) {
std::map<int, RoomData>::iterator it = roomMap.find(uid);
RoomData* ptr = FindRoom(uid);
if (ptr) return ptr;
ptr = CreateRoom(uid);
return ptr;
}
RoomData* RoomManager::FindRoom(int uid) {
std::map<int, RoomData*>::iterator it = roomMap.find(uid);
if (it == roomMap.end()) {
return nullptr;
}
return &it->second;
return it->second;
}
std::map<int, RoomData>* RoomManager::GetContainer() {
return &roomMap;
}
lua_State* RoomManager::SetLuaState(lua_State* L) {
return luaState = L;
}
lua_State* RoomManager::GetLuaState() {
return luaState;
RoomData* RoomManager::PushRoom(int uid, RoomData* room) {
//unload existing rooms with this index
std::map<int, RoomData*>::iterator it = roomMap.find(uid);
if (it != roomMap.end()) {
UnloadRoom(uid);
}
roomMap[uid] = room;
}
+10 -6
View File
@@ -36,17 +36,21 @@ public:
~RoomManager() = default;
//public access methods
//TODO: Fill this out
RoomData* CreateRoom(int uid);
RoomData* UnloadRoom(int uid);
RoomData* GetRoom(int uid);
RoomData* FindRoom(int uid);
RoomData* PushRoom(int uid, RoomData*);
//accessors and mutators
RoomData* GetRoom(int uid);
std::map<int, RoomData>* GetContainer();
std::map<int, RoomData*>* GetContainer() { return &roomMap; }
lua_State* SetLuaState(lua_State*);
lua_State* GetLuaState();
lua_State* SetLuaState(lua_State* L) { return luaState = L; }
lua_State* GetLuaState() { return luaState; }
private:
std::map<int, RoomData> roomMap;
std::map<int, RoomData*> roomMap;
lua_State* luaState = nullptr;
};
+29 -20
View File
@@ -117,7 +117,7 @@ void ServerApplication::Init(int argc, char** argv) {
std::cout << "\tTile Size: " << sizeof(Region::type_t) << std::endl;
std::cout << "\tRegion Format: " << REGION_WIDTH << ", " << REGION_HEIGHT << ", " << REGION_DEPTH << std::endl;
std::cout << "\tRegion Content Footprint: " << REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) << std::endl;
std::cout << "\tPACKET_BUFFER_SIZE (max size): " << PACKET_BUFFER_SIZE << std::endl;
std::cout << "\tPACKET_BUFFER_SIZE: " << PACKET_BUFFER_SIZE << std::endl;
std::cout << "\tMAX_PACKET_SIZE: " << MAX_PACKET_SIZE << std::endl;
//-------------------------
@@ -134,22 +134,31 @@ void ServerApplication::Init(int argc, char** argv) {
}
void ServerApplication::Proc() {
char packetBuffer[MAX_PACKET_SIZE];
SerialPacket* packetBuffer = static_cast<SerialPacket*>(malloc(MAX_PACKET_SIZE));
while(running) {
//suck in the waiting packets & process them
while(network.Receive(reinterpret_cast<SerialPacket*>(packetBuffer))) {
HandlePacket(reinterpret_cast<SerialPacket*>(packetBuffer));
while(network.Receive(packetBuffer)) {
HandlePacket(packetBuffer);
}
//update the internals
//TODO: update the internals i.e. player positions
//give the computer a break
SDL_Delay(10);
}
free(static_cast<void*>(packetBuffer));
}
void ServerApplication::Quit() {
std::cout << "Shutting down" << std::endl;
//close the managers
clientMap.clear();
accountMgr.UnloadAll();
characterMgr.UnloadAll();
//TODO: unload combats
//TODO: unload enemies
//TODO: unload rooms
//APIs
lua_close(luaState);
sqlite3_close_v2(database);
@@ -168,21 +177,21 @@ void ServerApplication::HandlePacket(SerialPacket* const argPacket) {
switch(argPacket->type) {
//basic connections
case SerialPacketType::BROADCAST_REQUEST:
HandleBroadcastRequest(dynamic_cast<SerialPacket*>(argPacket));
HandleBroadcastRequest(static_cast<SerialPacket*>(argPacket));
break;
case SerialPacketType::JOIN_REQUEST:
HandleJoinRequest(dynamic_cast<ClientPacket*>(argPacket));
HandleJoinRequest(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::DISCONNECT:
HandleDisconnect(dynamic_cast<ClientPacket*>(argPacket));
HandleDisconnect(static_cast<ClientPacket*>(argPacket));
break;
case SerialPacketType::SHUTDOWN:
HandleShutdown(dynamic_cast<SerialPacket*>(argPacket));
HandleShutdown(static_cast<SerialPacket*>(argPacket));
break;
//map management
case SerialPacketType::REGION_REQUEST:
HandleRegionRequest(dynamic_cast<RegionPacket*>(argPacket));
HandleRegionRequest(static_cast<RegionPacket*>(argPacket));
break;
//combat management
@@ -190,14 +199,14 @@ void ServerApplication::HandlePacket(SerialPacket* const argPacket) {
//character management
case SerialPacketType::CHARACTER_NEW:
HandleCharacterNew(dynamic_cast<CharacterPacket*>(argPacket));
HandleCharacterNew(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_DELETE:
HandleCharacterDelete(dynamic_cast<CharacterPacket*>(argPacket));
HandleCharacterDelete(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_UPDATE:
case SerialPacketType::CHARACTER_STATS_REQUEST:
HandleCharacterUpdate(dynamic_cast<CharacterPacket*>(argPacket));
HandleCharacterUpdate(static_cast<CharacterPacket*>(argPacket));
break;
//enemy management
@@ -205,12 +214,12 @@ void ServerApplication::HandlePacket(SerialPacket* const argPacket) {
//mismanagement
case SerialPacketType::SYNCHRONIZE:
HandleSynchronize(dynamic_cast<ClientPacket*>(argPacket));
HandleSynchronize(static_cast<ClientPacket*>(argPacket));
break;
//handle errors
default:
throw(std::runtime_error(std::string() + "Unknown SerialPacketType encountered in the server: " + to_string_custom(int(argPacket->type))));
throw(std::runtime_error(std::string() + "Unknown SerialPacketType encountered in the server: " + to_string_custom(static_cast<int>(argPacket->type)) ));
break;
}
}
@@ -228,7 +237,7 @@ void ServerApplication::HandleBroadcastRequest(SerialPacket* const argPacket) {
newPacket.playerCount = characterMgr.GetContainer()->size();
newPacket.version = NETWORK_VERSION;
network.SendTo(&argPacket->srcAddress, dynamic_cast<SerialPacket*>(&newPacket));
network.SendTo(&argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
}
void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) {
@@ -251,7 +260,7 @@ void ServerApplication::HandleJoinRequest(ClientPacket* const argPacket) {
newPacket.clientIndex = clientUID;
newPacket.accountIndex = accountIndex;
network.SendTo(&newClient.address, dynamic_cast<SerialPacket*>(&newPacket));
network.SendTo(&newClient.address, static_cast<SerialPacket*>(&newPacket));
//finished this routine
clientMap[clientUID++] = newClient;
@@ -264,7 +273,7 @@ void ServerApplication::HandleDisconnect(ClientPacket* const argPacket) {
//forward to the specified client
network.SendTo(
&clientMap[ accountMgr.GetAccount(argPacket->accountIndex)->clientIndex ].address,
dynamic_cast<SerialPacket*>(argPacket)
static_cast<SerialPacket*>(argPacket)
);
//save and unload this account's characters
@@ -315,7 +324,7 @@ void ServerApplication::HandleRegionRequest(RegionPacket* const argPacket) {
newPacket.region = roomMgr.GetRoom(argPacket->roomIndex)->pager.GetRegion(argPacket->x, argPacket->y);
//send the content
network.SendTo(&argPacket->srcAddress, dynamic_cast<SerialPacket*>(argPacket));
network.SendTo(&argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
}
//-------------------------
@@ -435,7 +444,7 @@ void ServerApplication::HandleSynchronize(ClientPacket* const argPacket) {
for (auto& it : *characterMgr.GetContainer()) {
newPacket.characterIndex = it.first;
CopyCharacterToPacket(&newPacket, it.first);
network.SendTo(&client.address, dynamic_cast<SerialPacket*>(&newPacket));
network.SendTo(&client.address, static_cast<SerialPacket*>(&newPacket));
}
//TODO: more in HandleSynchronize()
@@ -458,7 +467,7 @@ void ServerApplication::PumpCharacterUnload(int uid) {
CharacterPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_DELETE;
newPacket.characterIndex = uid;
PumpPacket(dynamic_cast<SerialPacket*>(&newPacket));
PumpPacket(static_cast<SerialPacket*>(&newPacket));
}
void ServerApplication::CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex) {
+1 -1
View File
@@ -1,5 +1,5 @@
TODO: encapsulate the data structures
TODO: Get the rooms working
TODO: update the map API to handle multiple rooms
TODO: Rejection packets
TODO: Authentication