Compare commits

..

75 Commits

Author SHA1 Message Date
Kayne Ruse c534158c2e Merge branch 'login' (read more)
This branch was originally intended to rewrite the login system, but I've discovered some serious problems that could not wait. See the previous commit for more information. Hopefully I can get back to this soon.

I believe this version deserves a new release tag.
2014-04-21 04:00:37 +10:00
Kayne Ruse b47191a0c1 Fixed a horrible region coordinate bug
Coordinates are supposed to be stored by their x & y, but the sizes of the
tile sheets were getting mixed in as well. When trying to store a region
at (0, 20), it was being stored at (0, 260).

Another visual bug inside the tile sheet's rendering function masked this
issue until now.

Another thing to note is that I've removed an incredibly complex system
for updating the client's map. The new system may seem complex at first,
but it is straight forward compared to what it replaced.

I've also fixed a few logarithmic lagging points in the code.
2014-04-21 03:56:48 +10:00
Kayne Ruse 6c6a025f2a Adjusted a few comments 2014-04-21 02:13:00 +10:00
Kayne Ruse 60edc97ea5 Added rejections for incompatible servers 2014-04-21 01:38:28 +10:00
Kayne Ruse a5b209d9e0 Merge branch 'login' (read more)
Made a few tweaks to the code, but the build still works, so I'm merging it into master.
2014-04-21 01:02:38 +10:00
Kayne Ruse fd673a415f Removed singleton pattern 2014-04-21 01:01:00 +10:00
Kayne Ruse 4270765146 Renamed NetworkPacket to SerialPacket, updated build 2014-04-20 23:54:59 +10:00
Kayne Ruse f56cb58dfb Revised SQL setup script, and the script function 2014-04-20 23:11:46 +10:00
Kayne Ruse f315f4bf35 Merge branch 'map' (read more)
After refactoring the map system, this new build uses the preprocessor macros to define the sizes of each region object. These macros, which are defined in region.hpp, were being used anyway; these modifications simply speed up the process by cutting out a lot of the fat.
2014-04-20 05:41:49 +10:00
Kayne Ruse 69765de433 Removed the TODO file; I think it's fairly stable again 2014-04-20 05:34:15 +10:00
Kayne Ruse 35d463d4ba Removed some annoying debugging messages 2014-04-20 05:30:08 +10:00
Kayne Ruse 894b46c5db Found the error in the format functor
I shouldn't automatically guess where an error is, since this project is
so complex.
2014-04-20 05:14:25 +10:00
Kayne Ruse eb0b18af6f Brought the programs into line, (BUG, read more)
It seems that the serialization code has a bug in it. I was expecting
something like this. When the server tries to send the region content, it
exits. I'll try and find the cause of the error, but I'm committing my
changes anyway.
2014-04-20 04:41:06 +10:00
Kayne Ruse fba183fa27 Brought the common/ directory up to date with the region's preprocessors
I really hope the serialization code still works.
2014-04-20 04:02:26 +10:00
Kayne Ruse c5a627004a Refactored the map system (read more)
The region's width, height and depth are all defined by preprocessor
macros. The rest of the map system has been updated to match. The
programs proper need to be updated as well. It would be a good idea to
include the macros' values as part of the initial communication protocols,
so that the clients don't connect to a server that is using the wrong
sized regions.
2014-04-20 03:41:08 +10:00
Kayne Ruse ac27fb0ca7 Found a list of TODO comments 2014-04-20 02:40:06 +10:00
Kayne Ruse be4a8311d5 Adjusted a few comments 2014-04-20 02:39:29 +10:00
Kayne Ruse 6d32d44fa3 Reverted some of the changes, stable 2014-04-15 23:23:15 +10:00
Kayne Ruse 9bacfb1424 Merge branch 'entity' (early part) (read more)
I've had some issues with the entity system I created, so I'm trying to
revert it right now, while also retaining the other few tweaks I've made.
2014-04-15 22:40:07 +10:00
Kayne Ruse c3464be589 The server is working correctly, using the entity system 2014-04-13 22:20:30 +10:00
Kayne Ruse 7fe71c60d0 This will not build; working on refactoring 2014-04-13 03:49:35 +10:00
Kayne Ruse 0c6537fb36 Began work on the server's generic entity system 2014-04-13 03:02:26 +10:00
Kayne Ruse 854dc0eb45 Added a link to the stable build 2014-04-08 21:24:49 +10:00
Kayne Ruse e90afb7e4a Merge branch 'net-map' 2014-04-08 21:13:17 +10:00
Kayne Ruse 0453f6becf The map paging is functional 2014-04-07 02:56:48 +10:00
Kayne Ruse c8a58ab515 Wrote a potentially buggy algorithm
This algorithm is designed to find the distance of a certain region,
however it may have been better to do a quick check, rather than worrying
how many regions were loaded at once.
2014-04-07 01:24:05 +10:00
Kayne Ruse 553f8dbfa5 Fixed some framerate issues 2014-04-06 20:53:51 +10:00
Kayne Ruse 2bacdcdab7 The basic server map is being displayed in the client 2014-04-06 03:38:58 +10:00
Kayne Ruse 99aecbfdbb The client->server->client region protocol is working 2014-04-06 02:48:43 +11:00
Kayne Ruse 27bda5dc28 Working on the client side map code (read more)
I've also added in some debug code to the map classes, because I was
hunting down a std::bad_alloc beingthrown. Turns out I forgot to set the
map sizes in the client's InWorld constructor. I'm committing the fix, and
the debug code.
2014-04-06 02:25:55 +11:00
Kayne Ruse 962f3f5dd0 Added "camera" 2014-04-05 01:56:05 +11:00
Kayne Ruse 41077b43b3 Merge branch 'network-map' 2014-03-31 21:54:22 +11:00
Kayne Ruse 4410ab892f Finished the region serial code 2014-03-31 21:40:50 +11:00
Kayne Ruse 60000cb0cf Minor tweak 2014-03-31 03:38:05 +11:00
Kayne Ruse 66b00255d5 Merge branch 'lua-api' into network-map 2014-03-31 01:32:39 +11:00
Kayne Ruse a5b68cf1fd Expaneded the lua API for Regions
I've added lua hooks for both pager functor classes. Hopefully, I haven't
missed any corner cases, because it took me a while to hunt everything
down. One issue is that the map's save directory needs to be set in the
Format class, but it'll do for now. I'll review this again when I've got
more than one map running at one time.

There should be enough here for a lua-driven map generator to be
implemented, even if it's a bit rough. I think I'll test this out in the
editor eventually, but getting the base branch's network map code going
comes first.

The current process is extremely convulted, so I need to document
everything that I've done so far, including C++ and lua functions.
2014-03-31 01:30:11 +11:00
Kayne Ruse 4cff57fe71 Established a connection between the Region objects and lua 2014-03-28 04:11:34 +11:00
Kayne Ruse 38b603fc8f Began working on the lua API for the map
The basic framework is done.
2014-03-28 03:24:14 +11:00
Kayne Ruse 47684380a9 I'm having trouble with the sequence of events 2014-03-26 00:30:10 +11:00
Kayne Ruse e4bfbfb906 Minor code tweaks, this needs a lot of forethought 2014-03-16 00:28:19 +11:00
Kayne Ruse 9db86c19f6 Implemented a macro for the serial buffer size 2014-03-15 23:36:31 +11:00
Kayne Ruse d5b551cec3 Reduced the footprint of the tiles
Also prepping for serializing the regions.
2014-03-15 23:02:21 +11:00
Kayne Ruse 7e500027e3 Loosened the requirements for constructing a MapPager
This is so that I can configure the size of the pages in the config.cfg
file.
2014-03-15 19:16:42 +11:00
Kayne Ruse dd786ba579 Merge branch 'server' (read more)
The only different between this commit and the currently stable branch is the
serialization code and a slight tweak to the server's startup sequence. I tried
to refactor the server, by moving the clientMap and playerMap into their own
wrapper classes, but that failed miserably. I need to stop getting so worked up
all the time, I've wasted way too much time already.
2014-03-11 19:04:32 +11:00
Kayne Ruse 5a57888305 Fixed the crash bug 2014-03-11 18:54:06 +11:00
Kayne Ruse 706aa5e1d7 Another worthless tweak 2014-03-10 23:56:47 +11:00
Kayne Ruse 19c1b1197d Added a brand new bug, I hate this branch 2014-03-10 23:15:57 +11:00
Kayne Ruse 5cf62f5517 Nothing special, just commiting minor changes 2014-03-09 01:51:17 +11:00
Kayne Ruse 56d02ad8d4 Working on reimplementing the player characters
I've also added EraseIf() to the manager classes.
2014-03-07 22:09:50 +11:00
Kayne Ruse 006a72174f Merge branch 'master' into server 2014-03-07 21:05:09 +11:00
Kayne Ruse 0cbc9dd9db Merge branch 'serial' into server (read more)
Conflicts:
	server/server_application.cpp (resolved)

After completing the serialization code, I'm merging it into the server's
development branch. This means that although the connection and
disconnection functionality work, I still need to test the player systems
from the new server with the new serialization code.

Immediately following this commit, I'll be merging the minor tweaks to the
editor from the master branch into this one.
2014-03-07 20:58:37 +11:00
Kayne Ruse 60c31ff56d Slight code tweak 2014-03-07 20:27:34 +11:00
Kayne Ruse 6a204643f6 Serialization is finally functional 2014-03-07 20:17:11 +11:00
Kayne Ruse 59285d1630 This isn't fucking working 2014-03-07 04:49:16 +11:00
Kayne Ruse a850d6b1af Added dummy serialization functions 2014-03-06 00:20:31 +11:00
Kayne Ruse f17fa0f345 Added lua, added db connection to PlayerManager
I've also revised the startup process a bit.
2014-03-05 00:27:21 +11:00
Kayne Ruse 756d4e770d Connection and disconnection are working correctly
I've dummied out the player code, so only the client connection code is
working. Otherwise the protocol hasn't changed.

I've also made a few other tweaks as I went along, but nothing really
major.
2014-03-04 02:48:47 +11:00
Kayne Ruse 7bb5e8ce0d Moving client and player data into manager classes
Remember: anything with "manager" in its name organizes a number of other
objects, as far as I'm concerned.

I'll eventually have a database connection in the PlayerManager class;
this'll make it easier to manage the database.
2014-03-02 23:20:37 +11:00
Kayne Ruse 975533afba Minor tweak to the editor's menu bar 2014-03-01 23:58:06 +11:00
Kayne Ruse 19749f7c87 Added grey highlighting to the debug text 2014-03-01 03:31:46 +11:00
Kayne Ruse 7703c4b0ad Merge branch 'master' into stable
Even though some parts of the new map system are a stub, I feel confident
enough to merge this branch back onto the stable branch.

On the whole, I've reduced the complexity of the system, while also allowing
acceptable restrictions.

The RegionPager class works correctly. The Update() member is empty, but it's
still usable.

I've removed TileSheetManager, so the maps can only have one tileset each;
that's fine.

The tiles are voxel integers.

The editor needs an entire overhaul. I think some of the GUI components
are too complex. The sooner I can implement the map in the main
client/server system the better.
2014-03-01 00:48:19 +11:00
Kayne Ruse dc8f594eec Tested RegionPager, removed trace statements, fixed logic errors 2014-03-01 00:39:39 +11:00
Kayne Ruse 4629b7302b Fixed Region's internals 2014-02-28 23:14:22 +11:00
Kayne Ruse 02d83d1f16 BUG: Region's memory isn't being zeroed by the looks of it 2014-02-28 03:41:03 +11:00
Kayne Ruse 91c9cef56d Working on the TileSheet class 2014-02-28 03:40:18 +11:00
Kayne Ruse f7d4912942 Merge branch 'stable' 2014-02-24 01:41:40 +11:00
Kayne Ruse eb8674b84f Moved the technical document 2014-02-24 01:41:21 +11:00
Kayne Ruse ff44e4d916 Merge branch 'stable' 2014-02-24 01:14:16 +11:00
Kayne Ruse e66540f114 Updated README 2014-02-24 01:12:42 +11:00
Kayne Ruse 639c0c70e3 RegionPager can now be instanciated with template parameters
* Fixed Region::GetX() and Region::GetY()
* Replaced calls to std::find_if with regular for loops
* Changed typing of RegionPager::regionList
** regionList now holds pointers rather than the objects themselves
* Added vestigial classes MapFileFormat and MapGenerator
** MapGenerator creates and destroys the region objects
* I'm leaving in the debugging code for now
** This includes trace statements and a basterdized main() function in
/editor/main.cpp
2014-02-24 00:34:02 +11:00
Kayne Ruse 37b02352e2 Fleshed out inherited functions
TODO:
* RegionPagerBase::Update() is a stub
* MapFileFormat
* MapGenerator
* Can replace the calls to std::find_if() with a utility function
2014-02-23 03:08:37 +11:00
Kayne Ruse 31c8bd7fd2 Split the pager class into two
I've also made the base class abstract, and the derived class a template.
Hopefully this'll let me work on different parts of the class without
major issues.

This code compiles, but since it's incomplete, I can't test it properly.
2014-02-21 03:42:02 +11:00
Kayne Ruse 808fe570a3 Added empty RegionPager 2014-02-18 01:18:04 +11:00
Kayne Ruse e706cc9d13 Completed a simple region class 2014-02-15 20:06:20 +11:00
Kayne Ruse eb02cc4b6a Removed the old map system from the editor 2014-02-11 21:56:45 +11:00
60 changed files with 2068 additions and 1117 deletions
+5 -5
View File
@@ -1,6 +1,6 @@
You can find the [latest nightly build here](https://dl.dropboxusercontent.com/u/46669050/Tortuga.rar). The most recent stable windows build can be found [here](https://dl.dropboxusercontent.com/u/46669050/Tortuga.rar).
Tortuga is an open source 2D multiplayer role playing game featuring permadeath (deletion of a character upon death). The emphasis of this game is on multiplayer cooperation, competition, and customization. The game runs on customizable server software that can support up to 150 simultaneous players or more. Tortuga is an open source 2D multiplayer role playing game featuring permadeath (deletion of a character upon death). The emphasis of this game is on multiplayer cooperation, competition, exploration and customization. The game runs on customizable server software that can support up to 150 simultaneous players or more.
This game is inspired by classic 2D RPGs, as well as more modern sandbox MMOs. This project is currently independently created and funded, with the goal of creating a game that will engage user's imagination and inspire a large modding community. This game is inspired by classic 2D RPGs, as well as more modern sandbox MMOs. This project is currently independently created and funded, with the goal of creating a game that will engage user's imagination and inspire a large modding community.
@@ -13,14 +13,14 @@ This game is inspired by classic 2D RPGs, as well as more modern sandbox MMOs. T
## Documentation ## Documentation
[Tortuga Game Design Document](https://docs.google.com/document/d/17SjOTdacKKWX0Z-UkaiFnVnjfEeMsc5LRmARtnjh5UI/edit?usp=sharing) [Tortuga Game Design Document](https://github.com/Ratstail91/Tortuga/blob/docs/design%20doc.docx?raw=true)
[Tortuga Technical Document](https://docs.google.com/document/d/1ASTfM_1e0yE1cFP-IZey_rHEC6k2kmVY56X4K407sw0/edit?usp=sharing) [Tortuga Technical Document](https://github.com/Ratstail91/Tortuga/blob/docs/technical%20doc.docx?raw=true)
## Copyright ## Copyright
The current version of Tortuga is released under the [zlib license](http://en.wikipedia.org/wiki/Zlib_License). The current version of Tortuga is released under the [zlib license](http://en.wikipedia.org/wiki/Zlib_License).
Copyright (c) 2013 Kayne Ruse Copyright (c) 2013, 2014 Kayne Ruse
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. 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.
+7 -24
View File
@@ -21,15 +21,11 @@
*/ */
#include "client_application.hpp" #include "client_application.hpp"
#include "serial.hpp"
#include <stdexcept> #include <stdexcept>
#include <chrono> #include <chrono>
//-------------------------
//Static declarations
//-------------------------
ClientApplication ClientApplication::instance;
//------------------------- //-------------------------
//Scene headers //Scene headers
//------------------------- //-------------------------
@@ -46,15 +42,7 @@ ClientApplication ClientApplication::instance;
//Public access members //Public access members
//------------------------- //-------------------------
ClientApplication::ClientApplication() { void ClientApplication::Init(int argc, char** argv) {
//
}
ClientApplication::~ClientApplication() {
//
}
void ClientApplication::Init() {
//load the prerequisites //load the prerequisites
config.Load("rsc\\config.cfg"); config.Load("rsc\\config.cfg");
@@ -62,13 +50,13 @@ void ClientApplication::Init() {
if (SDL_Init(SDL_INIT_VIDEO)) { if (SDL_Init(SDL_INIT_VIDEO)) {
throw(std::runtime_error("Failed to initialize SDL")); throw(std::runtime_error("Failed to initialize SDL"));
} }
BaseScene::SetScreen(config.Int("screen.w"), config.Int("screen.h"), 0, (config.Bool("screen.f")) ? SDL_HWSURFACE|SDL_DOUBLEBUF : SDL_HWSURFACE); BaseScene::SetScreen(config.Int("screen.w"), config.Int("screen.h"), 0, (config.Bool("screen.f")) ? SDL_HWSURFACE|SDL_DOUBLEBUF|SDL_FULLSCREEN : SDL_HWSURFACE|SDL_DOUBLEBUF);
//initialize SDL_net //initialize SDL_net
if (SDLNet_Init()) { if (SDLNet_Init()) {
throw(std::runtime_error("Failed to initialize SDL_net")); throw(std::runtime_error("Failed to initialize SDL_net"));
} }
network.Open(0, sizeof(NetworkPacket)); network.Open(0, PACKET_BUFFER_SIZE);
} }
void ClientApplication::Proc() { void ClientApplication::Proc() {
@@ -77,7 +65,7 @@ void ClientApplication::Proc() {
//prepare the time system //prepare the time system
typedef std::chrono::steady_clock Clock; typedef std::chrono::steady_clock Clock;
Clock::duration delta(16 * Clock::duration::period::den / std::milli::den); std::chrono::duration<int, std::milli> delta(16);
Clock::time_point simTime = Clock::now(); Clock::time_point simTime = Clock::now();
Clock::time_point realTime; Clock::time_point realTime;
@@ -95,15 +83,12 @@ void ClientApplication::Proc() {
//simulate game time //simulate game time
while (simTime < realTime) { while (simTime < realTime) {
//call each user defined function //call each user defined function
activeScene->RunFrame(double(delta.count()) / Clock::duration::period::den); activeScene->RunFrame(double(delta.count()) / std::chrono::duration<int, std::milli>::period::den);
simTime += delta; simTime += delta;
} }
//draw the game to the screen //draw the game to the screen
activeScene->RenderFrame(); activeScene->RenderFrame();
//give the computer a break
SDL_Delay(10);
} }
UnloadScene(); UnloadScene();
@@ -121,7 +106,6 @@ void ClientApplication::Quit() {
void ClientApplication::LoadScene(SceneList sceneIndex) { void ClientApplication::LoadScene(SceneList sceneIndex) {
UnloadScene(); UnloadScene();
switch(sceneIndex) { switch(sceneIndex) {
//add scene creation calls here //add scene creation calls here
case SceneList::FIRST: case SceneList::FIRST:
@@ -143,7 +127,6 @@ void ClientApplication::LoadScene(SceneList sceneIndex) {
case SceneList::INCOMBAT: case SceneList::INCOMBAT:
activeScene = new InCombat(); activeScene = new InCombat();
break; break;
default: default:
throw(std::logic_error("Failed to recognize the scene index")); throw(std::logic_error("Failed to recognize the scene index"));
} }
+3 -8
View File
@@ -26,19 +26,14 @@
#include "base_scene.hpp" #include "base_scene.hpp"
#include "config_utility.hpp" #include "config_utility.hpp"
#include "network_packet.hpp"
#include "udp_network_utility.hpp" #include "udp_network_utility.hpp"
class ClientApplication { class ClientApplication {
private:
ClientApplication();
~ClientApplication();
static ClientApplication instance;
public: public:
static ClientApplication* GetInstance() { return &instance; } ClientApplication() = default;
~ClientApplication() = default;
void Init(); void Init(int argc, char** argv);
void Proc(); void Proc();
void Quit(); void Quit();
+5 -4
View File
@@ -26,12 +26,13 @@
using namespace std; using namespace std;
int main(int, char**) { int main(int argc, char** argv) {
cout << "Beginning client" << endl; cout << "Beginning client" << endl;
try { try {
ClientApplication::GetInstance()->Init(); ClientApplication app;
ClientApplication::GetInstance()->Proc(); app.Init(argc, argv);
ClientApplication::GetInstance()->Quit(); app.Proc();
app.Quit();
} }
catch(exception& e) { catch(exception& e) {
cerr << "Fatal exception thrown: " << e.what() << endl; cerr << "Fatal exception thrown: " << e.what() << endl;
+2 -1
View File
@@ -25,6 +25,7 @@
#include "vector2.hpp" #include "vector2.hpp"
#include "sprite_sheet.hpp" #include "sprite_sheet.hpp"
//TODO: correct the PlayerCharacter class and it's movement system
class PlayerCharacter { class PlayerCharacter {
public: public:
enum class Direction { enum class Direction {
@@ -36,7 +37,7 @@ public:
void Update(double delta); void Update(double delta);
void DrawTo(SDL_Surface* const dest) { sprite.DrawTo(dest, position.x, position.y); } void DrawTo(SDL_Surface* const dest, int camX, int camY) { sprite.DrawTo(dest, position.x - camX, position.y - camY); }
//clunky code results in smooth movement and controls //clunky code results in smooth movement and controls
void AdjustDirection(Direction); void AdjustDirection(Direction);
+166 -41
View File
@@ -23,6 +23,8 @@
#include "channels.hpp" #include "channels.hpp"
#include <algorithm>
#include <cmath>
#include <stdexcept> #include <stdexcept>
//------------------------- //-------------------------
@@ -35,29 +37,34 @@ InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNet
clientIndex(*argClientIndex) clientIndex(*argClientIndex)
{ {
//setup the utility objects //setup the utility objects
image.LoadSurface(config["dir.interface"] + "button_menu.bmp"); buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp");
image.SetClipH(image.GetClipH()/3); buttonImage.SetClipH(buttonImage.GetClipH()/3);
font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp"); font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp");
//pass the utility objects //pass the utility objects
disconnectButton.SetImage(&image); disconnectButton.SetImage(&buttonImage);
disconnectButton.SetFont(&font); disconnectButton.SetFont(&font);
shutDownButton.SetImage(&image); shutDownButton.SetImage(&buttonImage);
shutDownButton.SetFont(&font); shutDownButton.SetFont(&font);
//set the button positions //set the button positions
disconnectButton.SetX(50); disconnectButton.SetX(50);
disconnectButton.SetY(50 + image.GetClipH() * 0); disconnectButton.SetY(50 + buttonImage.GetClipH() * 0);
shutDownButton.SetX(50); shutDownButton.SetX(50);
shutDownButton.SetY(50 + image.GetClipH() * 1); shutDownButton.SetY(50 + buttonImage.GetClipH() * 1);
//set the button texts //set the button texts
disconnectButton.SetText("Disconnect"); disconnectButton.SetText("Disconnect");
shutDownButton.SetText("Shut Down"); shutDownButton.SetText("Shut Down");
//load the tilesheet
//TODO: add the tilesheet to the map system?
tileSheet.Load(config["dir.tilesets"] + "terrain.bmp", 12, 15);
//create the server-side player object //create the server-side player object
NetworkPacket packet; //TODO: the login system needs an overhaul
packet.meta.type = NetworkPacket::Type::PLAYER_NEW; SerialPacket packet;
packet.meta.type = SerialPacket::Type::PLAYER_NEW;
packet.playerInfo.clientIndex = clientIndex; packet.playerInfo.clientIndex = clientIndex;
snprintf(packet.playerInfo.handle, PACKET_STRING_SIZE, "%s", config["player.handle"].c_str()); snprintf(packet.playerInfo.handle, PACKET_STRING_SIZE, "%s", config["player.handle"].c_str());
snprintf(packet.playerInfo.avatar, PACKET_STRING_SIZE, "%s", config["player.avatar"].c_str()); snprintf(packet.playerInfo.avatar, PACKET_STRING_SIZE, "%s", config["player.avatar"].c_str());
@@ -65,11 +72,17 @@ InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNet
packet.playerInfo.motion = {0,0}; packet.playerInfo.motion = {0,0};
//send it //send it
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket)); char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
//request a sync //request a sync
packet.meta.type = NetworkPacket::Type::SYNCHRONIZE; packet.meta.type = SerialPacket::Type::SYNCHRONIZE;
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket)); serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
//debug
// RequestRegion(0, 0);
} }
InWorld::~InWorld() { InWorld::~InWorld() {
@@ -85,29 +98,60 @@ void InWorld::FrameStart() {
} }
void InWorld::Update(double delta) { void InWorld::Update(double delta) {
SerialPacket packet;
//suck in all waiting packets //suck in all waiting packets
NetworkPacket packet;
while(network.Receive()) { while(network.Receive()) {
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket)); deserialize(&packet, network.GetInData());
packet.meta.srcAddress = network.GetInPacket()->address; packet.meta.srcAddress = network.GetInPacket()->address;
HandlePacket(packet); HandlePacket(packet);
} }
//update the characters
for (auto& it : playerCharacters) { for (auto& it : playerCharacters) {
it.second.Update(delta); it.second.Update(delta);
} }
//TODO: sort the players and entities by Y position
//update the camera
if(localCharacter) {
camera.x = localCharacter->GetPosition().x - camera.marginX;
camera.y = localCharacter->GetPosition().y - camera.marginY;
}
//check the map
UpdateMap();
} }
void InWorld::FrameEnd() { void InWorld::FrameEnd() {
// //
} }
void InWorld::RenderFrame() {
// SDL_FillRect(GetScreen(), 0, 0);
Render(GetScreen());
SDL_Flip(GetScreen());
}
void InWorld::Render(SDL_Surface* const screen) { void InWorld::Render(SDL_Surface* const screen) {
for (auto& it : playerCharacters) { //draw the map
it.second.DrawTo(screen); //TODO: figure out something to fix the region container access
for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
tileSheet.DrawRegionTo(screen, *it, camera.x, camera.y);
} }
//draw characters
for (auto& it : playerCharacters) {
it.second.DrawTo(screen, camera.x, camera.y);
}
//draw UI
disconnectButton.DrawTo(screen); disconnectButton.DrawTo(screen);
shutDownButton.DrawTo(screen); shutDownButton.DrawTo(screen);
font.DrawStringTo(to_string_custom(fps.GetFrameRate()), screen, 0, 0);
fps.Calculate();
} }
//------------------------- //-------------------------
@@ -209,38 +253,41 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) {
} }
} }
void InWorld::HandlePacket(NetworkPacket packet) { //-------------------------
//Network handlers
//-------------------------
void InWorld::HandlePacket(SerialPacket packet) {
switch(packet.meta.type) { switch(packet.meta.type) {
case NetworkPacket::Type::DISCONNECT: case SerialPacket::Type::DISCONNECT:
HandleDisconnect(packet); HandleDisconnect(packet);
break; break;
case SerialPacket::Type::PLAYER_NEW:
case NetworkPacket::Type::PLAYER_NEW:
HandlePlayerNew(packet); HandlePlayerNew(packet);
break; break;
case SerialPacket::Type::PLAYER_DELETE:
case NetworkPacket::Type::PLAYER_DELETE:
HandlePlayerDelete(packet); HandlePlayerDelete(packet);
break; break;
case SerialPacket::Type::PLAYER_UPDATE:
case NetworkPacket::Type::PLAYER_UPDATE:
HandlePlayerUpdate(packet); HandlePlayerUpdate(packet);
break; break;
case SerialPacket::Type::REGION_CONTENT:
HandleRegionContent(packet);
break;
//handle errors //handle errors
default: default:
throw(std::runtime_error("Unknown NetworkPacket::Type encountered")); throw(std::runtime_error("Unknown SerialPacket::Type encountered"));
break; break;
} }
} }
void InWorld::HandleDisconnect(NetworkPacket packet) { void InWorld::HandleDisconnect(SerialPacket packet) {
network.Unbind(Channels::SERVER); network.Unbind(Channels::SERVER);
clientIndex = -1; clientIndex = -1;
SetNextScene(SceneList::MAINMENU); SetNextScene(SceneList::MAINMENU);
} }
void InWorld::HandlePlayerNew(NetworkPacket packet) { void InWorld::HandlePlayerNew(SerialPacket packet) {
if (playerCharacters.find(packet.playerInfo.playerIndex) != playerCharacters.end()) { if (playerCharacters.find(packet.playerInfo.playerIndex) != playerCharacters.end()) {
throw(std::runtime_error("Cannot create duplicate players")); throw(std::runtime_error("Cannot create duplicate players"));
} }
@@ -254,10 +301,16 @@ void InWorld::HandlePlayerNew(NetworkPacket packet) {
if (packet.playerInfo.clientIndex == clientIndex && !localCharacter) { if (packet.playerInfo.clientIndex == clientIndex && !localCharacter) {
playerIndex = packet.playerInfo.playerIndex; playerIndex = packet.playerInfo.playerIndex;
localCharacter = &playerCharacters[playerIndex]; localCharacter = &playerCharacters[playerIndex];
//setup the camera
camera.width = GetScreen()->w;
camera.height = GetScreen()->h;
//center on the player's character
camera.marginX = (GetScreen()->w / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2);
camera.marginY = (GetScreen()->h / 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2);
} }
} }
void InWorld::HandlePlayerDelete(NetworkPacket packet) { void InWorld::HandlePlayerDelete(SerialPacket packet) {
if (playerCharacters.find(packet.playerInfo.playerIndex) == playerCharacters.end()) { if (playerCharacters.find(packet.playerInfo.playerIndex) == playerCharacters.end()) {
throw(std::runtime_error("Cannot delete non-existant players")); throw(std::runtime_error("Cannot delete non-existant players"));
} }
@@ -271,7 +324,7 @@ void InWorld::HandlePlayerDelete(NetworkPacket packet) {
} }
} }
void InWorld::HandlePlayerUpdate(NetworkPacket packet) { void InWorld::HandlePlayerUpdate(SerialPacket packet) {
if (playerCharacters.find(packet.playerInfo.playerIndex) == playerCharacters.end()) { if (playerCharacters.find(packet.playerInfo.playerIndex) == playerCharacters.end()) {
HandlePlayerNew(packet); HandlePlayerNew(packet);
return; return;
@@ -285,31 +338,103 @@ void InWorld::HandlePlayerUpdate(NetworkPacket packet) {
playerCharacters[packet.playerInfo.playerIndex].ResetDirection(); playerCharacters[packet.playerInfo.playerIndex].ResetDirection();
} }
void InWorld::HandleRegionContent(SerialPacket packet) {
//replace existing regions
if (regionPager.FindRegion(packet.regionInfo.x, packet.regionInfo.y)) {
regionPager.UnloadRegion(packet.regionInfo.x, packet.regionInfo.y);
}
regionPager.PushRegion(packet.regionInfo.region);
packet.regionInfo.region = nullptr;
}
//-------------------------
//Server control
//-------------------------
void InWorld::SendState() { void InWorld::SendState() {
NetworkPacket packet; SerialPacket packet;
packet.meta.type = NetworkPacket::Type::PLAYER_UPDATE; char buffer[PACKET_BUFFER_SIZE];
//pack the packet
packet.meta.type = SerialPacket::Type::PLAYER_UPDATE;
packet.playerInfo.clientIndex = clientIndex; packet.playerInfo.clientIndex = clientIndex;
packet.playerInfo.playerIndex = playerIndex; packet.playerInfo.playerIndex = playerIndex;
// snprintf(packet.playerInfo.handle, PACKET_STRING_SIZE, "%s", config["player.handle"].c_str());
// snprintf(packet.playerInfo.avatar, PACKET_STRING_SIZE, "%s", config["player.avatar"].c_str());
packet.playerInfo.position = localCharacter->GetPosition(); packet.playerInfo.position = localCharacter->GetPosition();
packet.playerInfo.motion = localCharacter->GetMotion(); packet.playerInfo.motion = localCharacter->GetMotion();
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket)); serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
} }
void InWorld::RequestDisconnect() { void InWorld::RequestDisconnect() {
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//send a disconnect request //send a disconnect request
NetworkPacket packet; packet.meta.type = SerialPacket::Type::DISCONNECT;
packet.meta.type = NetworkPacket::Type::DISCONNECT;
packet.clientInfo.index = clientIndex; packet.clientInfo.index = clientIndex;
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket)); serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
} }
void InWorld::RequestShutDown() { void InWorld::RequestShutDown() {
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//send a shutdown request //send a shutdown request
NetworkPacket packet; packet.meta.type = SerialPacket::Type::SHUTDOWN;
packet.meta.type = NetworkPacket::Type::SHUTDOWN;
packet.clientInfo.index = clientIndex; packet.clientInfo.index = clientIndex;
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket)); serialize(&packet, buffer);
} network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
}
void InWorld::RequestRegion(int x, int y) {
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//pack the region's data
packet.meta.type = SerialPacket::Type::REGION_REQUEST;
packet.regionInfo.x = x;
packet.regionInfo.y = y;
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
}
//-------------------------
//Utilities
//-------------------------
//TODO: convert this into a more generic function?; using parameters for the bounds
void InWorld::UpdateMap() {
//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
for (auto 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) {
//clunky, but the alternative was time consuming
int tmpX = (*it)->GetX();
int tmpY = (*it)->GetY();
++it;
regionPager.UnloadRegion(tmpX, tmpY);
continue;
}
++it;
}
//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)) {
RequestRegion(i, j);
}
}
}
}
+49 -11
View File
@@ -22,16 +22,31 @@
#ifndef INWORLD_HPP_ #ifndef INWORLD_HPP_
#define INWORLD_HPP_ #define INWORLD_HPP_
#include "base_scene.hpp" //maps
#include "map_allocator.hpp"
#include "map_file_format.hpp"
#include "region_pager.hpp"
#include "config_utility.hpp" //networking
#include "udp_network_utility.hpp" #include "udp_network_utility.hpp"
#include "network_packet.hpp" #include "serial_packet.hpp"
#include "serial.hpp"
//graphics
#include "image.hpp" #include "image.hpp"
#include "raster_font.hpp" #include "raster_font.hpp"
#include "button.hpp" #include "button.hpp"
#include "tile_sheet.hpp"
//common
#include "config_utility.hpp"
#include "frame_rate.hpp"
//client
#include "base_scene.hpp"
#include "player_character.hpp" #include "player_character.hpp"
//STL
#include <map> #include <map>
class InWorld : public BaseScene { class InWorld : public BaseScene {
@@ -45,6 +60,7 @@ protected:
void FrameStart(); void FrameStart();
void Update(double delta); void Update(double delta);
void FrameEnd(); void FrameEnd();
void RenderFrame();
void Render(SDL_Surface* const); void Render(SDL_Surface* const);
//Event handlers //Event handlers
@@ -55,26 +71,48 @@ protected:
void KeyDown(SDL_KeyboardEvent const&); void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&); void KeyUp(SDL_KeyboardEvent const&);
void HandlePacket(NetworkPacket); //Network handlers
void HandleDisconnect(NetworkPacket); void HandlePacket(SerialPacket);
void HandlePlayerNew(NetworkPacket); void HandleDisconnect(SerialPacket);
void HandlePlayerDelete(NetworkPacket); void HandlePlayerNew(SerialPacket);
void HandlePlayerUpdate(NetworkPacket); void HandlePlayerDelete(SerialPacket);
void HandlePlayerUpdate(SerialPacket);
void HandleRegionContent(SerialPacket);
//Server control
void SendState(); void SendState();
void RequestDisconnect(); void RequestDisconnect();
void RequestShutDown(); void RequestShutDown();
void RequestRegion(int x, int y);
//global //utilities
void UpdateMap();
//globals
ConfigUtility& config; ConfigUtility& config;
FrameRate fps;
UDPNetworkUtility& network; UDPNetworkUtility& network;
int& clientIndex; int& clientIndex;
//members //graphics
Image image; Image buttonImage;
RasterFont font; RasterFont font;
TileSheet tileSheet;
//map
RegionPager<BlankAllocator, DummyFormat> regionPager;
//UI
Button disconnectButton; Button disconnectButton;
Button shutDownButton; Button shutDownButton;
//TODO: Fix the camera
struct {
int x = 0, y = 0;
int width = 0, height = 0;
int marginX = 0, marginY = 0;
} camera;
//game
std::map<int, PlayerCharacter> playerCharacters; std::map<int, PlayerCharacter> playerCharacters;
PlayerCharacter* localCharacter = nullptr; PlayerCharacter* localCharacter = nullptr;
int playerIndex = -1; int playerIndex = -1;
+47 -14
View File
@@ -22,6 +22,7 @@
#include "lobby_menu.hpp" #include "lobby_menu.hpp"
#include "channels.hpp" #include "channels.hpp"
#include "utility.hpp"
#include <stdexcept> #include <stdexcept>
@@ -78,9 +79,9 @@ void LobbyMenu::FrameStart() {
void LobbyMenu::Update(double delta) { void LobbyMenu::Update(double delta) {
//suck in all waiting packets //suck in all waiting packets
NetworkPacket packet; SerialPacket packet;
while(network.Receive()) { while(network.Receive()) {
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket)); deserialize(&packet, network.GetInData());
packet.meta.srcAddress = network.GetInPacket()->address; packet.meta.srcAddress = network.GetInPacket()->address;
HandlePacket(packet); HandlePacket(packet);
} }
@@ -91,9 +92,13 @@ void LobbyMenu::FrameEnd() {
} }
void LobbyMenu::Render(SDL_Surface* const screen) { void LobbyMenu::Render(SDL_Surface* const screen) {
//TODO: I need a proper UI system for the entire client and the editor
//UI
search.DrawTo(screen); search.DrawTo(screen);
join.DrawTo(screen); join.DrawTo(screen);
back.DrawTo(screen); back.DrawTo(screen);
//TODO: draw headers for the server list
for (int i = 0; i < serverInfo.size(); i++) { for (int i = 0; i < serverInfo.size(); i++) {
//draw the selected server's highlight //draw the selected server's highlight
if (selection == &serverInfo[i]) { if (selection == &serverInfo[i]) {
@@ -104,6 +109,16 @@ void LobbyMenu::Render(SDL_Surface* const screen) {
//draw the server name //draw the server name
font.DrawStringTo(serverInfo[i].name, screen, listBox.x, listBox.y + i*listBox.h); font.DrawStringTo(serverInfo[i].name, screen, listBox.x, listBox.y + i*listBox.h);
//draw the player count
font.DrawStringTo(to_string_custom(serverInfo[i].playerCount), screen, listBox.x + listBox.w, listBox.y + i*listBox.h);
//compatible?
if (!serverInfo[i].compatible) {
font.DrawStringTo("?", screen, listBox.x - font.GetCharW(), listBox.y + i*listBox.h);
}
//TODO: ping?
} }
} }
@@ -125,21 +140,30 @@ void LobbyMenu::MouseButtonDown(SDL_MouseButtonEvent const& button) {
void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) { void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
if (search.MouseButtonUp(button) == Button::State::HOVER) { if (search.MouseButtonUp(button) == Button::State::HOVER) {
//the vars
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//broadcast to the network, or a specific server //broadcast to the network, or a specific server
NetworkPacket packet; packet.meta.type = SerialPacket::Type::BROADCAST_REQUEST;
packet.meta.type = NetworkPacket::Type::BROADCAST_REQUEST; serialize(&packet, buffer);
network.Send(config["server.host"].c_str(), config.Int("server.port"), reinterpret_cast<void*>(&packet), sizeof(NetworkPacket)); network.Send(config["server.host"].c_str(), config.Int("server.port"), buffer, PACKET_BUFFER_SIZE);
//reset the server list //reset the server list
serverInfo.clear(); serverInfo.clear();
selection = nullptr; selection = nullptr;
} }
else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr) { else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr && selection->compatible) {
//TODO: The player login information should be collected by the lobby screen
//the vars
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//join the selected server //join the selected server
NetworkPacket packet; packet.meta.type = SerialPacket::Type::JOIN_REQUEST;
packet.meta.type = NetworkPacket::Type::JOIN_REQUEST; serialize(&packet, buffer);
network.Send(&selection->address, &packet, sizeof(NetworkPacket)); network.Send(&selection->address, buffer, PACKET_BUFFER_SIZE);
selection = nullptr; selection = nullptr;
} }
@@ -173,16 +197,25 @@ void LobbyMenu::KeyUp(SDL_KeyboardEvent const& key) {
// //
} }
void LobbyMenu::HandlePacket(NetworkPacket packet) { void LobbyMenu::HandlePacket(SerialPacket packet) {
switch(packet.meta.type) { switch(packet.meta.type) {
case NetworkPacket::Type::BROADCAST_RESPONSE: { case SerialPacket::Type::BROADCAST_RESPONSE: {
//extract the data
ServerInformation server; ServerInformation server;
server.name = packet.serverInfo.name;
server.address = packet.meta.srcAddress; server.address = packet.meta.srcAddress;
server.name = packet.serverInfo.name;
server.playerCount = packet.serverInfo.playerCount;
//NOTE: Check compatibility here
server.compatible = packet.serverInfo.regionWidth == REGION_WIDTH &&
packet.serverInfo.regionHeight == REGION_HEIGHT &&
packet.serverInfo.regionDepth == REGION_DEPTH;
//push
serverInfo.push_back(server); serverInfo.push_back(server);
} }
break; break;
case NetworkPacket::Type::JOIN_RESPONSE: case SerialPacket::Type::JOIN_RESPONSE:
clientIndex = packet.clientInfo.index; clientIndex = packet.clientInfo.index;
network.Bind(&packet.meta.srcAddress, Channels::SERVER); network.Bind(&packet.meta.srcAddress, Channels::SERVER);
SetNextScene(SceneList::INWORLD); SetNextScene(SceneList::INWORLD);
@@ -190,7 +223,7 @@ void LobbyMenu::HandlePacket(NetworkPacket packet) {
//handle errors //handle errors
default: default:
throw(std::runtime_error("Unknown NetworkPacket::Type encountered")); throw(std::runtime_error("Unknown SerialPacket::Type encountered"));
break; break;
} }
} }
+18 -7
View File
@@ -22,16 +22,24 @@
#ifndef LOBBYMENU_HPP_ #ifndef LOBBYMENU_HPP_
#define LOBBYMENU_HPP_ #define LOBBYMENU_HPP_
#include "base_scene.hpp" //graphics & utilities
#include "image.hpp" #include "image.hpp"
#include "raster_font.hpp" #include "raster_font.hpp"
#include "button.hpp" #include "button.hpp"
#include "config_utility.hpp" #include "config_utility.hpp"
#include "udp_network_utility.hpp"
#include "network_packet.hpp"
//map
#include "region.hpp"
//network
#include "udp_network_utility.hpp"
#include "serial_packet.hpp"
#include "serial.hpp"
//client
#include "base_scene.hpp"
//STL
#include <vector> #include <vector>
class LobbyMenu : public BaseScene { class LobbyMenu : public BaseScene {
@@ -54,7 +62,7 @@ protected:
void KeyDown(SDL_KeyboardEvent const&); void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&); void KeyUp(SDL_KeyboardEvent const&);
void HandlePacket(NetworkPacket); void HandlePacket(SerialPacket);
//global //global
ConfigUtility& config; ConfigUtility& config;
@@ -70,8 +78,11 @@ protected:
//server list //server list
struct ServerInformation { struct ServerInformation {
std::string name;
IPaddress address; IPaddress address;
//TODO: version info
std::string name;
int playerCount;
bool compatible;
}; };
std::vector<ServerInformation> serverInfo; std::vector<ServerInformation> serverInfo;
+75
View File
@@ -0,0 +1,75 @@
/* Copyright: (c) Kayne Ruse 2013, 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 BBOX_HPP_
#define BBOX_HPP_
#include <type_traits>
#include <stdexcept>
#include <algorithm>
//TODO: This is supposed to interact with the vector
class BBox {
public:
double x, y;
double w, h;
BBox() = default;
BBox(double i, double j, double k, double l): x(i), y(j), w(k), h(l) {};
~BBox() = default;
BBox& operator=(BBox const&) = default;
double Size() {
return std::max(w*h,0.0);
}
bool IsCollision(BBox rhs) {
return not (
x >= rhs.x + rhs.w ||
y >= rhs.y + rhs.h ||
rhs.x >= x + w ||
rhs.y >= y + h
);
}
BBox Intersection(BBox rhs) {
if (!IsCollision(rhs)) {
return {0, 0, 0, 0};
}
BBox ret;
ret.x = std::max(x, rhs.x);
ret.y = std::max(y, rhs.y);
ret.w = std::min(x+w, rhs.x+rhs.w) - ret.x;
ret.h = std::min(y+h, rhs.y+rhs.h) - ret.y;
return ret;
}
double operator[](size_t i) {
if (i >= 4)
throw(std::domain_error("Out of range"));
return *(&x+i);
}
};
//This is explicitly a POD
static_assert(std::is_pod<BBox>::value, "BBox is not a POD");
#endif
+21 -23
View File
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -19,32 +19,30 @@
* 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.
*/ */
#ifndef TILE_HPP_ #ifndef FRAMERATE_HPP_
#define TILE_HPP_ #define FRAMERATE_HPP_
//explicitly a POD #include <chrono>
struct Tile {
//position relative to the Region
int x, y, depth;
//graphics class FrameRate {
int width, height; public:
int tileIndex; typedef std::chrono::high_resolution_clock Clock;
Tile() = default; FrameRate() = default;
Tile(int _x, int _y, int _depth, int _width, int _height, int _tileIndex) { int Calculate() {
//The order of the arguments should be explicit frameCount++;
x = _x; if (Clock::now() - tick >= std::chrono::duration<int>(1)) {
y = _y; lastFrameRate = frameCount;
depth = _depth; frameCount = 0;
width = _width; tick = Clock::now();
height = _height; }
tileIndex = _tileIndex; return lastFrameRate;
} }
int GetFrameRate() { return lastFrameRate; }
private:
int frameCount = 0;
int lastFrameRate = 0;
Clock::time_point tick = Clock::now();
}; };
bool operator<(Tile const& lhs, Tile const& rhs);
bool operator>(Tile const& lhs, Tile const& rhs);
bool operator==(Tile const& lhs, Tile const& rhs);
#endif #endif
+1 -1
View File
@@ -1,5 +1,5 @@
#config #config
INCLUDES+=. .. INCLUDES+=. .. ../map
LIBS+= LIBS+=
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES)) CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES)) CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
+61
View File
@@ -0,0 +1,61 @@
/* 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 "tile_sheet.hpp"
void TileSheet::Load(std::string fname, int xc, int yc) {
XCount = xc;
YCount = yc;
image.LoadSurface(fname);
image.SetClipW(image.GetClipW()/XCount);
image.SetClipH(image.GetClipH()/YCount);
}
void TileSheet::Unload() {
image.FreeSurface();
XCount = YCount = 0;
}
void TileSheet::DrawTo(SDL_Surface* const dest, int x, int y, Region::type_t tile) {
//0 is invisible
if (tile == 0) return;
image.SetClipX((tile-1) % XCount * image.GetClipW());
image.SetClipY((tile-1) / XCount * image.GetClipH());
image.DrawTo(dest, x, y);
}
void TileSheet::DrawRegionTo(SDL_Surface* const dest, Region* const region, int camX, int camY) {
Region::type_t tile = 0;
for (register int i = 0; i < REGION_WIDTH; ++i) {
for (register int j = 0; j < REGION_HEIGHT; ++j) {
for (register int k = 0; k < REGION_DEPTH; ++k) {
tile = region->GetTile(i, j, k);
//0 is invisible
if (tile == 0) continue;
image.SetClipX((tile-1) % XCount * image.GetClipW());
image.SetClipY((tile-1) / XCount * image.GetClipH());
image.DrawTo(dest,
(region->GetX() + i) * image.GetClipW() - camX,
(region->GetY() + j) * image.GetClipH() - camY);
}
}
}
}
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -19,33 +19,36 @@
* 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.
*/ */
#ifndef TILESHEETMANAGER_HPP_ #ifndef TILESHEET_HPP_
#define TILESHEETMANAGER_HPP_ #define TILESHEET_HPP_
#include "tile_sheet.hpp" #include "region.hpp"
#include "image.hpp"
#include <map>
#include <string> #include <string>
class TileSheetManager { class TileSheet {
public: public:
TileSheetManager() = default; TileSheet() = default;
~TileSheetManager() = default; TileSheet(std::string f, int x, int y) { Load(f, x, y); }
~TileSheet() = default;
TileSheet* LoadSheet(std::string fname, Uint16 w, Uint16 h); void Load(std::string fname, int XCount, int YCount);
TileSheet* GetSheet(std::string name); void Unload();
TileSheet* GetSheetByIndex(int tileIndex);
void UnloadSheet(std::string name);
void DrawTo(SDL_Surface* const, int x, int y, int tileIndex); void DrawTo(SDL_Surface* const dest, int x, int y, Region::type_t tile);
void DrawRegionTo(SDL_Surface* const dest, Region* const region, int camX, int camY);
int SetRangeEnd(int i) { return rangeEnd += i; } //accessors
int GetRangeEnd() const { return rangeEnd; } Image* GetImage() { return &image; }
int GetXCount() { return XCount; }
std::map<std::string, TileSheet>* GetSheetMap() { return &sheetMap; } int GetYCount() { return YCount; }
int GetTileW() { return image.GetClipW(); }
int GetTileH() { return image.GetClipH(); }
private: private:
std::map<std::string, TileSheet> sheetMap; Image image;
int rangeEnd = 0; int XCount = 0, YCount = 0;
}; };
#endif #endif
+1
View File
@@ -22,6 +22,7 @@ all: $(OBJ) $(OUT)
ar -crs $(OUT) $(OBJ) ar -crs $(OUT) $(OBJ)
$(MAKE) -C graphics $(MAKE) -C graphics
$(MAKE) -C map $(MAKE) -C map
$(MAKE) -C script
$(MAKE) -C network $(MAKE) -C network
$(MAKE) -C ui $(MAKE) -C ui
+60
View File
@@ -0,0 +1,60 @@
/* 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 "map_allocator.hpp"
#include <stdexcept>
void BlankAllocator::Create(Region** const ptr, int x, int y) {
(*ptr) = new Region(x, y);
}
void BlankAllocator::Unload(Region* const ptr) {
delete ptr;
}
void LuaAllocator::Create(Region** const ptr, int x, int y) {
//something to work on
(*ptr) = new Region(x, y);
//API hook
lua_getglobal(state, "Region");
lua_getfield(state, -1, "Create");
lua_pushlightuserdata(state, *ptr);
if (lua_pcall(state, 1, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
}
lua_pop(state, 1);
}
void LuaAllocator::Unload(Region* const ptr) {
//API hook
lua_getglobal(state, "Region");
lua_getfield(state, -1, "Unload");
lua_pushlightuserdata(state, ptr);
if (lua_pcall(state, 1, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
}
lua_pop(state, 1);
//clean up the memory
delete ptr;
}
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -19,26 +19,30 @@
* 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 "tile.hpp" #ifndef MAPALLOCATOR_HPP_
#define MAPALLOCATOR_HPP_
bool operator<(Tile const& lhs, Tile const& rhs) { #include "region.hpp"
//sort by depth -> y -> x
if (lhs.depth == rhs.depth) {
if (lhs.y == rhs.y) {
return lhs.x < rhs.x;
}
return lhs.y < rhs.y;
}
return lhs.depth < rhs.depth;
}
inline bool operator>(Tile const& lhs, Tile const& rhs) { #include "lua/lua.hpp"
//wrap the other operator
return rhs < lhs;
}
inline bool operator==(Tile const& lhs, Tile const& rhs) { class BlankAllocator {
//comparisons work on the location ONLY public:
//this function is redundant as far as the std::set object is concerned void Create(Region** const, int x, int y);
return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.depth == rhs.depth); void Unload(Region* const);
} private:
//
};
class LuaAllocator {
public:
void Create(Region** const, int x, int y);
void Unload(Region* const);
lua_State* SetLuaState(lua_State* L) { return state = L; }
lua_State* GetLuaState() { return state; }
private:
lua_State* state = nullptr;
};
#endif
+66
View File
@@ -0,0 +1,66 @@
/* 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 "map_file_format.hpp"
#include <stdexcept>
void DummyFormat::Load(Region** const ptr, int x, int y) {
//EMPTY
}
void DummyFormat::Save(Region* const ptr) {
//EMPTY
}
void LuaFormat::Load(Region** const ptr, int x, int y) {
//something to load into
if (!(*ptr)) {
(*ptr) = new Region(x, y);
}
//API hook
lua_getglobal(state, "Region");
lua_getfield(state, -1, "Load");
lua_pushlightuserdata(state, *ptr);
lua_pushstring(state, saveDir.c_str());
if (lua_pcall(state, 2, 1, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
}
if (lua_toboolean(state, -1) == false) {
delete (*ptr);
(*ptr) = nullptr;
}
lua_pop(state, 2);
}
void LuaFormat::Save(Region* const ptr) {
//API hook
lua_getglobal(state, "Region");
lua_getfield(state, -1, "Save");
lua_pushlightuserdata(state, ptr);
lua_pushstring(state, saveDir.c_str());
if (lua_pcall(state, 2, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
}
lua_pop(state, 1);
}
+60
View File
@@ -0,0 +1,60 @@
/* 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 MAPFILEFORMAT_HPP_
#define MAPFILEFORMAT_HPP_
#include "region.hpp"
#include "lua/lua.hpp"
#include <string>
class DummyFormat {
public:
void Load(Region** const, int x, int y);
void Save(Region* const);
std::string SetSaveDir(std::string s) { return saveDir = s; }
std::string GetSaveDir() { return saveDir; }
private:
std::string saveDir;
};
//TODO: verbose save file format
//TODO: compact save file format
class LuaFormat {
public:
void Load(Region** const, int x, int y);
void Save(Region* const);
std::string SetSaveDir(std::string s) { return saveDir = s; }
std::string GetSaveDir() { return saveDir; }
lua_State* SetLuaState(lua_State* L) { return state = L; }
lua_State* GetLuaState() { return state; }
private:
std::string saveDir;
lua_State* state = nullptr;
};
#endif
+10 -94
View File
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -21,103 +21,19 @@
*/ */
#include "region.hpp" #include "region.hpp"
#include "utility.hpp" Region::Region(int argX, int argY):
x(argX),
#include <stdexcept> y(argY)
#include <sstream>
Region::Region(int _x, int _y, int _w, int _h):
x(_x),
y(_y),
width(_w),
height(_h)
{ {
//make sure that the region's position lines up for (register int i = 0; i < REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH; ++i) {
if (x != snapToBase(width, x) || y != snapToBase(height, y)) { *(reinterpret_cast<type_t*>(tiles) + i) = 0;
std::ostringstream os;
os << "Region is unaligned; x: " << x << ", y: " << y << ", width: " << width << ", height: " << height;
throw(std::runtime_error(os.str()));
} }
} }
int Region::NewTileR(Tile const& tile) { Region::type_t Region::SetTile(int x, int y, int z, type_t v) {
//return 1 for overwrite, 0 for insert return tiles[x][y][z] = v;
if (!InBoundsR(tile.x, tile.y)) {
std::ostringstream os;
os << "New tile location out of bounds: " <<
"(" << x << "," << y << ")->" <<
"(" << tile.x << "," << tile.y << ")"
;
throw(std::runtime_error(os.str()));
}
int ret = tiles.erase(tile);
tiles.insert(tile);
return ret;
} }
Tile Region::GetTileR(int tx, int ty, int minDepth) { Region::type_t Region::GetTile(int x, int y, int z) {
std::set<Tile>::iterator ptr = tiles.begin(); return tiles[x][y][z];
//skip the tiles that are too deep
while(ptr != tiles.end()) {
if (ptr->depth >= minDepth) {
break;
}
ptr++;
}
//find the first tile here
while(ptr != tiles.end()) {
//bounds
if ((ptr->x <= tx) && (ptr->y <= ty) && (ptr->x + ptr->width > tx) && (ptr->y + ptr->height > ty)) {
break;
}
ptr++;
}
//found it
if (ptr != tiles.end()) {
return *ptr;
}
//a tileIndex of -1 is an error code, the rest is for show
return {0,0,0,-1,-1,-1};
}
int Region::DeleteTileR(Tile const& tile) {
if (!InBoundsR(tile.x, tile.y)) {
throw(std::runtime_error("Deleted tile location out of bounds"));
std::ostringstream os;
os << "Deleted tile location out of bounds: " <<
"(" << x << "," << y << ")->" <<
"(" << tile.x << "," << tile.y << ")"
;
throw(std::runtime_error(os.str()));
}
//sentinel/error code
if (tile.tileIndex == -1) {
return 0;
}
return tiles.erase(tile);
}
bool operator<(Region const& lhs, Region const& rhs) {
//sort by y -> x
if (lhs.y == rhs.y) {
return lhs.x < rhs.x;
}
return lhs.y < rhs.y;
}
inline bool operator>(Region const& lhs, Region const& rhs) {
//wrap the other operator
return rhs < lhs;
}
inline bool operator==(Region const& lhs, Region const& rhs) {
//comparisons work on the location ONLY
//this function is redundant as far as the std::set object is concerned
return (lhs.x == rhs.x) && (lhs.y == rhs.y);
} }
+14 -76
View File
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -22,91 +22,29 @@
#ifndef REGION_HPP_ #ifndef REGION_HPP_
#define REGION_HPP_ #define REGION_HPP_
#include "tile.hpp" #define REGION_WIDTH 20
#define REGION_HEIGHT 20
#define REGION_DEPTH 3
#include <set>
/* A single section of the map.
* This class stores the tiles relative to it's own position, but
* there are functions for referencing the tiles' absolute position.
* These functions simply wrap the normal functions.
*/
class Region { class Region {
public: public:
typedef unsigned short type_t;
Region() = delete; Region() = delete;
Region(int x, int y, int width, int height); Region(int x, int y);
~Region() = default; ~Region() = default;
//create and insert a new tile, overwriting an existing tile at that location type_t SetTile(int x, int y, int z, type_t v);
int NewTileR(Tile const& tile); type_t GetTile(int x, int y, int z);
int NewTileA(Tile const& tile) {
//these can change, if the Tile class is changed
return NewTileR({
tile.x - x,
tile.y - y,
tile.depth,
tile.width,
tile.height,
tile.tileIndex
});
}
//find the first tile at this location, with the specified minimum depth //accessors
Tile GetTileR(int tx, int ty, int minDepth);
Tile GetTileA(int tx, int ty, int minDepth) {
return GetTileR(tx - x, ty - y, minDepth);
}
//wrap the other delete functions
int DeleteTileR(int tx, int ty, int minDepth) {
return DeleteTileR(GetTileR(tx, ty, minDepth));
}
int DeleteTileA(int tx, int ty, int minDepth) {
//explicitly skip one function call by adjusting from A to R
return DeleteTileR(GetTileR(tx - x, ty - y, minDepth));
}
//delete the specified tile
int DeleteTileR(Tile const& tile);
int DeleteTileA(Tile const& tile) {
//these can change, if the Tile class is changed
return DeleteTileR({
tile.x - x,
tile.y - y,
tile.depth,
tile.width,
tile.height,
tile.tileIndex
});
}
//find if the specified location exists within the region's bounds
bool InBoundsR(int i, int j) {
return (i >= 0) && (j >= 0) && (i < width) && (j < height);
}
bool InBoundsA(int i, int j) {
return InBoundsR(i - x, j - y);
}
//Raw accessors & mutators
int GetX() const { return x; } int GetX() const { return x; }
int GetY() const { return y; } int GetY() const { return y; }
int GetWidth() const { return width; }
int GetHeight() const { return height; }
std::set<Tile>* GetTiles() { return &tiles; }
//sorting the regions by the locations
friend bool operator<(Region const& lhs, Region const& rhs);
friend bool operator>(Region const& lhs, Region const& rhs);
friend bool operator==(Region const& lhs, Region const& rhs);
private: private:
int const x; const int x;
int const y; const int y;
int const width;
int const height; type_t tiles[REGION_WIDTH][REGION_HEIGHT][REGION_DEPTH];
std::set<Tile> tiles;
}; };
#endif #endif
+37 -91
View File
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -23,99 +23,45 @@
#include "utility.hpp" #include "utility.hpp"
#include <stdexcept> Region::type_t RegionPagerBase::SetTile(int x, int y, int z, Region::type_t v) {
#include <string> Region* ptr = GetRegion(x, y);
return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v);
RegionPager::RegionPager() {
//
} }
RegionPager::~RegionPager() { Region::type_t RegionPagerBase::GetTile(int x, int y, int z) {
if (onDelete) { Region* ptr = GetRegion(x, y);
for (auto& i : regionList) { return ptr->GetTile(x - ptr->GetX(), y - ptr->GetY(), z);
onDelete(&i); }
Region* RegionPagerBase::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* RegionPagerBase::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::NewRegion(int x, int y) { Region* RegionPagerBase::PushRegion(Region* ptr) {
for (auto& i : regionList) { regionList.push_front(ptr);
if (i.GetX() == x && i.GetY() == y) { return regionList.front();
throw(std::runtime_error("Duplicate Regions detected")); }
}
}
regionList.push_front({x, y, regionWidth, regionHeight});
if (onNew) {
onNew(&regionList.front());
}
return &regionList.front();
}
Region* RegionPager::GetRegion(int x, int y) {
for (auto& i : regionList) {
if (i.GetX() == x && i.GetY() == y) {
return &i;
}
}
//create, insert and return
regionList.push_front({x, y, regionWidth, regionHeight});
if (onNew) {
onNew(&regionList.front());
}
return &regionList.front();
}
void RegionPager::DeleteRegion(int x, int y) {
for (std::list<Region>::iterator i = regionList.begin(); i != regionList.end(); i++) {
if (i->GetX() == x && i->GetY() == y) {
if (onDelete) {
onDelete(&(*i));
}
regionList.erase(i);
break;
}
}
}
void RegionPager::DrawTo(SDL_Surface* const dest, TileSheetManager* const sheetMgr, int camX, int camY) {
for (auto& regionIter : regionList) {
#ifdef DEBUG
//draw the region's location
SDL_Rect box = {
Sint16(regionIter.GetX() - camX),
Sint16(regionIter.GetY() - camY),
Uint16(regionIter.GetWidth()),
Uint16(regionIter.GetHeight())
};
SDL_FillRect(dest, &box, SDL_MapRGB(dest->format, 10, 10, 20));
#endif
//draw each tile
for (auto& tileIter : *regionIter.GetTiles()) {
sheetMgr->DrawTo(
dest,
tileIter.x + regionIter.GetX() - camX,
tileIter.y + regionIter.GetY() - camY,
tileIter.tileIndex
);
}
}
}
void RegionPager::Prune(int left, int top, int right, int bottom) {
std::list<Region>::iterator it = regionList.begin();
while(it != regionList.end()) {
if (it->GetX() >= right || it->GetY() >= bottom || it->GetX() + it->GetWidth() < left || it->GetY() + it->GetHeight() < top) {
if (onDelete) {
onDelete(&(*it));
}
regionList.erase(it);
it = regionList.begin();
continue;
}
it++;
}
}
+92 -28
View File
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -23,47 +23,111 @@
#define REGIONPAGER_HPP_ #define REGIONPAGER_HPP_
#include "region.hpp" #include "region.hpp"
#include "tile_sheet_manager.hpp" #include "utility.hpp"
#include <list> #include <list>
class RegionPager { class RegionPagerBase {
public: public:
//for simplicity and consistency RegionPagerBase() {};
typedef void (*regionCallback_t)(Region* const); virtual ~RegionPagerBase() {};
RegionPager(); //tile manipulation
~RegionPager(); Region::type_t SetTile(int x, int y, int z, Region::type_t v);
Region::type_t GetTile(int x, int y, int z);
//these parameters MUST be multiples of the width & height //region manipulation
Region* NewRegion(int x, int y);
Region* GetRegion(int x, int y); Region* GetRegion(int x, int y);
void DeleteRegion(int x, int y); Region* FindRegion(int x, int y);
Region* PushRegion(Region*);
//call this to draw to the screen //interface
void DrawTo(SDL_Surface* const, TileSheetManager* const, int camX, int camY); virtual Region* LoadRegion(int x, int y) = 0;
virtual Region* SaveRegion(int x, int y) = 0;
virtual Region* CreateRegion(int x, int y) = 0;
virtual void UnloadRegion(int x, int y) = 0;
//TODO: delete existing regions
//callback hooks //accessors & mutators
void SetOnNew(regionCallback_t f) { onNew = f; } std::list<Region*>* GetContainer() { return &regionList; }
void SetOnDelete(regionCallback_t f) { onDelete = f; } protected:
std::list<Region*> regionList;
};
//params: Absolute values template<typename Allocator, typename FileFormat>
void Prune(int left, int top, int right, int bottom); class RegionPager : public RegionPagerBase {
public:
RegionPager() {};
~RegionPager() {
UnloadAll();
}
//accessors and mutators Region* LoadRegion(int x, int y) {
int SetWidth(int i) { return regionWidth = i; } //snap the coords
int SetHeight(int i) { return regionHeight = i; } x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
int GetWidth() const { return regionWidth; } //load the region if possible
int GetHeight() const { return regionHeight; } Region* ptr = nullptr;
format.Load(&ptr, x, y);
if (ptr) {
return PushRegion(ptr);
}
return nullptr;
}
std::list<Region>* GetRegions() { return &regionList; } Region* SaveRegion(int x, int y) {
private: //snap the coords
std::list<Region> regionList; x = snapToBase(REGION_WIDTH, x);
int regionWidth = 0, regionHeight = 0; y = snapToBase(REGION_HEIGHT, y);
regionCallback_t onNew = nullptr; //find & save the region
regionCallback_t onDelete = nullptr; Region* ptr = FindRegion(x, y);
if (ptr) {
format.Save(ptr);
}
return ptr;
}
Region* CreateRegion(int x, int y) {
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//create and push the object
Region* ptr = nullptr;
allocator.Create(&ptr, x, y);
return PushRegion(ptr);
}
void UnloadRegion(int x, int y) {
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//custom loop
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); /* EMPTY */) {
if ((*it)->GetX() == x && (*it)->GetY() == y) {
allocator.Unload(*it);
it = regionList.erase(it);
continue;
}
++it;
}
}
void UnloadAll() {
for (auto& it : regionList) {
allocator.Unload(it);
}
regionList.clear();
}
//accessors
Allocator* GetAllocator() { return &allocator; }
FileFormat* GetFormat() { return &format; }
protected:
Allocator allocator;
FileFormat format;
}; };
#endif #endif
-59
View File
@@ -1,59 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013
*
* 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 "tile_sheet.hpp"
#include <stdexcept>
void TileSheet::Load(std::string fname, Uint16 w, Uint16 h) {
//setup the image
image.LoadSurface(fname);
image.SetClipW(w);
image.SetClipH(h);
//get the tile counts
xCount = image.GetSurface()->w / w;
yCount = image.GetSurface()->h / h;
totalCount = xCount * yCount;
//set begin & end (usually temporary)
begin = 0;
end = totalCount;
}
void TileSheet::Unload() {
image.FreeSurface();
totalCount = xCount = yCount = 0;
begin = end = -1;
}
void TileSheet::DrawTo(SDL_Surface* const dest, int x, int y, int tileIndex) {
if (!InRange(tileIndex)) {
throw(std::invalid_argument("Tile index out of range"));
}
Sint16 clipX = (tileIndex-begin) % xCount * image.GetClipW();
Sint16 clipY = (tileIndex-begin) / xCount * image.GetClipH();
image.SetClipX(clipX);
image.SetClipY(clipY);
image.DrawTo(dest, x, y);
}
-70
View File
@@ -1,70 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013
*
* 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 TILESHEET_HPP_
#define TILESHEET_HPP_
#include "image.hpp"
#include <string>
/* The TileSheet class is used for drawing tiles of the map to the screen.
* This class also tracks the range of the tile images.
*/
class TileSheet {
public:
TileSheet() = default;
~TileSheet() = default;
//these load/set functions need to be followed by bookkeeping code
//w & h are the width & height of individual tiles
//TODO: rename these
void Load(std::string fname, Uint16 w, Uint16 h);
void Unload();
void DrawTo(SDL_Surface* const dest, int x, int y, int tileIndex);
bool InRange(int i) { return i >= begin && i < end; }
//accessors and mutators
Image* GetImage() { return &image; }
int GetTileW() const { return image.GetClipW(); }
int GetTileH() const { return image.GetClipH(); }
int GetTotalCount() const { return totalCount; }
int GetXCount() const { return xCount; }
int GetYCount() const { return yCount; }
int SetBegin(int i) { return begin = i; }
int SetEnd(int i) { return end = i; }
int GetBegin() const { return begin; }
int GetEnd() const { return end; }
private:
Image image;
//these are generated and used by internal processes
int totalCount = 0, xCount = 0, yCount = 0;
int begin = -1, end = -1;
};
#endif
-73
View File
@@ -1,73 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013
*
* 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 "tile_sheet_manager.hpp"
#include "utility.hpp"
#include <stdexcept>
TileSheet* TileSheetManager::LoadSheet(std::string fname, Uint16 w, Uint16 h) {
//get the key
std::string key = truncatePath(fname);
//don't override what's already here
if (sheetMap.find(key) != sheetMap.end()) {
throw(std::runtime_error("Cannot load duplicate tile sheets"));
}
//load & setup the sheet object
sheetMap[key].Load(fname, w, h);
sheetMap[key].SetBegin(rangeEnd);
rangeEnd += sheetMap[key].GetTotalCount();
sheetMap[key].SetEnd(rangeEnd);
//you can modify the object, say, during the save & load routines...
return &sheetMap[key];
}
TileSheet* TileSheetManager::GetSheet(std::string name) {
return &sheetMap.at(name);
}
TileSheet* TileSheetManager::GetSheetByIndex(int tileIndex) {
for (auto& it : sheetMap) {
if (it.second.InRange(tileIndex)) {
return &it.second;
}
}
return nullptr;
}
void TileSheetManager::UnloadSheet(std::string name) {
sheetMap.erase(name);
}
void TileSheetManager::DrawTo(SDL_Surface* const dest, int x, int y, int tileIndex) {
for (auto& it : sheetMap) {
if (it.second.InRange(tileIndex)) {
it.second.DrawTo(dest, x, y, tileIndex);
return;
}
}
//No matching tile index
throw(std::invalid_argument("Tile index is out of range of all tile sheets"));
}
+1 -1
View File
@@ -1,5 +1,5 @@
#config #config
INCLUDES+=. .. INCLUDES+=. .. ../map
LIBS+= LIBS+=
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES)) CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES)) CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
+303
View File
@@ -0,0 +1,303 @@
/* 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 "serial.hpp"
#include "map_allocator.hpp"
#include <cstring>
//-------------------------
//internal serialization functions
//-------------------------
void serializeType(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
}
void serializeServer(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//server info
//Note: version info serialization goes here
memcpy(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE;
memcpy(buffer, &packet->serverInfo.playerCount, sizeof(int));
buffer += sizeof(int);
//map format
memcpy(buffer, &packet->serverInfo.regionWidth, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->serverInfo.regionHeight, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->serverInfo.regionDepth, sizeof(int));
}
void serializeClient(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
memcpy(buffer, &packet->clientInfo.index, sizeof(int));
}
void serializePlayer(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//indexes
memcpy(buffer, &packet->playerInfo.clientIndex, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->playerInfo.playerIndex, sizeof(int));
buffer += sizeof(int);
//text
memcpy(buffer, packet->playerInfo.handle, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE;
memcpy(buffer, packet->playerInfo.avatar, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE;
//vectors
memcpy(buffer, &packet->playerInfo.position.x, sizeof(double));
buffer += sizeof(double);
memcpy(buffer, &packet->playerInfo.position.y, sizeof(double));
buffer += sizeof(double);
memcpy(buffer, &packet->playerInfo.motion.x, sizeof(double));
buffer += sizeof(double);
memcpy(buffer, &packet->playerInfo.motion.y, sizeof(double));
}
void serializeRegionFormat(SerialPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//x & y
memcpy(buffer, &packet->regionInfo.x, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->regionInfo.y, sizeof(int));
}
void serializeRegionContent(SerialPacket* packet, char* buffer) {
//format
memcpy(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//x & y
*reinterpret_cast<int*>(buffer) = packet->regionInfo.region->GetX();
buffer += sizeof(int);
*reinterpret_cast<int*>(buffer) = packet->regionInfo.region->GetY();
buffer += sizeof(int);
//content
for (register int i = 0; i < REGION_WIDTH; i++) {
for (register int j = 0; j < REGION_HEIGHT; j++) {
for (register int k = 0; k < REGION_DEPTH; k++) {
*reinterpret_cast<Region::type_t*>(buffer) = packet->regionInfo.region->GetTile(i, j, k);
buffer += sizeof(Region::type_t);
}
}
}
}
//-------------------------
//internal deserialization functions
//-------------------------
void deserializeType(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type));
}
void deserializeServer(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//server info
//Note: version info deserialization goes here
memcpy(packet->serverInfo.name, buffer, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE;
memcpy(&packet->serverInfo.playerCount, buffer, sizeof(int));
buffer += sizeof(int);
//map format
memcpy(&packet->serverInfo.regionWidth, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->serverInfo.regionHeight, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->serverInfo.regionDepth, buffer, sizeof(int));
}
void deserializeClient(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
memcpy(&packet->clientInfo.index, buffer, sizeof(int));
}
void deserializePlayer(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//indexes
memcpy(&packet->playerInfo.clientIndex, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->playerInfo.playerIndex, buffer, sizeof(int));
buffer += sizeof(int);
//text
memcpy(packet->playerInfo.handle, buffer, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE;
memcpy(packet->playerInfo.avatar, buffer, PACKET_STRING_SIZE);
buffer += PACKET_STRING_SIZE;
//vectors
memcpy(&packet->playerInfo.position.x, buffer, sizeof(double));
buffer += sizeof(double);
memcpy(&packet->playerInfo.position.y, buffer, sizeof(double));
buffer += sizeof(double);
memcpy(&packet->playerInfo.motion.x, buffer, sizeof(double));
buffer += sizeof(double);
memcpy(&packet->playerInfo.motion.y, buffer, sizeof(double));
}
void deserializeRegionFormat(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//x & y
memcpy(&packet->regionInfo.x, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->regionInfo.y, buffer, sizeof(int));
}
void deserializeRegionContent(SerialPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(SerialPacket::Type));
buffer += sizeof(SerialPacket::Type);
//x & y
memcpy(&packet->regionInfo.x, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->regionInfo.y, buffer, sizeof(int));
buffer += sizeof(int);
//content
BlankAllocator().Create(
&packet->regionInfo.region,
packet->regionInfo.x,
packet->regionInfo.y
);
for (register int i = 0; i < REGION_WIDTH; i++) {
for (register int j = 0; j < REGION_HEIGHT; j++) {
for (register int k = 0; k < REGION_DEPTH; k++) {
packet->regionInfo.region->SetTile(i, j, k, *reinterpret_cast<Region::type_t*>(buffer));
buffer += sizeof(Region::type_t);
}
}
}
}
//-------------------------
//the interface functions
//-------------------------
void serialize(SerialPacket* packet, void* buffer) {
switch(packet->meta.type) {
//No extra data
case SerialPacket::Type::NONE:
case SerialPacket::Type::PING:
case SerialPacket::Type::PONG:
case SerialPacket::Type::BROADCAST_REQUEST:
case SerialPacket::Type::JOIN_REQUEST:
case SerialPacket::Type::SYNCHRONIZE:
serializeType(packet, reinterpret_cast<char*>(buffer));
break;
//Server info
case SerialPacket::Type::BROADCAST_RESPONSE:
serializeServer(packet, reinterpret_cast<char*>(buffer));
break;
//Client info
case SerialPacket::Type::JOIN_RESPONSE:
case SerialPacket::Type::DISCONNECT:
case SerialPacket::Type::SHUTDOWN:
serializeClient(packet, reinterpret_cast<char*>(buffer));
break;
//Player info
case SerialPacket::Type::PLAYER_NEW:
case SerialPacket::Type::PLAYER_DELETE:
case SerialPacket::Type::PLAYER_UPDATE:
serializePlayer(packet, reinterpret_cast<char*>(buffer));
break;
//region info
case SerialPacket::Type::REGION_REQUEST:
serializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
break;
case SerialPacket::Type::REGION_CONTENT:
serializeRegionContent(packet, reinterpret_cast<char*>(buffer));
break;
}
}
void deserialize(SerialPacket* packet, void* buffer) {
//find the type, so that you can actually deserialize the packet!
deserializeType(packet, reinterpret_cast<char*>(buffer));
switch(packet->meta.type) {
//No extra data
case SerialPacket::Type::NONE:
case SerialPacket::Type::PING:
case SerialPacket::Type::PONG:
case SerialPacket::Type::BROADCAST_REQUEST:
case SerialPacket::Type::JOIN_REQUEST:
case SerialPacket::Type::SYNCHRONIZE:
//NOTHING
break;
//Server info
case SerialPacket::Type::BROADCAST_RESPONSE:
deserializeServer(packet, reinterpret_cast<char*>(buffer));
break;
//Client info
case SerialPacket::Type::JOIN_RESPONSE:
case SerialPacket::Type::DISCONNECT:
case SerialPacket::Type::SHUTDOWN:
deserializeClient(packet, reinterpret_cast<char*>(buffer));
break;
//Player info
case SerialPacket::Type::PLAYER_NEW:
case SerialPacket::Type::PLAYER_DELETE:
case SerialPacket::Type::PLAYER_UPDATE:
deserializePlayer(packet, reinterpret_cast<char*>(buffer));
break;
//region info
case SerialPacket::Type::REGION_REQUEST:
deserializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
break;
case SerialPacket::Type::REGION_CONTENT:
deserializeRegionContent(packet, reinterpret_cast<char*>(buffer));
break;
}
}
+38
View File
@@ -0,0 +1,38 @@
/* 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 SERIAL_HPP_
#define SERIAL_HPP_
#include "serial_packet.hpp"
/* NOTE: Keep the PACKET_BUFFER_SIZE up to date
* NOTE: REGION_CONTENT is currently the largest type of packet
* map content: REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizoeof(region::type_t)
* map format: sizeof(int) * 2
* metadata: sizeof(metadata)
*/
#define PACKET_BUFFER_SIZE REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) + sizeof(int) * 2 + sizeof(SerialPacket::Metadata)
void serialize(SerialPacket* const, void*);
void deserialize(SerialPacket* const, void*);
#endif
@@ -19,18 +19,19 @@
* 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.
*/ */
#ifndef NETWORKPACKET_HPP_ #ifndef SERIALPACKET_HPP_
#define NETWORKPACKET_HPP_ #define SERIALPACKET_HPP_
#include "SDL/SDL_net.h"
#include "vector2.hpp" #include "vector2.hpp"
#include "region.hpp"
#include "SDL/SDL_net.h"
#define PACKET_STRING_SIZE 100 #define PACKET_STRING_SIZE 100
#pragma pack(push, 0) #pragma pack(push, 0)
union NetworkPacket { union SerialPacket {
//types of packets //types of packets
enum class Type { enum class Type {
//default: there is something wrong //default: there is something wrong
@@ -61,6 +62,10 @@ union NetworkPacket {
PLAYER_NEW = 10, PLAYER_NEW = 10,
PLAYER_DELETE = 11, PLAYER_DELETE = 11,
PLAYER_UPDATE = 12, PLAYER_UPDATE = 12,
//map data
REGION_REQUEST = 13,
REGION_CONTENT = 14,
}; };
//metadata on the packet itself //metadata on the packet itself
@@ -74,10 +79,16 @@ union NetworkPacket {
Metadata meta; Metadata meta;
//TODO: version info //TODO: version info
char name[PACKET_STRING_SIZE]; char name[PACKET_STRING_SIZE];
//TODO: player count int playerCount;
//map format
int regionWidth;
int regionHeight;
int regionDepth;
}serverInfo; }serverInfo;
//information about the client //information about the client
//TODO: login credentials
struct ClientInformation { struct ClientInformation {
Metadata meta; Metadata meta;
int index; int index;
@@ -88,14 +99,22 @@ union NetworkPacket {
Metadata meta; Metadata meta;
int clientIndex; int clientIndex;
int playerIndex; int playerIndex;
//TODO: should move handle/avatar into clientInfo; these might actually do better during the login system
char handle[PACKET_STRING_SIZE]; char handle[PACKET_STRING_SIZE];
char avatar[PACKET_STRING_SIZE]; char avatar[PACKET_STRING_SIZE];
Vector2 position; Vector2 position;
Vector2 motion; Vector2 motion;
}playerInfo; }playerInfo;
//map data
struct RegionInformation {
Metadata meta;
int x, y;
Region* region;
}regionInfo;
//defaults //defaults
NetworkPacket() { SerialPacket() {
meta.type = Type::NONE; meta.type = Type::NONE;
meta.srcAddress = {0,0}; meta.srcAddress = {0,0};
} }
+72
View File
@@ -0,0 +1,72 @@
/*
** $Id: linit.c,v 1.32 2011/04/08 19:17:36 roberto Exp $
** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h
*/
/* Modified for use in Tortuga, renamed to linit.cpp
*/
/*
** If you embed Lua in your program and need to open the standard
** libraries, call luaL_openlibs in your program. If you need a
** different set of libraries, copy this file to your project and edit
** it to suit your needs.
*/
#define linit_c
#define LUA_LIB
#include "lua/lua.hpp"
#include "region_api.hpp"
/*
** these libs are loaded by lua.c and are readily available to any Lua
** program
*/
static const luaL_Reg loadedlibs[] = {
/* Standard libs */
{"_G", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_COLIBNAME, luaopen_coroutine},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_BITLIBNAME, luaopen_bit32},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_DBLIBNAME, luaopen_debug},
/* custom libs */
{LUA_REGIONLIBNAME, luaopen_regionapi},
{NULL, NULL}
};
/*
** these libs are preloaded and must be required before used
*/
static const luaL_Reg preloadedlibs[] = {
{NULL, NULL}
};
LUALIB_API void luaL_openlibs (lua_State *L) {
const luaL_Reg *lib;
/* call open functions from 'loadedlibs' and set results to global table */
for (lib = loadedlibs; lib->func; lib++) {
luaL_requiref(L, lib->name, lib->func, 1);
lua_pop(L, 1); /* remove lib */
}
/* add open functions from 'preloadedlibs' into 'package.preload' table */
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
for (lib = preloadedlibs; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_setfield(L, -2, lib->name);
}
lua_pop(L, 1); /* remove _PRELOAD table */
}
+43
View File
@@ -0,0 +1,43 @@
#config
INCLUDES+=. .. ../map
LIBS+=
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
#source
CXXSRC=$(wildcard *.cpp)
CSRC=$(wildcard *.c)
#objects
OBJDIR=obj
OBJ+=$(addprefix $(OBJDIR)/,$(CXXSRC:.cpp=.o))
OBJ+=$(addprefix $(OBJDIR)/,$(CSRC:.c=.o))
#output
OUTDIR=../..
OUT=$(addprefix $(OUTDIR)/,libcommon.a)
#targets
all: $(OBJ) $(OUT)
ar -crs $(OUT) $(OBJ)
$(OBJ): | $(OBJDIR)
$(OUT): | $(OUTDIR)
$(OBJDIR):
mkdir $(OBJDIR)
$(OUTDIR):
mkdir $(OUTDIR)
$(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
+88
View File
@@ -0,0 +1,88 @@
/* 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_api.hpp"
#include "region.hpp"
static int setTile(lua_State* L) {
Region* ptr = (Region*)lua_touserdata(L, 1);
ptr->SetTile(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1, lua_tointeger(L, 4)-1, lua_tointeger(L, 5));
return 0;
}
static int getTile(lua_State* L) {
Region* ptr = (Region*)lua_touserdata(L, 1);
int ret = ptr->GetTile(lua_tointeger(L, 2)-1, lua_tointeger(L, 3)-1, lua_tointeger(L, 4)-1);
lua_pushnumber(L, ret);
return 1;
}
static int getWidth(lua_State* L) {
lua_pushinteger(L, REGION_WIDTH);
return 1;
}
static int getHeight(lua_State* L) {
lua_pushinteger(L, REGION_HEIGHT);
return 1;
}
static int getDepth(lua_State* L) {
lua_pushinteger(L, REGION_DEPTH);
return 1;
}
static int getX(lua_State* L) {
Region* ptr = (Region*)lua_touserdata(L, 1);
lua_pushinteger(L, ptr->GetX());
return 1;
}
static int getY(lua_State* L) {
Region* ptr = (Region*)lua_touserdata(L, 1);
lua_pushinteger(L, ptr->GetY());
return 1;
}
static int dummy(lua_State* L) {
return 0;
}
static const luaL_Reg regionlib[] = {
{"SetTile",setTile},
{"GetTile",getTile},
{"GetWidth",getWidth},
{"GetHeight",getHeight},
{"GetDepth",getDepth},
{"GetX",getX},
{"GetY",getY},
{"Create", dummy},
{"Unload", dummy},
{"Load", dummy},
{"Save", dummy},
{nullptr, nullptr}
};
LUAMOD_API int luaopen_regionapi(lua_State* L) {
luaL_newlib(L, regionlib);
return 1;
}
+30
View File
@@ -0,0 +1,30 @@
/* 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 REGIONAPI_HPP_
#define REGIONAPI_HPP_
#include "lua/lua.hpp"
#define LUA_REGIONLIBNAME "Region"
LUAMOD_API int luaopen_regionapi(lua_State* L);
#endif
+2 -2
View File
@@ -27,9 +27,9 @@ int snapToBase(int base, int x) {
//snap to a grid //snap to a grid
if (x < 0) { if (x < 0) {
x++; x++;
return x - x % base - base; return x / base * base - base;
} }
return x - x % base; return x / base * base;
} }
std::string truncatePath(std::string pathname) { std::string truncatePath(std::string pathname) {
+4 -1
View File
@@ -22,6 +22,7 @@
#ifndef VECTOR2_HPP_ #ifndef VECTOR2_HPP_
#define VECTOR2_HPP_ #define VECTOR2_HPP_
#include <type_traits>
#include <stdexcept> #include <stdexcept>
#include <cmath> #include <cmath>
@@ -29,7 +30,6 @@ class Vector2 {
public: public:
double x, y; double x, y;
//This is explicitly a POD
Vector2() = default; Vector2() = default;
Vector2(double i, double j): x(i), y(j) {}; Vector2(double i, double j): x(i), y(j) {};
~Vector2() = default; ~Vector2() = default;
@@ -112,4 +112,7 @@ template<typename T> Vector2 operator/(T t, Vector2 v) { return v / t; }
template<typename T> bool operator==(T t, Vector2 v) { return v == t; } template<typename T> bool operator==(T t, Vector2 v) { return v == t; }
template<typename T> bool operator!=(T t, Vector2 v) { return v != t; } template<typename T> bool operator!=(T t, Vector2 v) { return v != t; }
//This is explicitly a POD
static_assert(std::is_pod<Vector2>::value, "Vector2 is not a POD");
#endif #endif
+1 -15
View File
@@ -24,12 +24,6 @@
#include <stdexcept> #include <stdexcept>
#include <chrono> #include <chrono>
//-------------------------
//Static declarations
//-------------------------
EditorApplication EditorApplication::instance;
//------------------------- //-------------------------
//Scene headers //Scene headers
//------------------------- //-------------------------
@@ -42,15 +36,7 @@ EditorApplication EditorApplication::instance;
//Public access members //Public access members
//------------------------- //-------------------------
EditorApplication::EditorApplication() { void EditorApplication::Init(int argc, char** argv) {
//
}
EditorApplication::~EditorApplication() {
//
}
void EditorApplication::Init() {
config.Load("rsc\\config.cfg"); config.Load("rsc\\config.cfg");
if (SDL_Init(SDL_INIT_VIDEO)) if (SDL_Init(SDL_INIT_VIDEO))
throw(std::runtime_error("Failed to initialize SDL")); throw(std::runtime_error("Failed to initialize SDL"));
+3 -7
View File
@@ -27,15 +27,11 @@
#include "config_utility.hpp" #include "config_utility.hpp"
class EditorApplication { class EditorApplication {
private:
EditorApplication();
~EditorApplication();
static EditorApplication instance;
public: public:
static EditorApplication* GetInstance() { return &instance; } EditorApplication() = default;
~EditorApplication() = default;
void Init(); void Init(int argc, char** argv);
void Proc(); void Proc();
void Quit(); void Quit();
+95 -147
View File
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2013, 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -50,25 +50,19 @@ EditorScene::EditorScene(ConfigUtility* const arg1):
menuBar.SetImage(&buttonImage); menuBar.SetImage(&buttonImage);
menuBar.SetEntries({ menuBar.SetEntries({
{"File", "-New", "-Open", "-Save", "-Save As...", "-Close", "Exit"}, {"File", "New", "Open", "Save", "Close"},
{"Edit", "-Set Tile", "-Load Sheet", "-Delete Sheet", "-Metadata", "-Run Script"}, {"Edit", "Set Tile", "Set Brush", "Script"},
{"Debugging", "Debug On", "Debug Off", "Toggle Debug", "Testificate"} {"Debug", "Debug On", "Debug Off", "Toggle", "Testificate"}
}); });
//setup the pager //debug
pager.SetOnNew([](Region* const ptr){ tsheet.Load(config["dir.tilesets"] + "terrain.bmp", 12, 15);
printf("New Region: %d, %d\n", ptr->GetX(), ptr->GetY()); for (int i = 0; i < REGION_WIDTH; i++) {
}); for (int j = 0; j < REGION_HEIGHT; j++) {
pager.SetTile(i, j, 0, 14);
pager.SetOnDelete([](Region* const ptr){ }
printf("Delete Region: %d, %d\n", ptr->GetX(), ptr->GetY()); }
}); pager.SetTile(5, 10, 1, 48);
//Set a resonable size for the regions
pager.SetWidth(32*4);
pager.SetHeight(32*4);
sheetMgr.LoadSheet(config["dir.tilesets"] + "terrain.bmp", 32, 32);
} }
EditorScene::~EditorScene() { EditorScene::~EditorScene() {
@@ -84,7 +78,7 @@ void EditorScene::FrameStart() {
} }
void EditorScene::Update(double delta) { void EditorScene::Update(double delta) {
pager.Prune(camera.x, camera.y, camera.x + GetScreen()->w, camera.y + GetScreen()->h); //
} }
void EditorScene::FrameEnd() { void EditorScene::FrameEnd() {
@@ -92,10 +86,23 @@ void EditorScene::FrameEnd() {
} }
void EditorScene::Render(SDL_Surface* const screen) { void EditorScene::Render(SDL_Surface* const screen) {
//draw the map tsheet.DrawRegionTo(screen, pager.GetRegion(0, 0), camera.x, camera.y);
pager.DrawTo(screen, &sheetMgr, camera.x, camera.y); /* //debug
for (int i = 0; i < pager.GetRegionWidth()*2; i++) {
//draw a big bar across the top for (int j = 0; j < pager.GetRegionHeight()*2; j++) {
for (int k = 0; k < pager.GetRegionDepth(); k++) {
//TODO: skip the out-of-bounds regions
tsheet.DrawTo(
screen,
i*tsheet.GetTileW()-camera.x,
j*tsheet.GetTileH()-camera.y,
pager.GetTile(i,j,k)
);
}
}
}
*/
//draw a big bar across the top (hackish)
buttonImage.SetClipY(0); buttonImage.SetClipY(0);
for (int i = 0; i < screen->w; i += buttonImage.GetClipW()) { for (int i = 0; i < screen->w; i += buttonImage.GetClipW()) {
buttonImage.DrawTo(screen, i, 0); buttonImage.DrawTo(screen, i, 0);
@@ -114,13 +121,15 @@ void EditorScene::Render(SDL_Surface* const screen) {
} }
void EditorScene::DrawToDebugInfo(std::string str, int line) { void EditorScene::DrawToDebugInfo(std::string str, int line) {
//draw the debug info on the right //draw the debug info on the right, with a grey background
font.DrawStringTo( SDL_Rect clip = {
str, Sint16(debugInfo.GetClipW() - str.size() * font.GetCharW()),
debugInfo.GetSurface(), Sint16(font.GetCharH() * line),
debugInfo.GetClipW() - str.size() * font.GetCharW(), Uint16(str.size() * font.GetCharW()),
font.GetCharH() * line Uint16(font.GetCharH())
); };
SDL_FillRect(debugInfo.GetSurface(), &clip, SDL_MapRGB(debugInfo.GetSurface()->format, 64, 64, 64));
font.DrawStringTo(str, debugInfo.GetSurface(), clip.x, clip.y);
} }
//------------------------- //-------------------------
@@ -130,24 +139,6 @@ void EditorScene::DrawToDebugInfo(std::string str, int line) {
void EditorScene::MouseMotion(SDL_MouseMotionEvent const& motion) { void EditorScene::MouseMotion(SDL_MouseMotionEvent const& motion) {
menuBar.MouseMotion(motion); menuBar.MouseMotion(motion);
if (motion.state & SDL_BUTTON_LMASK && motion.y >= buttonImage.GetClipH()) {
Region* regionPtr = pager.GetRegion(
snapToBase(pager.GetWidth(), motion.x + camera.x),
snapToBase(pager.GetHeight(), motion.y + camera.y)
);
TileSheet* sheetPtr = sheetMgr.GetSheetByIndex(tileCounter);
regionPtr->NewTileA({
snapToBase(sheetPtr->GetTileW(), motion.x + camera.x), //x
snapToBase(sheetPtr->GetTileH(), motion.y + camera.y), //y
0, //depth
sheetPtr->GetTileW(), //width
sheetPtr->GetTileH(), //height
tileCounter++ //value
});
}
if (motion.state & SDL_BUTTON_RMASK) { if (motion.state & SDL_BUTTON_RMASK) {
camera.x -= motion.xrel; camera.x -= motion.xrel;
camera.y -= motion.yrel; camera.y -= motion.yrel;
@@ -156,108 +147,12 @@ void EditorScene::MouseMotion(SDL_MouseMotionEvent const& motion) {
void EditorScene::MouseButtonDown(SDL_MouseButtonEvent const& button) { void EditorScene::MouseButtonDown(SDL_MouseButtonEvent const& button) {
menuBar.MouseButtonDown(button); menuBar.MouseButtonDown(button);
if (button.button == SDL_BUTTON_LEFT && button.y >= buttonImage.GetClipH()) {
Region* regionPtr = pager.GetRegion(
snapToBase(pager.GetWidth(), button.x + camera.x),
snapToBase(pager.GetHeight(), button.y + camera.y)
);
TileSheet* sheetPtr = sheetMgr.GetSheetByIndex(tileCounter);
regionPtr->NewTileA({
snapToBase(sheetPtr->GetTileW(), button.x + camera.x), //x
snapToBase(sheetPtr->GetTileH(), button.y + camera.y), //y
0, //depth
sheetPtr->GetTileW(), //width
sheetPtr->GetTileH(), //height
tileCounter++ //value
});
}
} }
void EditorScene::MouseButtonUp(SDL_MouseButtonEvent const& button) { void EditorScene::MouseButtonUp(SDL_MouseButtonEvent const& button) {
int entry, drop; int entry, drop;
menuBar.MouseButtonUp(button, &entry, &drop); menuBar.MouseButtonUp(button, &entry, &drop);
HandleMenuOption(entry, drop);
//manage input from the menu bar
switch(entry) {
case 0: //File
switch(drop) {
case 0:
//TODO: NEW
break;
case 1:
//TODO: OPEN
break;
case 2:
//TODO: SAVE
break;
case 3:
//TODO: SAVE AS
break;
case 4:
//TODO: CLOSE
break;
case 5: {
//Quit
SDL_Event e;
e.type = SDL_QUIT;
SDL_PushEvent(&e);
}
break;
}
break;
case 1: //Edit
switch(drop) {
case 0:
//TODO: SET TILE
break;
case 1:
//TODO: LOAD SHEET
break;
case 2:
//TODO: DELETE SHEET
break;
case 3:
//TODO: METADATA
break;
case 4:
//TODO: RUN SCRIPT
break;
}
break;
case 2: //Debug
switch(drop) {
case 0:
debugOpen = true;
break;
case 1:
debugOpen = false;
break;
case 2:
debugOpen = !debugOpen;
break;
case 3:
SetNextScene(SceneList::TESTIFICATESCENE);
break;
}
break;
}
} }
void EditorScene::KeyDown(SDL_KeyboardEvent const& key) { void EditorScene::KeyDown(SDL_KeyboardEvent const& key) {
@@ -265,12 +160,10 @@ void EditorScene::KeyDown(SDL_KeyboardEvent const& key) {
case SDLK_ESCAPE: case SDLK_ESCAPE:
QuitEvent(); QuitEvent();
break; break;
case SDLK_SPACE: case SDLK_SPACE:
camera.x = 0; camera.x = 0;
camera.y = 0; camera.y = 0;
break; break;
case SDLK_TAB: case SDLK_TAB:
debugOpen = !debugOpen; debugOpen = !debugOpen;
break; break;
@@ -280,3 +173,58 @@ void EditorScene::KeyDown(SDL_KeyboardEvent const& key) {
void EditorScene::KeyUp(SDL_KeyboardEvent const& key) { void EditorScene::KeyUp(SDL_KeyboardEvent const& key) {
// //
} }
//-------------------------
//Members
//-------------------------
void EditorScene::HandleMenuOption(int entry, int drop) {
//manage input from the menu bar
switch(entry) {
case 0: //File
switch(drop) {
case 0:
//TODO: NEW
break;
case 1:
//TODO: OPEN
break;
case 2:
//TODO: SAVE
break;
case 3:
//TODO: CLOSE
break;
}
break;
case 1: //Edit
switch(drop) {
case 0:
//TODO: SET TILE
break;
case 1:
//TODO: SET BRUSH
break;
case 2:
//TODO: SCRIPT
break;
}
break;
case 2: //Debug
switch(drop) {
case 0:
debugOpen = true;
break;
case 1:
debugOpen = false;
break;
case 2:
debugOpen = !debugOpen;
break;
case 3:
SetNextScene(SceneList::TESTIFICATESCENE);
break;
}
break;
}
}
+10 -10
View File
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2013, 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -24,15 +24,15 @@
#include "base_scene.hpp" #include "base_scene.hpp"
#include "region_pager.hpp"
#include "tile_sheet_manager.hpp"
#include "config_utility.hpp" #include "config_utility.hpp"
#include "image.hpp" #include "image.hpp"
#include "raster_font.hpp" #include "raster_font.hpp"
#include "menu_bar.hpp" #include "menu_bar.hpp"
//#include "map_loader.hpp" #include "region_pager.hpp"
#include "map_allocator.hpp"
#include "map_file_format.hpp"
#include "tile_sheet.hpp"
class EditorScene : public BaseScene { class EditorScene : public BaseScene {
public: public:
@@ -54,6 +54,9 @@ protected:
void KeyDown(SDL_KeyboardEvent const&); void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&); void KeyUp(SDL_KeyboardEvent const&);
//members
void HandleMenuOption(int entry, int drop);
//globals //globals
ConfigUtility& config; ConfigUtility& config;
@@ -62,19 +65,16 @@ protected:
Image debugInfo; Image debugInfo;
bool debugOpen = true; bool debugOpen = true;
RegionPager pager;
TileSheetManager sheetMgr;
RasterFont font; RasterFont font;
Image buttonImage; Image buttonImage;
MenuBar menuBar; MenuBar menuBar;
struct { struct {
int x = 0, y = 0; int x = 0, y = 0;
} camera; } camera;
int tileCounter = 0; RegionPager<BlankAllocator, DummyFormat> pager;
TileSheet tsheet;
}; };
#endif #endif
+6 -5
View File
@@ -26,12 +26,13 @@
using namespace std; using namespace std;
int main(int, char**) { int main(int argc, char** argv) {
cout << "Beginning editor" << endl; cout << "Beginning editor" << endl;
try { try {
EditorApplication::GetInstance()->Init(); EditorApplication app;
EditorApplication::GetInstance()->Proc(); app.Init(argc, argv);
EditorApplication::GetInstance()->Quit(); app.Proc();
app.Quit();
} }
catch(exception& e) { catch(exception& e) {
cerr << "Fatal exception thrown: " << e.what() << endl; cerr << "Fatal exception thrown: " << e.what() << endl;
@@ -39,4 +40,4 @@ int main(int, char**) {
} }
cout << "Clean exit" << endl; cout << "Clean exit" << endl;
return 0; return 0;
} }
+1 -1
View File
@@ -1,6 +1,6 @@
#config #config
INCLUDES+=../common ../common/graphics ../common/map ../common/ui INCLUDES+=../common ../common/graphics ../common/map ../common/ui
LIBS+=../libcommon.a -lmingw32 -lSDLmain -lSDL LIBS+=../libcommon.a -lmingw32 -lSDLmain -lSDL -llua
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES)) CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES)) CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
+2 -18
View File
@@ -33,18 +33,7 @@ using std::endl;
TestificateScene::TestificateScene(ConfigUtility* const arg1): TestificateScene::TestificateScene(ConfigUtility* const arg1):
config(*arg1) config(*arg1)
{ {
sheetMgr.LoadSheet(config["dir.tilesets"] + "grass.bmp", 32, 32); //
sheetMgr.LoadSheet(config["dir.tilesets"] + "longgrass.bmp", 32, 32);
sheetMgr.LoadSheet(config["dir.tilesets"] + "sand.bmp", 32, 32);
sheetMgr.LoadSheet(config["dir.tilesets"] + "dirt.bmp", 32, 32);
sheetMgr.LoadSheet(config["dir.tilesets"] + "water.bmp", 32, 32);
cout << "Range End: " << sheetMgr.GetRangeEnd() << endl;
pager.SetWidth(128);
pager.SetHeight(128);
pager.GetRegion(0, 0)->NewTileR({0, 0, 0, 32, 32, 0});
} }
TestificateScene::~TestificateScene() { TestificateScene::~TestificateScene() {
@@ -68,12 +57,7 @@ void TestificateScene::FrameEnd() {
} }
void TestificateScene::Render(SDL_Surface* const screen) { void TestificateScene::Render(SDL_Surface* const screen) {
//dump all tile graphics to the screen //
for (int i = 0; i < sheetMgr.GetRangeEnd(); i++) {
sheetMgr.DrawTo(screen, i * 32 % screen->w, i * 32 / screen->w * 32, i);
}
// pager.DrawTo(screen, &sheetMgr, 0, 0);
} }
//------------------------- //-------------------------
-6
View File
@@ -25,8 +25,6 @@
#include "base_scene.hpp" #include "base_scene.hpp"
#include "config_utility.hpp" #include "config_utility.hpp"
#include "tile_Sheet_manager.hpp"
#include "region_pager.hpp"
class TestificateScene : public BaseScene { class TestificateScene : public BaseScene {
public: public:
@@ -50,10 +48,6 @@ protected:
//globals //globals
ConfigUtility& config; ConfigUtility& config;
//members
TileSheetManager sheetMgr;
RegionPager pager;
}; };
#endif #endif
+1
View File
@@ -1,3 +1,4 @@
#TODO: The build process needs revising
#for use on Windows: #for use on Windows:
#MKDIR=mkdir #MKDIR=mkdir
+5
View File
@@ -17,6 +17,11 @@ dir.tilesets = rsc/graphics/tilesets/
dir.interface = rsc/graphics/interface/ dir.interface = rsc/graphics/interface/
dir.scripts = rsc/scripts/ dir.scripts = rsc/scripts/
#map system
map.pager.width = 20
map.pager.height = 20
map.pager.depth = 3
#player options #player options
player.handle = username player.handle = username
player.avatar = elliot2.bmp player.avatar = elliot2.bmp
Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File
+29
View File
@@ -0,0 +1,29 @@
print("Lua script check OK (./rsc)")
function Region.Create(r)
-- print("Region:Create(r", Region.GetX(r), Region.GetY(r), ")")
for i = 1, Region.GetWidth(r) do
for j = 1, Region.GetHeight(r) do
if math.abs(i) == math.abs(j) then
Region.SetTile(r, i, j, 1, 50)
else
Region.SetTile(r, i, j, 1, 14)
end
end
end
-- print("done")
end
function Region.Unload(r)
-- print("Region:Unload(r", Region.GetX(r), Region.GetY(r), ")")
end
--return true if file loaded, otherwise return false
function Region.Load(r, saveDir)
-- print("Region:Load(r,", saveDir, Region.GetX(r), Region.GetY(r), ")")
return false
end
function Region.Save(r, saveDir)
-- print("Region:Save(r,", saveDir, Region.GetX(r), Region.GetY(r), ")")
end
+48 -39
View File
@@ -1,11 +1,13 @@
--TODO: The SQL startup script needs revising
------------------------- -------------------------
--Server --Server
------------------------- -------------------------
CREATE TABLE IF NOT EXISTS UserAccounts ( CREATE TABLE IF NOT EXISTS UserAccounts (
userAccountID INTEGER PRIMARY KEY AUTOINCREMENT, uid INTEGER PRIMARY KEY AUTOINCREMENT,
username varchar(30) UNIQUE, username varchar(100) UNIQUE,
password varchar(30), password varchar(100), --NOTE: DO NOT DO THIS!!
blacklisted BIT DEFAULT 0, blacklisted BIT DEFAULT 0,
whitelisted BIT DEFAULT 1 whitelisted BIT DEFAULT 1
); );
@@ -14,31 +16,30 @@ CREATE TABLE IF NOT EXISTS UserAccounts (
--Items --Items
------------------------- -------------------------
CREATE TABLE IF NOT EXISTS GlobalItemList (
globalItemListID INTEGER PRIMARY KEY AUTOINCREMENT,
itemName varchar(30) UNIQUE,
itemImage varchar(30),
type varchar(15), --{'mundane', 'consumable', 'equipment'}
maxStackSize INTEGER, --{1-max; 0 for non-stackable}
maxUniqueCopies INTEGER --{1-max; 0 for unlimited}
);
CREATE TABLE IF NOT EXISTS MundaneItems ( CREATE TABLE IF NOT EXISTS MundaneItems (
mundaneItemID INTEGER PRIMARY KEY AUTOINCREMENT, --metadata
globalItemListID INTEGER REFERENCES GlobalItemList(globalItemListID) uid INTEGER PRIMARY KEY AUTOINCREMENT,
--holds whatever itemID INTEGER,
stackSize INTEGER DEFAULT 0,
owner INTEGER REFERENCES PlayerCharacters(uid)
); );
CREATE TABLE IF NOT EXISTS Consumables ( CREATE TABLE IF NOT EXISTS Consumables (
consumableID INTEGER PRIMARY KEY AUTOINCREMENT, --metadata
globalItemListID INTEGER REFERENCES GlobalItemList(globalItemListID) uid INTEGER PRIMARY KEY AUTOINCREMENT,
itemID INTEGER,
stackSize INTEGER DEFAULT 0,
owner INTEGER REFERENCES PlayerCharacters(uid)
--holds all consumable items info (food, potions, etc.) --holds all consumable items info (food, potions, etc.)
); );
CREATE TABLE IF NOT EXISTS Equipment ( CREATE TABLE IF NOT EXISTS Equipment (
equipmentID INTEGER PRIMARY KEY AUTOINCREMENT, --metadata
globalItemListID INTEGER REFERENCES GlobalItemList(globalItemListID) uid INTEGER PRIMARY KEY AUTOINCREMENT,
itemID INTEGER,
owner INTEGER REFERENCES PlayerCharacters(uid)
--hold all equipment info --hold all equipment info
--stat mods, special effects, etc.
); );
------------------------- -------------------------
@@ -46,28 +47,36 @@ CREATE TABLE IF NOT EXISTS Equipment (
------------------------- -------------------------
CREATE TABLE IF NOT EXISTS PlayerCharacters ( CREATE TABLE IF NOT EXISTS PlayerCharacters (
playerCharacterID INTEGER PRIMARY KEY AUTOINCREMENT, uid INTEGER PRIMARY KEY AUTOINCREMENT,
name varchar(30) UNIQUE,
--stats --metadata
currentLevel INTEGER DEFAULT 0, handle varchar(100) UNIQUE,
currentExperience INTEGER DEFAULT 0, avatar varchar(100),
maxHealth INTEGER DEFAULT 0, birth timestamp NOT NULL DEFAULT (datetime()),
maxMana INTEGER DEFAULT 0,
currentHealth INTEGER DEFAULT 0, --position
currentMana INTEGER DEFAULT 0, mapIndex INTEGER DEFAULT 0,
attack INTEGER DEFAULT 0, positionX INTEGER DEFAULT 0,
defence INTEGER DEFAULT 0, positionY INTEGER DEFAULT 0,
--etc.
--statistics
level INTEGER DEFAULT 0,
exp INTEGER DEFAULT 0,
maxHP INTEGER DEFAULT 0,
health INTEGER DEFAULT 0,
maxMP INTEGER DEFAULT 0,
mana INTEGER DEFAULT 0,
attack INTEGER DEFAULT 0,
defence INTEGER DEFAULT 0,
intelligence INTEGER DEFAULT 0,
resistance INTEGER DEFAULT 0,
accuracy REAL DEFAULT 0.0,
evasion REAL DEFAULT 0.0,
luck REAL DEFAULT 0.0,
--equipment --equipment
weapon INTEGER REFERENCES Equipment(equipmentID), weapon INTEGER REFERENCES Equipment(uid),
helmet INTEGER REFERENCES Equipment(equipmentID), helmet INTEGER REFERENCES Equipment(uid),
armour INTEGER REFERENCES Equipment(equipmentID) armour INTEGER REFERENCES Equipment(uid)
--etc. --etc.
); );
CREATE TABLE IF NOT EXISTS PlayerInventoryItems (
characterID INTEGER REFERENCES PlayerCharacters(characterID),
globalItemListID INTEGER REFERENCES GlobalItemList(globalItemListID)
);
+24
View File
@@ -0,0 +1,24 @@
/* 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 "client_entry.hpp"
unsigned int ClientEntry::uidCounter;
+5 -11
View File
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -19,20 +19,14 @@
* 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.
*/ */
#ifndef CLIENT_HPP_ #ifndef CLIENTENTRY_HPP_
#define CLIENT_HPP_ #define CLIENTENTRY_HPP_
#include "SDL/SDL_net.h" #include "SDL/SDL_net.h"
#include <map> struct ClientEntry {
/* Hold the client info.
*/
struct Client {
IPaddress address; IPaddress address;
static unsigned int uidCounter;
}; };
typedef std::map<int, Client> ClientMap;
#endif #endif
+1 -1
View File
@@ -33,7 +33,7 @@ int main(int argc, char** argv) {
try { try {
ServerApplication app; ServerApplication app;
app.Init(argc, argv); app.Init(argc, argv);
app.Loop(); app.Proc();
app.Quit(); app.Quit();
} }
catch(exception& e) { catch(exception& e) {
+1 -1
View File
@@ -1,5 +1,5 @@
#config #config
INCLUDES+=. ../common ../common/map ../common/network INCLUDES+=. ../common ../common/map ../common/script ../common/network
LIBS+=../libcommon.a -lSDL_net -lwsock32 -liphlpapi -lmingw32 -lSDLmain -lSDL -llua -lsqlite3 LIBS+=../libcommon.a -lSDL_net -lwsock32 -liphlpapi -lmingw32 -lSDLmain -lSDL -llua -lsqlite3
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES)) CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES)) CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
+24
View File
@@ -0,0 +1,24 @@
/* 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 "player_entry.hpp"
unsigned int PlayerEntry::uidCounter;
+62
View File
@@ -0,0 +1,62 @@
/* 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 PLAYERENTRY_HPP_
#define PLAYERENTRY_HPP_
//POD members
#include "bbox.hpp"
#include "vector2.hpp"
#include <string>
struct PlayerEntry {
//metadata
int clientIndex;
std::string handle;
std::string avatar;
//world position
int mapIndex;
Vector2 position;
Vector2 motion;
BBox bbox;
//statistics
int level;
int exp;
int maxHP;
int health;
int maxMP;
int mana;
int attack;
int defence;
int intelligence;
int resistance;
float accuracy;
float evasion;
float luck;
//uid
static unsigned int uidCounter;
};
#endif
+198 -125
View File
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2013, 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -26,275 +26,348 @@
#include <stdexcept> #include <stdexcept>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <fstream>
using namespace std;
//------------------------- //-------------------------
//Define the ServerApplication //Define the public members
//------------------------- //-------------------------
ServerApplication::ServerApplication() {
//
}
ServerApplication::~ServerApplication() {
//
}
void ServerApplication::Init(int argc, char** argv) { void ServerApplication::Init(int argc, char** argv) {
//TODO: proper command line option parsing //NOTE: I might need to rearrange the init process so that lua & SQL can interact with the map system as needed.
std::cout << "Beginning startup" << std::endl;
//load config //initial setup
ClientEntry::uidCounter = 0;
PlayerEntry::uidCounter = 0;
config.Load("rsc\\config.cfg"); config.Load("rsc\\config.cfg");
//Init SDL //Init SDL
if (SDL_Init(0)) { if (SDL_Init(0)) {
throw(runtime_error("Failed to initialize SDL")); throw(std::runtime_error("Failed to initialize SDL"));
} }
cout << "initialized SDL" << endl; std::cout << "Initialized SDL" << std::endl;
//Init SDL_net //Init SDL_net
if (SDLNet_Init()) { if (SDLNet_Init()) {
throw(runtime_error("Failed to init SDL_net")); throw(std::runtime_error("Failed to initialize SDL_net"));
} }
network.Open(config.Int("server.port"), sizeof(NetworkPacket)); network.Open(config.Int("server.port"), PACKET_BUFFER_SIZE);
cout << "initialized SDL_net" << endl; std::cout << "Initialized SDL_net" << std::endl;
//Init SQL //Init SQL
string dbname = (config["server.dbname"].size()) ? config["server.dbname"] : std::string(argv[0]) + ".db"; //fancy and unnecessary int ret = sqlite3_open_v2(config["server.dbname"].c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, nullptr);
int ret = sqlite3_open_v2(dbname.c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_FULLMUTEX, nullptr);
if (ret != SQLITE_OK || !database) { if (ret != SQLITE_OK || !database) {
throw(runtime_error("Failed to open the server database")); throw(std::runtime_error(std::string() + "Failed to initialize SQL: " + sqlite3_errmsg(database) ));
} }
cout << "initialized SQL" << endl; std::cout << "Initialized SQL" << std::endl;
cout << "Database filename: " << dbname << endl;
//TODO: move this into a function? //setup the database
//Run setup scripts if (runSQLScript(database, config["dir.scripts"] + "setup_server.sql")) {
ifstream is("rsc\\scripts\\setup_server.sql"); throw(std::runtime_error("Failed to initialize SQL's setup script"));
if (!is.is_open()) {
throw(runtime_error("Failed to run database setup script"));
} }
string script; std::cout << "Initialized SQL's setup script" << std::endl;
getline(is, script, '\0');
is.close(); //lua
sqlite3_exec(database, script.c_str(), nullptr, nullptr, nullptr); luaState = luaL_newstate();
if (!luaState) {
throw(std::runtime_error("Failed to initialize lua"));
}
luaL_openlibs(luaState);
std::cout << "Initialized lua" << std::endl;
//run the startup script
if (luaL_dofile(luaState, (config["dir.scripts"] + "setup_server.lua").c_str())) {
throw(std::runtime_error(std::string() + "Failed to initialize lua's setup script: " + lua_tostring(luaState, -1) ));
}
std::cout << "Initialized lua's setup script" << std::endl;
//setup the map object
regionPager.GetAllocator()->SetLuaState(luaState);
regionPager.GetFormat()->SetLuaState(luaState);
//TODO: config parameter
regionPager.GetFormat()->SetSaveDir("save/mapname/");
std::cout << "Initialized the map system" << std::endl;
std::cout << "\tsizeof(SerialPacket): " << sizeof(SerialPacket) << std::endl;
std::cout << "\tPACKET_BUFFER_SIZE: " << PACKET_BUFFER_SIZE << std::endl;
//finalize the startup
std::cout << "Startup completed successfully" << std::endl;
//debugging
//
} }
void ServerApplication::Loop() { void ServerApplication::Proc() {
NetworkPacket packet; SerialPacket packet;
while(running) { while(running) {
//suck in the waiting packets & process them //suck in the waiting packets & process them
try { while(network.Receive()) {
while(network.Receive()) { //get the packet
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket)); deserialize(&packet, network.GetInData());
packet.meta.srcAddress = network.GetInPacket()->address; //cache the source address
HandlePacket(packet); packet.meta.srcAddress = network.GetInPacket()->address;
} //we need to go deeper
HandlePacket(packet);
} }
catch(exception& e) {
cerr << "Network Error: " << e.what() << endl;
}
//give the computer a break //give the computer a break
//TODO: remove this delay?
SDL_Delay(10); SDL_Delay(10);
} }
} }
void ServerApplication::Quit() { void ServerApplication::Quit() {
//members std::cout << "Shutting down" << std::endl;
network.Close(); //empty the members
regionPager.UnloadAll();
//APIs //APIs
lua_close(luaState);
sqlite3_close_v2(database); sqlite3_close_v2(database);
network.Close();
SDLNet_Quit(); SDLNet_Quit();
SDL_Quit(); SDL_Quit();
std::cout << "Shutdown finished" << std::endl;
} }
void ServerApplication::HandlePacket(NetworkPacket packet) { //-------------------------
//Define the uber switch
//-------------------------
void ServerApplication::HandlePacket(SerialPacket packet) {
switch(packet.meta.type) { switch(packet.meta.type) {
case NetworkPacket::Type::BROADCAST_REQUEST: case SerialPacket::Type::BROADCAST_REQUEST:
HandleBroadcastRequest(packet); HandleBroadcastRequest(packet);
break; break;
case SerialPacket::Type::JOIN_REQUEST:
case NetworkPacket::Type::JOIN_REQUEST:
HandleJoinRequest(packet); HandleJoinRequest(packet);
break; break;
case SerialPacket::Type::DISCONNECT:
case NetworkPacket::Type::DISCONNECT:
HandleDisconnect(packet); HandleDisconnect(packet);
break; break;
case SerialPacket::Type::SYNCHRONIZE:
case NetworkPacket::Type::SYNCHRONIZE:
HandleSynchronize(packet); HandleSynchronize(packet);
break; break;
case SerialPacket::Type::SHUTDOWN:
case NetworkPacket::Type::SHUTDOWN:
HandleShutdown(packet); HandleShutdown(packet);
break; break;
case SerialPacket::Type::PLAYER_NEW:
case NetworkPacket::Type::PLAYER_NEW:
HandlePlayerNew(packet); HandlePlayerNew(packet);
break; break;
case SerialPacket::Type::PLAYER_DELETE:
case NetworkPacket::Type::PLAYER_DELETE:
HandlePlayerDelete(packet); HandlePlayerDelete(packet);
break; break;
case SerialPacket::Type::PLAYER_UPDATE:
case NetworkPacket::Type::PLAYER_UPDATE:
HandlePlayerUpdate(packet); HandlePlayerUpdate(packet);
break; break;
case SerialPacket::Type::REGION_REQUEST:
HandleRegionRequest(packet);
break;
//handle errors //handle errors
default: default:
throw(runtime_error("Unknown NetworkPacket::Type encountered")); throw(std::runtime_error("Unknown SerialPacket::Type encountered"));
break; break;
} }
} }
void ServerApplication::HandleBroadcastRequest(NetworkPacket packet) { //-------------------------
//send back the server's name //Handle various network input
packet.meta.type = NetworkPacket::Type::BROADCAST_RESPONSE; //-------------------------
void ServerApplication::HandleBroadcastRequest(SerialPacket packet) {
//send back the server's metadata
packet.meta.type = SerialPacket::Type::BROADCAST_RESPONSE;
//pack the data
//TODO: version info
snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str()); snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str());
network.Send(&packet.meta.srcAddress, &packet, sizeof(NetworkPacket)); packet.serverInfo.playerCount = playerMap.size();
packet.serverInfo.regionWidth = REGION_WIDTH;
packet.serverInfo.regionHeight = REGION_HEIGHT;
packet.serverInfo.regionDepth = REGION_DEPTH;
//send the data
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
} }
void ServerApplication::HandleJoinRequest(NetworkPacket packet) { void ServerApplication::HandleJoinRequest(SerialPacket packet) {
//TODO: prevent duplicate logins from the same address? //register the new client
ClientEntry newClient;
//create the new client, filling it with the correct info
Client newClient;
newClient.address = packet.meta.srcAddress; newClient.address = packet.meta.srcAddress;
clientMap[ClientEntry::uidCounter] = newClient;
//push the new client //send the client their index
clientMap[clientCounter] = newClient; char buffer[PACKET_BUFFER_SIZE];
packet.meta.type = SerialPacket::Type::JOIN_RESPONSE;
packet.clientInfo.index = ClientEntry::uidCounter;
serialize(&packet, buffer);
//send the client their info //bounce this packet
packet.meta.type = NetworkPacket::Type::JOIN_RESPONSE; network.Send(&newClient.address, buffer, PACKET_BUFFER_SIZE);
packet.clientInfo.index = clientCounter;
network.Send(&newClient.address, &packet, sizeof(NetworkPacket));
//finished this routine //finished this routine
clientCounter++; ClientEntry::uidCounter++;
cout << "connect, total: " << clientMap.size() << endl; std::cout << "Connect, total: " << clientMap.size() << std::endl;
} }
void ServerApplication::HandleDisconnect(NetworkPacket packet) { void ServerApplication::HandleDisconnect(SerialPacket packet) {
//TODO: authenticate who is disconnecting/kicking
//disconnect the specified client //disconnect the specified client
network.Send(&clientMap[packet.clientInfo.index].address, &packet, sizeof(NetworkPacket)); char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(&clientMap[packet.clientInfo.index].address, buffer, PACKET_BUFFER_SIZE);
clientMap.erase(packet.clientInfo.index); clientMap.erase(packet.clientInfo.index);
//delete players //prep the delete packet
erase_if(playerMap, [&](pair<int, Player> it) -> bool { SerialPacket delPacket;
delPacket.meta.type = SerialPacket::Type::PLAYER_DELETE;
//TODO: can this use DeletePlayer() instead?
//delete server and client side players
erase_if(playerMap, [&](std::pair<unsigned int, PlayerEntry> it) -> bool {
//find the internal players to delete
if (it.second.clientIndex == packet.clientInfo.index) { if (it.second.clientIndex == packet.clientInfo.index) {
NetworkPacket delPacket; //send the delete player command to all clients
//data to delete one specific player
delPacket.meta.type = NetworkPacket::Type::PLAYER_DELETE;
delPacket.playerInfo.playerIndex = it.first; delPacket.playerInfo.playerIndex = it.first;
//send to all
PumpPacket(delPacket); PumpPacket(delPacket);
//delete this player object
return true; return true;
} }
//don't delete this player object
return false; return false;
}); });
cout << "disconnect, total: " << clientMap.size() << endl; //finished this routine
std::cout << "Disconnect, total: " << clientMap.size() << std::endl;
} }
void ServerApplication::HandleSynchronize(NetworkPacket packet) { void ServerApplication::HandleSynchronize(SerialPacket packet) {
//TODO: compensate for large distances
//send all the server's data to this client //send all the server's data to this client
NetworkPacket newPacket; SerialPacket newPacket;
char buffer[PACKET_BUFFER_SIZE];
//TODO: syncronize the map?
//players //players
newPacket.meta.type = NetworkPacket::Type::PLAYER_UPDATE; newPacket.meta.type = SerialPacket::Type::PLAYER_UPDATE;
for (auto& it : playerMap) { for (auto& it : playerMap) {
//TODO: update this for the expanded PlayerEntry structure
newPacket.playerInfo.playerIndex = it.first; newPacket.playerInfo.playerIndex = it.first;
snprintf(newPacket.playerInfo.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str()); snprintf(newPacket.playerInfo.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str());
snprintf(newPacket.playerInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str()); snprintf(newPacket.playerInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str());
newPacket.playerInfo.position = it.second.position; newPacket.playerInfo.position = it.second.position;
newPacket.playerInfo.motion = it.second.motion; newPacket.playerInfo.motion = it.second.motion;
network.Send(&clientMap[packet.clientInfo.index].address, &newPacket, sizeof(NetworkPacket)); serialize(&newPacket, buffer);
network.Send(&clientMap[packet.clientInfo.index].address, buffer, PACKET_BUFFER_SIZE);
} }
} }
void ServerApplication::HandleShutdown(NetworkPacket packet) { void ServerApplication::HandleShutdown(SerialPacket packet) {
//end the server //end the server
running = false; running = false;
//disconnect all clients //disconnect all clients
packet.meta.type = NetworkPacket::Type::DISCONNECT; packet.meta.type = SerialPacket::Type::DISCONNECT;
PumpPacket(packet); PumpPacket(packet);
cout << "shutting down" << endl; //finished this routine
std::cout << "Shutdown signal accepted" << std::endl;
} }
void ServerApplication::HandlePlayerNew(NetworkPacket packet) { void ServerApplication::HandlePlayerNew(SerialPacket packet) {
//create the new player object //register the new PlayerEntry
Player newPlayer; //NOTE: assigning each field one-by-one so adding or moving a field doesn't break this code
PlayerEntry newPlayer;
//metadata
newPlayer.clientIndex = packet.playerInfo.clientIndex; newPlayer.clientIndex = packet.playerInfo.clientIndex;
newPlayer.handle = packet.playerInfo.handle; newPlayer.handle = packet.playerInfo.handle;
newPlayer.avatar = packet.playerInfo.avatar; newPlayer.avatar = packet.playerInfo.avatar;
//position
newPlayer.mapIndex = 0;
newPlayer.position = {0,0}; newPlayer.position = {0,0};
newPlayer.motion = {0,0}; newPlayer.motion = {0,0};
newPlayer.bbox = {0, 0, 0, 0};
//stats
//TODO
//push this player //push this player
playerMap[playerCounter] = newPlayer; playerMap[PlayerEntry::uidCounter] = newPlayer;
//send the client their info //send the client their info
packet.playerInfo.playerIndex = playerCounter; packet.playerInfo.playerIndex = PlayerEntry::uidCounter;
packet.playerInfo.position = playerMap[playerCounter].position; packet.playerInfo.position = newPlayer.position;
packet.playerInfo.motion = playerMap[playerCounter].motion; packet.playerInfo.motion = newPlayer.motion;
//actually send to everyone //actually send to everyone
PumpPacket(packet); PumpPacket(packet);
//finish this routine //finish this routine
playerCounter++; PlayerEntry::uidCounter++;
} }
void ServerApplication::HandlePlayerDelete(NetworkPacket packet) { //TODO: differentiate between delete and unload
void ServerApplication::HandlePlayerDelete(SerialPacket packet) {
//TODO: authenticate who is deleting this player
if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) { if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) {
throw(std::runtime_error("Cannot delete a non-existant player")); throw(std::runtime_error("Cannot delete a non-existant player"));
} }
//delete players //TODO: remove the deleted player from the database?
erase_if(playerMap, [&](pair<int, Player> it) -> bool {
//prep the delete packet
SerialPacket delPacket;
delPacket.meta.type = SerialPacket::Type::PLAYER_DELETE;
//delete the specified playerEntry
erase_if(playerMap, [&](std::pair<unsigned int, PlayerEntry> it) -> bool {
//find the specified PlayerEntry
if (it.first == packet.playerInfo.playerIndex) { if (it.first == packet.playerInfo.playerIndex) {
NetworkPacket delPacket;
//data to delete one specific player
delPacket.meta.type = NetworkPacket::Type::PLAYER_DELETE;
delPacket.playerInfo.playerIndex = it.first;
//send to all //send to all
delPacket.playerInfo.playerIndex = it.first;
PumpPacket(delPacket); PumpPacket(delPacket);
//delete this player
return true; return true;
} }
//skip this player
return false; return false;
}); });
} }
void ServerApplication::HandlePlayerUpdate(NetworkPacket packet) { void ServerApplication::HandlePlayerUpdate(SerialPacket packet) {
if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) { if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) {
throw(std::runtime_error("Cannot update a non-existant player")); throw(std::runtime_error("Cannot update a non-existant player"));
} }
//server is the slave to the clients, but only for now //TODO: the server needs it's own movement system too
playerMap[packet.playerInfo.playerIndex].position = packet.playerInfo.position; playerMap[packet.playerInfo.playerIndex].position = packet.playerInfo.position;
playerMap[packet.playerInfo.playerIndex].motion = packet.playerInfo.motion; playerMap[packet.playerInfo.playerIndex].motion = packet.playerInfo.motion;
PumpPacket(packet); PumpPacket(packet);
} }
void ServerApplication::PumpPacket(NetworkPacket packet) { void ServerApplication::HandleRegionRequest(SerialPacket packet) {
//send this packet to all clients char buffer[PACKET_BUFFER_SIZE];
packet.meta.type = SerialPacket::Type::REGION_CONTENT;
packet.regionInfo.region = regionPager.GetRegion(packet.regionInfo.x, packet.regionInfo.y);
serialize(&packet, buffer);
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
}
void ServerApplication::PumpPacket(SerialPacket packet) {
//I don't really like this, but it'll do for now
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
for (auto& it : clientMap) { for (auto& it : clientMap) {
network.Send(&it.second.address, &packet, sizeof(NetworkPacket)); network.Send(&it.second.address, buffer, PACKET_BUFFER_SIZE);
} }
} }
+43 -33
View File
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2013, 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -22,67 +22,77 @@
#ifndef SERVERAPPLICATION_HPP_ #ifndef SERVERAPPLICATION_HPP_
#define SERVERAPPLICATION_HPP_ #define SERVERAPPLICATION_HPP_
//server specific stuff
#include "server_utility.hpp"
#include "client_entry.hpp"
#include "player_entry.hpp"
//maps
#include "map_allocator.hpp"
#include "map_file_format.hpp"
#include "region_pager.hpp"
//networking //networking
#include "network_packet.hpp" #include "serial_packet.hpp"
#include "udp_network_utility.hpp" #include "udp_network_utility.hpp"
#include "serial.hpp"
//APIs //common
#include "sqlite3/sqlite3.h"
#include "SDL/SDL.h"
//misc
#include "config_utility.hpp" #include "config_utility.hpp"
#include "vector2.hpp" #include "vector2.hpp"
#include "client.hpp" //APIs
#include "player.hpp" #include "lua/lua.hpp"
#include "sqlite3/sqlite3.h"
#include "SDL/SDL.h"
//STL //STL
#include <map> #include <map>
#include <string>
//The main application class //The main application class
class ServerApplication { class ServerApplication {
public: public:
//standard functions //standard functions
ServerApplication(); ServerApplication() = default;
~ServerApplication(); ~ServerApplication() = default;
void Init(int argc, char** argv); void Init(int argc, char** argv);
void Loop(); void Proc();
void Quit(); void Quit();
private: private:
void HandlePacket(NetworkPacket); void HandlePacket(SerialPacket);
//high cohesion utility functions //high cohesion utility functions
void HandleBroadcastRequest(NetworkPacket); void HandleBroadcastRequest(SerialPacket);
void HandleJoinRequest(NetworkPacket); void HandleJoinRequest(SerialPacket);
void HandleDisconnect(NetworkPacket); void HandleDisconnect(SerialPacket);
void HandleSynchronize(NetworkPacket); void HandleSynchronize(SerialPacket);
void HandleShutdown(NetworkPacket); void HandleShutdown(SerialPacket);
void HandlePlayerNew(NetworkPacket); void HandlePlayerNew(SerialPacket);
void HandlePlayerDelete(NetworkPacket); void HandlePlayerDelete(SerialPacket);
void HandlePlayerUpdate(NetworkPacket); void HandlePlayerUpdate(SerialPacket);
void HandleRegionRequest(SerialPacket);
void PumpPacket(NetworkPacket); //TODO: a function that only sends to players in a certain proximity
void PumpPacket(SerialPacket);
//networking //APIs
UDPNetworkUtility network; UDPNetworkUtility network;
//database
sqlite3* database = nullptr; sqlite3* database = nullptr;
lua_State* luaState = nullptr;
//server tables
std::map<unsigned int, ClientEntry> clientMap;
std::map<unsigned int, PlayerEntry> playerMap;
//maps
//TODO: I need to handle multiple map objects
RegionPager<LuaAllocator, LuaFormat> regionPager;
//misc //misc
bool running = true; bool running = true;
ConfigUtility config; ConfigUtility config;
//global lists
ClientMap clientMap;
PlayerMap playerMap;
int clientCounter = 0;
int playerCounter = 0;
}; };
#endif #endif
+50
View File
@@ -0,0 +1,50 @@
/* 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 "server_utility.hpp"
#include "utility.hpp"
#include <stdexcept>
#include <fstream>
#include <cstdlib>
int runSQLScript(sqlite3* db, std::string fname, int (*callback)(void*,int,char**,char**), void* argPtr) {
//load the file into a string
std::ifstream is(fname);
if (!is.is_open()) {
return -1;
}
std::string script;
getline(is, script, '\0');
is.close();
//run the SQL loaded from the file
char* errmsg = nullptr;
int ret = sqlite3_exec(db, script.c_str(), callback, argPtr, &errmsg);
if (ret != SQLITE_OK) {
//handle any errors received from the SQL
std::runtime_error e(std::string() + "SQL Script Error " + to_string_custom(ret) + ": " + errmsg);
free(errmsg);
throw(e);
}
return ret;
}
@@ -1,4 +1,4 @@
/* Copyright: (c) Kayne Ruse 2013 /* Copyright: (c) Kayne Ruse 2014
* *
* This software is provided 'as-is', without any express or implied * This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages * warranty. In no event will the authors be held liable for any damages
@@ -19,25 +19,13 @@
* 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.
*/ */
#ifndef PLAYER_HPP_ #ifndef SERVERUTILITY_HPP_
#define PLAYER_HPP_ #define SERVERUTILITY_HPP_
#include "vector2.hpp" #include "sqlite3/sqlite3.h"
#include <string> #include <string>
#include <map>
/* Hold the player info. int runSQLScript(sqlite3* db, std::string fname, int (*callback)(void*,int,char**,char**) = nullptr, void* argPtr = nullptr);
*/
struct Player {
int clientIndex;
std::string handle;
std::string avatar;
Vector2 position;
Vector2 motion;
};
typedef std::map<int, Player> PlayerMap;
#endif #endif