Compare commits

..

53 Commits

Author SHA1 Message Date
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
46 changed files with 1739 additions and 936 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.
@@ -13,14 +13,14 @@ This game is inspired by classic 2D RPGs, as well as more modern sandbox MMOs. T
## Documentation
[Tortuga Game Design Document](https://docs.google.com/document/d/17SjOTdacKKWX0Z-UkaiFnVnjfEeMsc5LRmARtnjh5UI/edit?usp=sharing)
[Tortuga Technical Document](https://docs.google.com/document/d/1ASTfM_1e0yE1cFP-IZey_rHEC6k2kmVY56X4K407sw0/edit?usp=sharing)
[Tortuga Game Design Document](https://github.com/Ratstail91/Tortuga/blob/docs/design%20doc.docx?raw=true)
[Tortuga Technical Document](https://github.com/Ratstail91/Tortuga/blob/docs/technical%20doc.docx?raw=true)
## Copyright
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.
+4 -9
View File
@@ -62,13 +62,13 @@ void ClientApplication::Init() {
if (SDL_Init(SDL_INIT_VIDEO)) {
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
if (SDLNet_Init()) {
throw(std::runtime_error("Failed to initialize SDL_net"));
}
network.Open(0, sizeof(NetworkPacket));
network.Open(0, PACKET_BUFFER_SIZE);
}
void ClientApplication::Proc() {
@@ -77,7 +77,7 @@ void ClientApplication::Proc() {
//prepare the time system
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 realTime;
@@ -95,15 +95,12 @@ void ClientApplication::Proc() {
//simulate game time
while (simTime < realTime) {
//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;
}
//draw the game to the screen
activeScene->RenderFrame();
//give the computer a break
SDL_Delay(10);
}
UnloadScene();
@@ -121,7 +118,6 @@ void ClientApplication::Quit() {
void ClientApplication::LoadScene(SceneList sceneIndex) {
UnloadScene();
switch(sceneIndex) {
//add scene creation calls here
case SceneList::FIRST:
@@ -143,7 +139,6 @@ void ClientApplication::LoadScene(SceneList sceneIndex) {
case SceneList::INCOMBAT:
activeScene = new InCombat();
break;
default:
throw(std::logic_error("Failed to recognize the scene index"));
}
+1 -1
View File
@@ -36,7 +36,7 @@ public:
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
void AdjustDirection(Direction);
+207 -23
View File
@@ -23,8 +23,15 @@
#include "channels.hpp"
#include <algorithm>
#include <cmath>
#include <stdexcept>
//debugging
#include <iostream>
using std::cout;
using std::endl;
//-------------------------
//Public access members
//-------------------------
@@ -35,26 +42,34 @@ InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNet
clientIndex(*argClientIndex)
{
//setup the utility objects
image.LoadSurface(config["dir.interface"] + "button_menu.bmp");
image.SetClipH(image.GetClipH()/3);
buttonImage.LoadSurface(config["dir.interface"] + "button_menu.bmp");
buttonImage.SetClipH(buttonImage.GetClipH()/3);
font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp");
//pass the utility objects
disconnectButton.SetImage(&image);
disconnectButton.SetImage(&buttonImage);
disconnectButton.SetFont(&font);
shutDownButton.SetImage(&image);
shutDownButton.SetImage(&buttonImage);
shutDownButton.SetFont(&font);
//set the button positions
disconnectButton.SetX(50);
disconnectButton.SetY(50 + image.GetClipH() * 0);
disconnectButton.SetY(50 + buttonImage.GetClipH() * 0);
shutDownButton.SetX(50);
shutDownButton.SetY(50 + image.GetClipH() * 1);
shutDownButton.SetY(50 + buttonImage.GetClipH() * 1);
//set the button texts
disconnectButton.SetText("Disconnect");
shutDownButton.SetText("Shut Down");
//load the tilesheet
tileSheet.Load(config["dir.tilesets"] + "terrain.bmp", 12, 15);
//setup the map object
mapPager.SetRegionWidth(REGION_WIDTH);
mapPager.SetRegionHeight(REGION_HEIGHT);
mapPager.SetRegionDepth(REGION_DEPTH);
//create the server-side player object
NetworkPacket packet;
packet.meta.type = NetworkPacket::Type::PLAYER_NEW;
@@ -65,11 +80,17 @@ InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNet
packet.playerInfo.motion = {0,0};
//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
packet.meta.type = NetworkPacket::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() {
@@ -85,29 +106,59 @@ void InWorld::FrameStart() {
}
void InWorld::Update(double delta) {
//suck in all waiting packets
NetworkPacket packet;
//suck in all waiting packets
while(network.Receive()) {
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket));
deserialize(&packet, network.GetInData());
packet.meta.srcAddress = network.GetInPacket()->address;
HandlePacket(packet);
}
//update the characters
for (auto& it : playerCharacters) {
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::RenderFrame() {
// SDL_FillRect(GetScreen(), 0, 0);
Render(GetScreen());
SDL_Flip(GetScreen());
}
void InWorld::Render(SDL_Surface* const screen) {
for (auto& it : playerCharacters) {
it.second.DrawTo(screen);
//draw the map
for (auto it = mapPager.GetContainer()->begin(); it != mapPager.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);
shutDownButton.DrawTo(screen);
font.DrawStringTo(to_string_custom(fps.GetFrameRate()), screen, 0, 0);
fps.Calculate();
}
//-------------------------
@@ -209,24 +260,27 @@ void InWorld::KeyUp(SDL_KeyboardEvent const& key) {
}
}
//-------------------------
//Network handlers
//-------------------------
void InWorld::HandlePacket(NetworkPacket packet) {
switch(packet.meta.type) {
case NetworkPacket::Type::DISCONNECT:
HandleDisconnect(packet);
break;
case NetworkPacket::Type::PLAYER_NEW:
HandlePlayerNew(packet);
break;
case NetworkPacket::Type::PLAYER_DELETE:
HandlePlayerDelete(packet);
break;
case NetworkPacket::Type::PLAYER_UPDATE:
HandlePlayerUpdate(packet);
break;
case NetworkPacket::Type::REGION_CONTENT:
HandleRegionContent(packet);
break;
//handle errors
default:
throw(std::runtime_error("Unknown NetworkPacket::Type encountered"));
@@ -254,6 +308,12 @@ void InWorld::HandlePlayerNew(NetworkPacket packet) {
if (packet.playerInfo.clientIndex == clientIndex && !localCharacter) {
playerIndex = packet.playerInfo.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);
}
}
@@ -285,31 +345,155 @@ void InWorld::HandlePlayerUpdate(NetworkPacket packet) {
playerCharacters[packet.playerInfo.playerIndex].ResetDirection();
}
void InWorld::HandleRegionContent(NetworkPacket packet) {
//replace existing regions
if (mapPager.FindRegion(packet.regionInfo.x, packet.regionInfo.y)) {
mapPager.UnloadRegion(packet.regionInfo.x, packet.regionInfo.y);
}
mapPager.PushRegion(packet.regionInfo.region);
packet.regionInfo.region = nullptr;
//debugging
cout << "Received region: " << packet.regionInfo.x << ", " << packet.regionInfo.y << endl;
if (mapPager.FindRegion(packet.regionInfo.x, packet.regionInfo.y)) {
cout << "Success" << endl;
}
else {
cout << "Failure" << endl;
}
}
//-------------------------
//Server control
//-------------------------
void InWorld::SendState() {
NetworkPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//pack the packet
packet.meta.type = NetworkPacket::Type::PLAYER_UPDATE;
packet.playerInfo.clientIndex = clientIndex;
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.motion = localCharacter->GetMotion();
network.Send(Channels::SERVER, &packet, sizeof(NetworkPacket));
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
}
void InWorld::RequestDisconnect() {
//send a disconnect request
NetworkPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//send a disconnect request
packet.meta.type = NetworkPacket::Type::DISCONNECT;
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() {
//send a shutdown request
NetworkPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//send a shutdown request
packet.meta.type = NetworkPacket::Type::SHUTDOWN;
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) {
NetworkPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//pack the region's data
packet.meta.type = NetworkPacket::Type::REGION_REQUEST;
packet.regionInfo.x = x;
packet.regionInfo.y = y;
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
}
//-------------------------
//Utilities
//-------------------------
int InWorld::CheckBufferDistance(Region* const region) {
/* DOCUMENTATION
* This algorithm is extremely complex and involed, but initial tests show
* that it gives the right answers. The purpose is to determine how far off screen
* a certain region is, so that it can be unloaded when necessary.
*
* If the region is actually onscreen, then there's no reason to run the rest, so
* the algorithm corrects for the camera's location, before checking the bounds of
* the screen.
*
* The next part is tricky. If X or Y is negative, then it is divided by the
* graphical size of the regions, resulting in a usable integer, representing how
* far from the screen it is in "region units". If, however, X or Y is larger than
* 0, than first, the size of the screen is subtracted from that variable, before
* it is then divided by the graphical size of a region. Finally, to compensate for
* the off by one error, 1 is added at the end.
*
* Since only the magnitude of the distance in either direction is needed, this
* method returns the largest absolute value of X or Y.
*
* The final result of this algorithm is an integer representing how far, rounded
* up, a certain region is from the screen's edges in any direction, measured in
* "region units". This algorithm may be flawed, in which case, I recommend simply
* replacing it with a boolean check, to see if the region's distance from the player
* is larger than a certain value. This algorithm lacks the advantages I initially
* expected, so that may be beneficial at some point.
*/
//locations relative to the camera
int x = region->GetX() - camera.x;
int y = region->GetY() - camera.y;
//if the region is visible, return -1
if (x >= -mapPager.GetRegionWidth() * tileSheet.GetTileW() && x < camera.width &&
y >= -mapPager.GetRegionHeight() * tileSheet.GetTileH() && y < camera.height) {
return -1;
}
//prune the screen's area from the algorithm; get the pseudo-indexes
if (x < 0) x /= (mapPager.GetRegionWidth() * tileSheet.GetTileW());
if (y < 0) y /= (mapPager.GetRegionHeight() * tileSheet.GetTileH());
if (x > 0) x = (x - camera.width) / (mapPager.GetRegionWidth() * tileSheet.GetTileW()) + 1;
if (y > 0) y = (y - camera.height) / (mapPager.GetRegionHeight() * tileSheet.GetTileH()) + 1;
//return the pseudo-index with the greatest magnitude
return std::max(abs(x), abs(y));
}
void InWorld::UpdateMap() {
//prune distant regions
for (auto it = mapPager.GetContainer()->begin(); it != mapPager.GetContainer()->end(); /* EMPTY */) {
if (CheckBufferDistance(*it) > 2) {
//debugging
cout << "unloading: " << (*it)->GetX() << ", " << (*it)->GetY() << endl;
mapPager.UnloadRegion((*it)->GetX(), (*it)->GetY());
//reset
it = mapPager.GetContainer()->begin();
continue;
}
++it;
}
//TODO: make the region units official
int regionUnitX = mapPager.GetRegionWidth() * tileSheet.GetTileW();
int regionUnitY = mapPager.GetRegionHeight() * tileSheet.GetTileH();
//request empty regions, including buffers (-1 & +1 region unit)
for (int i = snapToBase(regionUnitX, camera.x - regionUnitX); i <= snapToBase(regionUnitX, camera.x + camera.width + regionUnitX); i += regionUnitX) {
for (int j = snapToBase(regionUnitY, camera.y - regionUnitY); j <= snapToBase(regionUnitY, camera.y + camera.height + regionUnitY); j += regionUnitY) {
if (!mapPager.FindRegion(i, j)) {
RequestRegion(i, j);
}
}
}
}
+43 -5
View File
@@ -22,16 +22,31 @@
#ifndef INWORLD_HPP_
#define INWORLD_HPP_
#include "base_scene.hpp"
//maps
#include "map_generator.hpp"
#include "map_file_format.hpp"
#include "region_pager.hpp"
#include "config_utility.hpp"
//networking
#include "udp_network_utility.hpp"
#include "network_packet.hpp"
#include "serial.hpp"
//graphics
#include "image.hpp"
#include "raster_font.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"
//STL
#include <map>
class InWorld : public BaseScene {
@@ -45,6 +60,7 @@ protected:
void FrameStart();
void Update(double delta);
void FrameEnd();
void RenderFrame();
void Render(SDL_Surface* const);
//Event handlers
@@ -55,26 +71,48 @@ protected:
void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&);
//Network handlers
void HandlePacket(NetworkPacket);
void HandleDisconnect(NetworkPacket);
void HandlePlayerNew(NetworkPacket);
void HandlePlayerDelete(NetworkPacket);
void HandlePlayerUpdate(NetworkPacket);
void HandleRegionContent(NetworkPacket);
//Server control
void SendState();
void RequestDisconnect();
void RequestShutDown();
void RequestRegion(int x, int y);
//global
//utilities
int CheckBufferDistance(Region* const);
void UpdateMap();
//globals
ConfigUtility& config;
FrameRate fps;
UDPNetworkUtility& network;
int& clientIndex;
//members
Image image;
//graphics
Image buttonImage;
RasterFont font;
TileSheet tileSheet;
//map
RegionPager<BlankGenerator, DummyFormat> mapPager;
//UI
Button disconnectButton;
Button shutDownButton;
struct {
int x = 0, y = 0;
int width = 0, height = 0;
int marginX = 0, marginY = 0;
} camera;
//game
std::map<int, PlayerCharacter> playerCharacters;
PlayerCharacter* localCharacter = nullptr;
int playerIndex = -1;
+13 -5
View File
@@ -80,7 +80,7 @@ void LobbyMenu::Update(double delta) {
//suck in all waiting packets
NetworkPacket packet;
while(network.Receive()) {
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket));
deserialize(&packet, network.GetInData());
packet.meta.srcAddress = network.GetInPacket()->address;
HandlePacket(packet);
}
@@ -125,10 +125,14 @@ void LobbyMenu::MouseButtonDown(SDL_MouseButtonEvent const& button) {
void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
if (search.MouseButtonUp(button) == Button::State::HOVER) {
//broadcast to the network, or a specific server
//the vars
NetworkPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//broadcast to the network, or a specific server
packet.meta.type = NetworkPacket::Type::BROADCAST_REQUEST;
network.Send(config["server.host"].c_str(), config.Int("server.port"), reinterpret_cast<void*>(&packet), sizeof(NetworkPacket));
serialize(&packet, buffer);
network.Send(config["server.host"].c_str(), config.Int("server.port"), buffer, PACKET_BUFFER_SIZE);
//reset the server list
serverInfo.clear();
@@ -136,10 +140,14 @@ void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
}
else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr) {
//join the selected server
//the vars
NetworkPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//join the selected server
packet.meta.type = NetworkPacket::Type::JOIN_REQUEST;
network.Send(&selection->address, &packet, sizeof(NetworkPacket));
serialize(&packet, buffer);
network.Send(&selection->address, buffer, PACKET_BUFFER_SIZE);
selection = nullptr;
}
+1
View File
@@ -31,6 +31,7 @@
#include "config_utility.hpp"
#include "udp_network_utility.hpp"
#include "network_packet.hpp"
#include "serial.hpp"
#include <vector>
+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
* 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
* distribution.
*/
#ifndef TILE_HPP_
#define TILE_HPP_
#ifndef FRAMERATE_HPP_
#define FRAMERATE_HPP_
//explicitly a POD
struct Tile {
//position relative to the Region
int x, y, depth;
#include <chrono>
//graphics
int width, height;
int tileIndex;
class FrameRate {
public:
typedef std::chrono::high_resolution_clock Clock;
Tile() = default;
Tile(int _x, int _y, int _depth, int _width, int _height, int _tileIndex) {
//The order of the arguments should be explicit
x = _x;
y = _y;
depth = _depth;
width = _width;
height = _height;
tileIndex = _tileIndex;
FrameRate() = default;
int Calculate() {
frameCount++;
if (Clock::now() - tick >= std::chrono::duration<int>(1)) {
lastFrameRate = frameCount;
frameCount = 0;
tick = Clock::now();
}
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
+1 -1
View File
@@ -1,5 +1,5 @@
#config
INCLUDES+=. ..
INCLUDES+=. .. ../map
LIBS+=
CXXFLAGS+=-std=c++11 -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->GetWidth(); ++i) {
for (register int j = 0; j < region->GetHeight(); ++j) {
for (register int k = 0; k < region->GetDepth(); ++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);
}
}
}
}
+54
View File
@@ -0,0 +1,54 @@
/* 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 TILESHEET_HPP_
#define TILESHEET_HPP_
#include "region.hpp"
#include "image.hpp"
#include <string>
class TileSheet {
public:
TileSheet() = default;
TileSheet(std::string f, int x, int y) { Load(f, x, y); }
~TileSheet() = default;
void Load(std::string fname, int XCount, int YCount);
void Unload();
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);
//accessors
Image* GetImage() { return &image; }
int GetXCount() { return XCount; }
int GetYCount() { return YCount; }
int GetTileW() { return image.GetClipW(); }
int GetTileH() { return image.GetClipH(); }
private:
Image image;
int XCount = 0, YCount = 0;
};
#endif
+1
View File
@@ -22,6 +22,7 @@ all: $(OBJ) $(OUT)
ar -crs $(OUT) $(OBJ)
$(MAKE) -C graphics
$(MAKE) -C map
$(MAKE) -C script
$(MAKE) -C network
$(MAKE) -C ui
+79
View File
@@ -0,0 +1,79 @@
/* 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 width, int height, int depth, int x, int y) {
//EMPTY
}
void DummyFormat::Save(Region* const ptr) {
//EMPTY
}
/*
void VerboseFormat::Load(Region** const ptr, int x, int y) {
//TODO
}
void VerboseFormat::Save(Region* const ptr) {
//TODO
}
void CompactFormat::Load(Region** const ptr, int x, int y) {
//TODO
}
void CompactFormat::Save(Region* const ptr) {
//TODO
}
*/
void LuaFormat::Load(Region** const ptr, int width, int height, int depth, int x, int y) {
//something to load into
(*ptr) = new Region(width, height, depth, 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);
}
+79
View File
@@ -0,0 +1,79 @@
/* 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 width, int height, int depth, 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;
};
/*
class VerboseFormat {
public:
void Load(Region** const, int width, int height, int depth, 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;
};
class CompactFormat {
public:
void Load(Region** const, int width, int height, int depth, 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;
};
*/
class LuaFormat {
public:
void Load(Region** const, int width, int height, int depth, 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
+68
View File
@@ -0,0 +1,68 @@
/* 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_generator.hpp"
#include <stdexcept>
void BlankGenerator::Create(Region** const ptr, int width, int height, int depth, int x, int y) {
(*ptr) = new Region(width, height, depth, x, y);
}
void BlankGenerator::Unload(Region* const ptr) {
delete ptr;
}
/*
void PerlinGenerator::Create(Region** const ptr, int width, int height, int depth, int x, int y) {
(*ptr) = new Region(width, height, depth, x, y);
}
void PerlinGenerator::Unload(Region* const ptr) {
delete ptr;
}
*/
void LuaGenerator::Create(Region** const ptr, int width, int height, int depth, int x, int y) {
//something to work on
(*ptr) = new Region(width, height, depth, 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 LuaGenerator::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
* warranty. In no event will the authors be held liable for any damages
@@ -19,33 +19,38 @@
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef TILESHEETMANAGER_HPP_
#define TILESHEETMANAGER_HPP_
#ifndef MAPGENERATOR_HPP_
#define MAPGENERATOR_HPP_
#include "tile_sheet.hpp"
#include "region.hpp"
#include <map>
#include <string>
#include "lua/lua.hpp"
class TileSheetManager {
class BlankGenerator {
public:
TileSheetManager() = default;
~TileSheetManager() = default;
TileSheet* LoadSheet(std::string fname, Uint16 w, Uint16 h);
TileSheet* GetSheet(std::string name);
TileSheet* GetSheetByIndex(int tileIndex);
void UnloadSheet(std::string name);
void DrawTo(SDL_Surface* const, int x, int y, int tileIndex);
int SetRangeEnd(int i) { return rangeEnd += i; }
int GetRangeEnd() const { return rangeEnd; }
std::map<std::string, TileSheet>* GetSheetMap() { return &sheetMap; }
void Create(Region** const, int width, int height, int depth, int x, int y);
void Unload(Region* const);
private:
std::map<std::string, TileSheet> sheetMap;
int rangeEnd = 0;
//
};
/*
class PerlinGenerator {
public:
void Create(Region** const, int width, int height, int depth, int x, int y);
void Unload(Region* const);
private:
//
};
*/
class LuaGenerator {
public:
void Create(Region** const, int width, int height, int depth, 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
+26 -90
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
* warranty. In no event will the authors be held liable for any damages
@@ -21,103 +21,39 @@
*/
#include "region.hpp"
#include "utility.hpp"
#include <stdexcept>
#include <sstream>
Region::Region(int _x, int _y, int _w, int _h):
x(_x),
y(_y),
width(_w),
height(_h)
Region::Region(int argWidth, int argHeight, int argDepth, int argX, int argY):
width(argWidth),
height(argHeight),
depth(argDepth),
x(argX),
y(argY)
{
//make sure that the region's position lines up
if (x != snapToBase(width, x) || y != snapToBase(height, y)) {
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) {
//return 1 for overwrite, 0 for insert
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) {
std::set<Tile>::iterator ptr = tiles.begin();
//skip the tiles that are too deep
while(ptr != tiles.end()) {
if (ptr->depth >= minDepth) {
break;
tiles = new type_t**[width];
for (register int i = 0; i < width; ++i) {
tiles[i] = new type_t*[height];
for (register int j = 0; j < height; ++j) {
tiles[i][j] = new type_t[depth];
for (register int k = 0; k < depth; ++k) {
tiles[i][j][k] = 0;
}
}
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;
Region::~Region() {
for (register int i = 0; i < width; ++i) {
for (register int j = 0; j < height; j++) {
delete tiles[i][j];
}
ptr++;
delete tiles[i];
}
//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};
delete tiles;
}
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);
Region::type_t Region::SetTile(int x, int y, int z, type_t v) {
return tiles[x][y][z] = v;
}
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);
Region::type_t Region::GetTile(int x, int y, int z) {
return tiles[x][y][z];
}
+22 -77
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
* warranty. In no event will the authors be held liable for any damages
@@ -22,91 +22,36 @@
#ifndef REGION_HPP_
#define REGION_HPP_
#include "tile.hpp"
//temporary?
#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 {
public:
typedef unsigned short type_t;
Region() = delete;
Region(int x, int y, int width, int height);
~Region() = default;
Region(int width, int height, int depth, int x, int y);
~Region();
//create and insert a new tile, overwriting an existing tile at that location
int NewTileR(Tile const& tile);
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
});
}
type_t SetTile(int x, int y, int z, type_t v);
type_t GetTile(int x, int y, int z);
//find the first tile at this location, with the specified minimum depth
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 GetY() const { return y; }
//accessors
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);
int GetDepth() const { return depth; }
int GetX() const { return x; }
int GetY() const { return y; }
private:
int const x;
int const y;
int const width;
int const height;
std::set<Tile> tiles;
const int width;
const int height;
const int depth;
const int x;
const int y;
type_t*** tiles = nullptr;
};
#endif
+46 -90
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
* warranty. In no event will the authors be held liable for any damages
@@ -23,99 +23,55 @@
#include "utility.hpp"
#include <stdexcept>
#include <string>
RegionPager::RegionPager() {
//
RegionPagerBase::RegionPagerBase(int argWidth, int argHeight, int argDepth):
regionWidth(argWidth),
regionHeight(argHeight),
regionDepth(argDepth)
{
//EMPTY
}
RegionPager::~RegionPager() {
if (onDelete) {
for (auto& i : regionList) {
onDelete(&i);
RegionPagerBase::~RegionPagerBase() {
//EMPTY
}
Region::type_t RegionPagerBase::SetTile(int x, int y, int z, Region::type_t v) {
Region* ptr = GetRegion(x, y);
return ptr->SetTile(x - ptr->GetX(), y - ptr->GetY(), z, v);
}
Region::type_t RegionPagerBase::GetTile(int x, int y, int z) {
Region* ptr = GetRegion(x, y);
return ptr->GetTile(x - ptr->GetX(), y - ptr->GetY(), z);
}
Region* RegionPagerBase::GetRegion(int x, int y) {
//snap the coords
x = snapToBase(regionWidth, x);
y = snapToBase(regionHeight, y);
//get the region by various means
//TODO: revert this try/catch point
Region* ptr = nullptr;
ptr = FindRegion(x, y);
if (ptr) return ptr;
ptr = LoadRegion(x, y);
if (ptr) return ptr;
return CreateRegion(x, y);
}
Region* RegionPagerBase::FindRegion(int x, int y) {
//find the region
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) {
for (auto& i : regionList) {
if (i.GetX() == x && i.GetY() == y) {
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++;
}
Region* RegionPagerBase::PushRegion(Region* ptr) {
regionList.push_front(ptr);
return regionList.front();
}
+116 -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
* warranty. In no event will the authors be held liable for any damages
@@ -23,47 +23,135 @@
#define REGIONPAGER_HPP_
#include "region.hpp"
#include "tile_sheet_manager.hpp"
#include "utility.hpp"
#include <list>
class RegionPager {
class RegionPagerBase {
public:
//for simplicity and consistency
typedef void (*regionCallback_t)(Region* const);
RegionPagerBase() = default;
RegionPagerBase(int regionWidth, int regionHeight, int regionDepth);
virtual ~RegionPagerBase();
RegionPager();
~RegionPager();
//tile manipulation
Region::type_t SetTile(int x, int y, int z, Region::type_t v);
Region::type_t GetTile(int x, int y, int z);
//these parameters MUST be multiples of the width & height
Region* NewRegion(int x, int y);
//region manipulation
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
void DrawTo(SDL_Surface* const, TileSheetManager* const, int camX, int camY);
//interface
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?
//callback hooks
void SetOnNew(regionCallback_t f) { onNew = f; }
void SetOnDelete(regionCallback_t f) { onDelete = f; }
//accessors & mutators
//NOTE: don't change the sizes mid-program, it will cause issues
int SetRegionWidth(int i) { return regionWidth = i; }
int SetRegionHeight(int i) { return regionHeight = i; }
int SetRegionDepth(int i) { return regionDepth = i; }
//params: Absolute values
void Prune(int left, int top, int right, int bottom);
int GetRegionWidth() const { return regionWidth; }
int GetRegionHeight() const { return regionHeight; }
int GetRegionDepth() const { return regionDepth; }
//accessors and mutators
int SetWidth(int i) { return regionWidth = i; }
int SetHeight(int i) { return regionHeight = i; }
std::list<Region*>* GetContainer() { return &regionList; }
protected:
int regionWidth;
int regionHeight;
int regionDepth;
std::list<Region*> regionList;
};
int GetWidth() const { return regionWidth; }
int GetHeight() const { return regionHeight; }
template<typename MapGenerator, typename MapFileFormat>
class RegionPager : public RegionPagerBase {
public:
RegionPager() = default;
RegionPager(int w, int h, int d):
RegionPagerBase(w, h, d)
{
//EMPTY
}
~RegionPager() {
UnloadAll();
}
std::list<Region>* GetRegions() { return &regionList; }
private:
std::list<Region> regionList;
int regionWidth = 0, regionHeight = 0;
Region* LoadRegion(int x, int y) {
//snap the coords
x = snapToBase(regionWidth, x);
y = snapToBase(regionHeight, y);
regionCallback_t onNew = nullptr;
regionCallback_t onDelete = nullptr;
//load the region if possible
Region* ptr = nullptr;
format.Load(&ptr, regionWidth, regionHeight, regionDepth, x, y);
if (ptr) {
regionList.push_back(ptr);
return ptr;
}
return nullptr;
}
Region* SaveRegion(int x, int y) {
//snap the coords
x = snapToBase(regionWidth, x);
y = snapToBase(regionHeight, y);
//find & save the region
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); it++) {
if ((*it)->GetX() == x && (*it)->GetY() == y) {
format.Save(*it);
return *it;
}
}
return nullptr;
}
Region* CreateRegion(int x, int y) {
//snap the coords
x = snapToBase(regionWidth, x);
y = snapToBase(regionHeight, y);
//create and push the object
Region* ptr = nullptr;
generator.Create(&ptr, regionWidth, regionHeight, regionDepth, x, y);
regionList.push_back(ptr);
return ptr;
}
void UnloadRegion(int x, int y) {
//snap the coords
x = snapToBase(regionWidth, x);
y = snapToBase(regionHeight, y);
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); /* EMPTY */) {
if ((*it)->GetX() == x && (*it)->GetY() == y) {
generator.Unload(*it);
regionList.erase(it);
//reset the loop, because of reasons
it = regionList.begin();
continue;
}
++it;
}
}
void UnloadAll() {
for (auto& it : regionList) {
generator.Unload(it);
}
regionList.clear();
}
//accessors
MapGenerator* GetGenerator() { return &generator; }
MapFileFormat* GetFormat() { return &format; }
protected:
MapGenerator generator;
MapFileFormat format;
};
#endif
-44
View File
@@ -1,44 +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.hpp"
bool operator<(Tile const& lhs, Tile const& rhs) {
//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) {
//wrap the other operator
return rhs < lhs;
}
inline bool operator==(Tile const& lhs, Tile 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) && (lhs.depth == rhs.depth);
}
-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
INCLUDES+=. ..
INCLUDES+=. .. ../map
LIBS+=
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
+15 -2
View File
@@ -22,9 +22,10 @@
#ifndef NETWORKPACKET_HPP_
#define NETWORKPACKET_HPP_
#include "SDL/SDL_net.h"
#include "vector2.hpp"
#include "region.hpp"
#include "SDL/SDL_net.h"
#define PACKET_STRING_SIZE 100
@@ -61,6 +62,10 @@ union NetworkPacket {
PLAYER_NEW = 10,
PLAYER_DELETE = 11,
PLAYER_UPDATE = 12,
//map data
REGION_REQUEST = 13,
REGION_CONTENT = 14,
};
//metadata on the packet itself
@@ -75,6 +80,7 @@ union NetworkPacket {
//TODO: version info
char name[PACKET_STRING_SIZE];
//TODO: player count
//TODO: map format
}serverInfo;
//information about the client
@@ -94,6 +100,13 @@ union NetworkPacket {
Vector2 motion;
}playerInfo;
//map data
struct RegionInformation {
Metadata meta;
int width, height, depth, x, y;
Region* region;
}regionInfo;
//defaults
NetworkPacket() {
meta.type = Type::NONE;
+299
View File
@@ -0,0 +1,299 @@
/* 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_generator.hpp"
#include <cstring>
//-------------------------
//internal serialization functions
//-------------------------
void serializeType(NetworkPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type));
}
void serializeServer(NetworkPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
memcpy(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
}
void serializeClient(NetworkPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
memcpy(buffer, &packet->clientInfo.index, sizeof(int));
}
void serializePlayer(NetworkPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::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(NetworkPacket* packet, char* buffer) {
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
//size
memcpy(buffer, &packet->regionInfo.width, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->regionInfo.height, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->regionInfo.depth, sizeof(int));
buffer += sizeof(int);
//x & y
memcpy(buffer, &packet->regionInfo.x, sizeof(int));
buffer += sizeof(int);
memcpy(buffer, &packet->regionInfo.y, sizeof(int));
}
void serializeRegionContent(NetworkPacket* packet, char* buffer) {
//format
memcpy(buffer, &packet->meta.type, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
//size
*reinterpret_cast<int*>(buffer) = packet->regionInfo.region->GetWidth();
buffer += sizeof(int);
*reinterpret_cast<int*>(buffer) = packet->regionInfo.region->GetHeight();
buffer += sizeof(int);
*reinterpret_cast<int*>(buffer) = packet->regionInfo.region->GetDepth();
buffer += sizeof(int);
//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 < packet->regionInfo.region->GetWidth(); i++) {
for (register int j = 0; j < packet->regionInfo.region->GetHeight(); j++) {
for (register int k = 0; k < packet->regionInfo.region->GetDepth(); k++) {
*reinterpret_cast<Region::type_t*>(buffer) = packet->regionInfo.region->GetTile(i, j, k);
buffer += sizeof(Region::type_t);
}
}
}
}
//-------------------------
//internal deserialization functions
//-------------------------
void deserializeType(NetworkPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type));
}
void deserializeServer(NetworkPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
memcpy(packet->serverInfo.name, buffer, PACKET_STRING_SIZE);
}
void deserializeClient(NetworkPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
memcpy(&packet->clientInfo.index, buffer, sizeof(int));
}
void deserializePlayer(NetworkPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::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(NetworkPacket* packet, char* buffer) {
memcpy(&packet->meta.type, buffer, sizeof(NetworkPacket::Type));
buffer += sizeof(NetworkPacket::Type);
//size
memcpy(&packet->regionInfo.width, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->regionInfo.height, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->regionInfo.depth, buffer, sizeof(int));
buffer += sizeof(int);
//x & y
memcpy(&packet->regionInfo.x, buffer, sizeof(int));
buffer += sizeof(int);
memcpy(&packet->regionInfo.y, buffer, sizeof(int));
}
void deserializeRegionContent(NetworkPacket* packet, char* buffer) {
//format
deserializeRegionFormat(packet, buffer);
buffer += sizeof(int) * 5 + sizeof(NetworkPacket::Type);
//content
BlankGenerator().Create(
&packet->regionInfo.region,
packet->regionInfo.width,
packet->regionInfo.height,
packet->regionInfo.depth,
packet->regionInfo.x,
packet->regionInfo.y
);
for (register int i = 0; i < packet->regionInfo.region->GetWidth(); i++) {
for (register int j = 0; j < packet->regionInfo.region->GetHeight(); j++) {
for (register int k = 0; k < packet->regionInfo.region->GetDepth(); k++) {
packet->regionInfo.region->SetTile(i, j, k, *reinterpret_cast<Region::type_t*>(buffer));
buffer += sizeof(Region::type_t);
}
}
}
}
//-------------------------
//the interface functions
//-------------------------
void serialize(NetworkPacket* packet, void* buffer) {
switch(packet->meta.type) {
//No extra data
case NetworkPacket::Type::NONE:
case NetworkPacket::Type::PING:
case NetworkPacket::Type::PONG:
case NetworkPacket::Type::BROADCAST_REQUEST:
case NetworkPacket::Type::JOIN_REQUEST:
case NetworkPacket::Type::SYNCHRONIZE:
serializeType(packet, reinterpret_cast<char*>(buffer));
break;
//Server info
case NetworkPacket::Type::BROADCAST_RESPONSE:
serializeServer(packet, reinterpret_cast<char*>(buffer));
break;
//Client info
case NetworkPacket::Type::JOIN_RESPONSE:
case NetworkPacket::Type::DISCONNECT:
case NetworkPacket::Type::SHUTDOWN:
serializeClient(packet, reinterpret_cast<char*>(buffer));
break;
//Player info
case NetworkPacket::Type::PLAYER_NEW:
case NetworkPacket::Type::PLAYER_DELETE:
case NetworkPacket::Type::PLAYER_UPDATE:
serializePlayer(packet, reinterpret_cast<char*>(buffer));
break;
//region info
case NetworkPacket::Type::REGION_REQUEST:
serializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
break;
case NetworkPacket::Type::REGION_CONTENT:
serializeRegionContent(packet, reinterpret_cast<char*>(buffer));
break;
}
}
void deserialize(NetworkPacket* 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 NetworkPacket::Type::NONE:
case NetworkPacket::Type::PING:
case NetworkPacket::Type::PONG:
case NetworkPacket::Type::BROADCAST_REQUEST:
case NetworkPacket::Type::JOIN_REQUEST:
case NetworkPacket::Type::SYNCHRONIZE:
//NOTHING
break;
//Server info
case NetworkPacket::Type::BROADCAST_RESPONSE:
deserializeServer(packet, reinterpret_cast<char*>(buffer));
break;
//Client info
case NetworkPacket::Type::JOIN_RESPONSE:
case NetworkPacket::Type::DISCONNECT:
case NetworkPacket::Type::SHUTDOWN:
deserializeClient(packet, reinterpret_cast<char*>(buffer));
break;
//Player info
case NetworkPacket::Type::PLAYER_NEW:
case NetworkPacket::Type::PLAYER_DELETE:
case NetworkPacket::Type::PLAYER_UPDATE:
deserializePlayer(packet, reinterpret_cast<char*>(buffer));
break;
//region info
case NetworkPacket::Type::REGION_REQUEST:
deserializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
break;
case NetworkPacket::Type::REGION_CONTENT:
deserializeRegionContent(packet, reinterpret_cast<char*>(buffer));
break;
}
}
+11 -17
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
* warranty. In no event will the authors be held liable for any damages
@@ -19,25 +19,19 @@
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef PLAYER_HPP_
#define PLAYER_HPP_
#ifndef SERIAL_HPP_
#define SERIAL_HPP_
#include "vector2.hpp"
#include "network_packet.hpp"
#include <string>
#include <map>
/* Hold the player info.
/* Sending regions are the largest type of packet
* content: width * height * depth * sizoeof(type)
* map format: sizeof(int) * 5
* metadata: sizeof(metadata)
*/
#define PACKET_BUFFER_SIZE REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) + sizeof(int) * 5 + sizeof(NetworkPacket::Metadata)
struct Player {
int clientIndex;
std::string handle;
std::string avatar;
Vector2 position;
Vector2 motion;
};
typedef std::map<int, Player> PlayerMap;
void serialize(NetworkPacket* const, void*);
void deserialize(NetworkPacket* const, void*);
#endif
+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
+91
View File
@@ -0,0 +1,91 @@
/* 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) {
Region* ptr = (Region*)lua_touserdata(L, 1);
lua_pushinteger(L, ptr->GetWidth());
return 1;
}
static int getHeight(lua_State* L) {
Region* ptr = (Region*)lua_touserdata(L, 1);
lua_pushinteger(L, ptr->GetHeight());
return 1;
}
static int getDepth(lua_State* L) {
Region* ptr = (Region*)lua_touserdata(L, 1);
lua_pushinteger(L, ptr->GetDepth());
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;
}
@@ -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
* warranty. In no event will the authors be held liable for any damages
@@ -19,20 +19,12 @@
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef CLIENT_HPP_
#define CLIENT_HPP_
#ifndef REGIONAPI_HPP_
#define REGIONAPI_HPP_
#include "SDL/SDL_net.h"
#include "lua/lua.hpp"
#include <map>
/* Hold the client info.
*/
struct Client {
IPaddress address;
};
typedef std::map<int, Client> ClientMap;
#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
if (x < 0) {
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) {
+98 -145
View File
@@ -50,25 +50,24 @@ EditorScene::EditorScene(ConfigUtility* const arg1):
menuBar.SetImage(&buttonImage);
menuBar.SetEntries({
{"File", "-New", "-Open", "-Save", "-Save As...", "-Close", "Exit"},
{"Edit", "-Set Tile", "-Load Sheet", "-Delete Sheet", "-Metadata", "-Run Script"},
{"Debugging", "Debug On", "Debug Off", "Toggle Debug", "Testificate"}
{"File", "New", "Open", "Save", "Close"},
{"Edit", "Set Tile", "Set Brush", "Script"},
{"Debug", "Debug On", "Debug Off", "Toggle", "Testificate"}
});
//setup the pager
pager.SetOnNew([](Region* const ptr){
printf("New Region: %d, %d\n", ptr->GetX(), ptr->GetY());
});
//setup the map
pager.SetRegionWidth(REGION_WIDTH);
pager.SetRegionHeight(REGION_HEIGHT);
pager.SetRegionDepth(REGION_DEPTH);
pager.SetOnDelete([](Region* const ptr){
printf("Delete Region: %d, %d\n", ptr->GetX(), ptr->GetY());
});
//Set a resonable size for the regions
pager.SetWidth(32*4);
pager.SetHeight(32*4);
sheetMgr.LoadSheet(config["dir.tilesets"] + "terrain.bmp", 32, 32);
//debug
tsheet.Load(config["dir.tilesets"] + "terrain.bmp", 12, 15);
for (int i = 0; i < REGION_WIDTH; i++) {
for (int j = 0; j < REGION_HEIGHT; j++) {
pager.SetTile(i, j, 0, 14);
}
}
pager.SetTile(5, 10, 1, 48);
}
EditorScene::~EditorScene() {
@@ -84,7 +83,7 @@ void EditorScene::FrameStart() {
}
void EditorScene::Update(double delta) {
pager.Prune(camera.x, camera.y, camera.x + GetScreen()->w, camera.y + GetScreen()->h);
//
}
void EditorScene::FrameEnd() {
@@ -92,10 +91,23 @@ void EditorScene::FrameEnd() {
}
void EditorScene::Render(SDL_Surface* const screen) {
//draw the map
pager.DrawTo(screen, &sheetMgr, camera.x, camera.y);
//draw a big bar across the top
tsheet.DrawRegionTo(screen, pager.GetRegion(0, 0), camera.x, camera.y);
/* //debug
for (int i = 0; i < pager.GetRegionWidth()*2; i++) {
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);
for (int i = 0; i < screen->w; i += buttonImage.GetClipW()) {
buttonImage.DrawTo(screen, i, 0);
@@ -114,13 +126,15 @@ void EditorScene::Render(SDL_Surface* const screen) {
}
void EditorScene::DrawToDebugInfo(std::string str, int line) {
//draw the debug info on the right
font.DrawStringTo(
str,
debugInfo.GetSurface(),
debugInfo.GetClipW() - str.size() * font.GetCharW(),
font.GetCharH() * line
);
//draw the debug info on the right, with a grey background
SDL_Rect clip = {
Sint16(debugInfo.GetClipW() - str.size() * font.GetCharW()),
Sint16(font.GetCharH() * line),
Uint16(str.size() * font.GetCharW()),
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 +144,6 @@ void EditorScene::DrawToDebugInfo(std::string str, int line) {
void EditorScene::MouseMotion(SDL_MouseMotionEvent const& 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) {
camera.x -= motion.xrel;
camera.y -= motion.yrel;
@@ -156,108 +152,12 @@ void EditorScene::MouseMotion(SDL_MouseMotionEvent const& motion) {
void EditorScene::MouseButtonDown(SDL_MouseButtonEvent const& 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) {
int entry, drop;
menuBar.MouseButtonUp(button, &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;
}
HandleMenuOption(entry, drop);
}
void EditorScene::KeyDown(SDL_KeyboardEvent const& key) {
@@ -265,12 +165,10 @@ void EditorScene::KeyDown(SDL_KeyboardEvent const& key) {
case SDLK_ESCAPE:
QuitEvent();
break;
case SDLK_SPACE:
camera.x = 0;
camera.y = 0;
break;
case SDLK_TAB:
debugOpen = !debugOpen;
break;
@@ -280,3 +178,58 @@ void EditorScene::KeyDown(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;
}
}
+9 -9
View File
@@ -24,15 +24,15 @@
#include "base_scene.hpp"
#include "region_pager.hpp"
#include "tile_sheet_manager.hpp"
#include "config_utility.hpp"
#include "image.hpp"
#include "raster_font.hpp"
#include "menu_bar.hpp"
//#include "map_loader.hpp"
#include "region_pager.hpp"
#include "map_generator.hpp"
#include "map_file_format.hpp"
#include "tile_sheet.hpp"
class EditorScene : public BaseScene {
public:
@@ -54,6 +54,9 @@ protected:
void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&);
//members
void HandleMenuOption(int entry, int drop);
//globals
ConfigUtility& config;
@@ -62,19 +65,16 @@ protected:
Image debugInfo;
bool debugOpen = true;
RegionPager pager;
TileSheetManager sheetMgr;
RasterFont font;
Image buttonImage;
MenuBar menuBar;
struct {
int x = 0, y = 0;
} camera;
int tileCounter = 0;
RegionPager<BlankGenerator, DummyFormat> pager;
TileSheet tsheet;
};
#endif
+1 -1
View File
@@ -1,6 +1,6 @@
#config
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))
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
+2 -18
View File
@@ -33,18 +33,7 @@ using std::endl;
TestificateScene::TestificateScene(ConfigUtility* const 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() {
@@ -68,12 +57,7 @@ void TestificateScene::FrameEnd() {
}
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 "config_utility.hpp"
#include "tile_Sheet_manager.hpp"
#include "region_pager.hpp"
class TestificateScene : public BaseScene {
public:
@@ -50,10 +48,6 @@ protected:
//globals
ConfigUtility& config;
//members
TileSheetManager sheetMgr;
RegionPager pager;
};
#endif
+5
View File
@@ -17,6 +17,11 @@ dir.tilesets = rsc/graphics/tilesets/
dir.interface = rsc/graphics/interface/
dir.scripts = rsc/scripts/
#map system
map.pager.width = 20
map.pager.height = 20
map.pager.depth = 3
#player options
player.handle = username
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
+1 -1
View File
@@ -1,5 +1,5 @@
#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
CXXFLAGS+=-std=c++11 -DDEBUG $(addprefix -I,$(INCLUDES))
CFLAGS+=-DDEBUG $(addprefix -I,$(INCLUDES))
+139 -78
View File
@@ -30,20 +30,28 @@
using namespace std;
//-------------------------
//Define the ServerApplication
//-------------------------
ServerApplication::ServerApplication() {
//
int runSQLScript(sqlite3* db, std::string fname) {
ifstream is(fname);
if (!is.is_open()) {
return -1;
}
string script;
getline(is, script, '\0');
is.close();
//TODO: flesh out this error if needed
if (sqlite3_exec(db, script.c_str(), nullptr, nullptr, nullptr) != SQLITE_OK) {
return -2;
}
return 0;
}
ServerApplication::~ServerApplication() {
//
}
//-------------------------
//Define the public members
//-------------------------
void ServerApplication::Init(int argc, char** argv) {
//TODO: proper command line option parsing
cout << "Beginning startup" << endl;
int ret = 0;
//load config
config.Load("rsc\\config.cfg");
@@ -52,101 +60,129 @@ void ServerApplication::Init(int argc, char** argv) {
if (SDL_Init(0)) {
throw(runtime_error("Failed to initialize SDL"));
}
cout << "initialized SDL" << endl;
cout << "Initialized SDL" << endl;
//Init SDL_net
if (SDLNet_Init()) {
throw(runtime_error("Failed to init SDL_net"));
throw(runtime_error("Failed to initialize SDL_net"));
}
network.Open(config.Int("server.port"), sizeof(NetworkPacket));
cout << "initialized SDL_net" << endl;
network.Open(config.Int("server.port"), PACKET_BUFFER_SIZE);
cout << "Initialized SDL_net" << endl;
//Init SQL
string dbname = (config["server.dbname"].size()) ? config["server.dbname"] : std::string(argv[0]) + ".db"; //fancy and unnecessary
int ret = sqlite3_open_v2(dbname.c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_FULLMUTEX, nullptr);
ret = sqlite3_open_v2(config["server.dbname"].c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, nullptr);
if (ret != SQLITE_OK || !database) {
throw(runtime_error("Failed to open the server database"));
throw(runtime_error(string() + "Failed to initialize SQL: " + sqlite3_errmsg(database) ));
}
cout << "initialized SQL" << endl;
cout << "Database filename: " << dbname << endl;
cout << "Initialized SQL" << endl;
//TODO: move this into a function?
//Run setup scripts
ifstream is("rsc\\scripts\\setup_server.sql");
if (!is.is_open()) {
throw(runtime_error("Failed to run database setup script"));
//setup the database
if (runSQLScript(database, config["dir.scripts"] + "setup_server.sql")) {
throw(runtime_error("Failed to initialize SQL's setup script"));
}
string script;
getline(is, script, '\0');
is.close();
sqlite3_exec(database, script.c_str(), nullptr, nullptr, nullptr);
cout << "Initialized SQL's setup script" << endl;
//lua
luaState = luaL_newstate();
if (!luaState) {
throw(runtime_error("Failed to initialize lua"));
}
luaL_openlibs(luaState);
cout << "Initialized lua" << endl;
//run the startup script
if (luaL_dofile(luaState, (config["dir.scripts"] + "setup_server.lua").c_str())) {
throw(runtime_error(string() + "Failed to initialize lua's setup script: " + lua_tostring(luaState, -1) ));
}
cout << "Initialized lua's setup script" << endl;
//setup the map object
mapPager.SetRegionWidth(REGION_WIDTH);
mapPager.SetRegionHeight(REGION_HEIGHT);
mapPager.SetRegionDepth(REGION_DEPTH);
mapPager.GetGenerator()->SetLuaState(luaState);
mapPager.GetFormat()->SetLuaState(luaState);
mapPager.GetFormat()->SetSaveDir("save/mapname/");
//TODO: pass args to the generator & format as needed
//NOTE: I might need to rearrange the init process so that lua & SQL can interact
// with the map system as needed.
cout << "Initialized the map system" << endl;
cout << "\tsizeof(NetworkPacket): " << sizeof(NetworkPacket) << endl;
cout << "\tPACKET_BUFFER_SIZE: " << PACKET_BUFFER_SIZE << endl;
//finalize the startup
cout << "Startup completed successfully" << endl;
//debugging
//
}
void ServerApplication::Loop() {
NetworkPacket packet;
while(running) {
//suck in the waiting packets & process them
try {
while(network.Receive()) {
memcpy(&packet, network.GetInData(), sizeof(NetworkPacket));
packet.meta.srcAddress = network.GetInPacket()->address;
HandlePacket(packet);
}
while(network.Receive()) {
//get the packet
deserialize(&packet, network.GetInData());
//cache the source address
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
SDL_Delay(10);
}
}
void ServerApplication::Quit() {
//members
network.Close();
cout << "Shutting down" << endl;
//empty the members
mapPager.UnloadAll();
//TODO: player manager
//TODO: client manager
//APIs
lua_close(luaState);
sqlite3_close_v2(database);
network.Close();
SDLNet_Quit();
SDL_Quit();
cout << "Shutdown finished" << endl;
}
//-------------------------
//Define the uber switch
//-------------------------
void ServerApplication::HandlePacket(NetworkPacket packet) {
switch(packet.meta.type) {
case NetworkPacket::Type::BROADCAST_REQUEST:
HandleBroadcastRequest(packet);
break;
case NetworkPacket::Type::JOIN_REQUEST:
HandleJoinRequest(packet);
break;
case NetworkPacket::Type::DISCONNECT:
HandleDisconnect(packet);
break;
case NetworkPacket::Type::SYNCHRONIZE:
HandleSynchronize(packet);
break;
case NetworkPacket::Type::SHUTDOWN:
HandleShutdown(packet);
break;
case NetworkPacket::Type::PLAYER_NEW:
HandlePlayerNew(packet);
break;
case NetworkPacket::Type::PLAYER_DELETE:
HandlePlayerDelete(packet);
break;
case NetworkPacket::Type::PLAYER_UPDATE:
HandlePlayerUpdate(packet);
break;
case NetworkPacket::Type::REGION_REQUEST:
HandleRegionRequest(packet);
break;
//handle errors
default:
throw(runtime_error("Unknown NetworkPacket::Type encountered"));
@@ -154,61 +190,73 @@ void ServerApplication::HandlePacket(NetworkPacket packet) {
}
}
//-------------------------
//Handle various network input
//-------------------------
void ServerApplication::HandleBroadcastRequest(NetworkPacket packet) {
//send back the server's name
//send back the server's metadata
packet.meta.type = NetworkPacket::Type::BROADCAST_RESPONSE;
//TODO: version info
snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str());
network.Send(&packet.meta.srcAddress, &packet, sizeof(NetworkPacket));
//TODO: player count
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
}
void ServerApplication::HandleJoinRequest(NetworkPacket packet) {
//TODO: prevent duplicate logins from the same address?
//create the new client, filling it with the correct info
Client newClient;
newClient.address = packet.meta.srcAddress;
//push the new client
clientMap[clientCounter] = newClient;
//register the new client
ClientEntry c;
c.address = packet.meta.srcAddress;
clientMap[clientCounter] = c;
//send the client their info
char buffer[PACKET_BUFFER_SIZE];
packet.meta.type = NetworkPacket::Type::JOIN_RESPONSE;
packet.clientInfo.index = clientCounter;
network.Send(&newClient.address, &packet, sizeof(NetworkPacket));
serialize(&packet, buffer);
network.Send(&clientMap[clientCounter].address, buffer, PACKET_BUFFER_SIZE);
//finished this routine
clientCounter++;
cout << "connect, total: " << clientMap.size() << endl;
cout << "Connect, total: " << clientMap.size() << endl;
}
void ServerApplication::HandleDisconnect(NetworkPacket packet) {
//disconnect the specified client
network.Send(&clientMap[packet.clientInfo.index].address, &packet, sizeof(NetworkPacket));
//TODO: authenticate who is disconnecting/kicking
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(&clientMap[packet.clientInfo.index].address, buffer, PACKET_BUFFER_SIZE);
clientMap.erase(packet.clientInfo.index);
//delete players
erase_if(playerMap, [&](pair<int, Player> it) -> bool {
//delete players from all clients
NetworkPacket delPacket;
delPacket.meta.type = NetworkPacket::Type::PLAYER_DELETE;
erase_if(playerMap, [&](std::pair<int, PlayerEntry> it) -> bool {
//find the internal players to delete
if (it.second.clientIndex == packet.clientInfo.index) {
NetworkPacket delPacket;
//data to delete one specific player
delPacket.meta.type = NetworkPacket::Type::PLAYER_DELETE;
delPacket.playerInfo.playerIndex = it.first;
//send to all
//send the delete player command to all clients
PumpPacket(delPacket);
return true;
}
return false;
});
cout << "disconnect, total: " << clientMap.size() << endl;
//finished this routine
cout << "Disconnect, total: " << clientMap.size() << endl;
}
void ServerApplication::HandleSynchronize(NetworkPacket packet) {
//send all the server's data to this client
//TODO: compensate for large distances
NetworkPacket newPacket;
char buffer[PACKET_BUFFER_SIZE];
//players
newPacket.meta.type = NetworkPacket::Type::PLAYER_UPDATE;
@@ -218,7 +266,8 @@ void ServerApplication::HandleSynchronize(NetworkPacket packet) {
snprintf(newPacket.playerInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str());
newPacket.playerInfo.position = it.second.position;
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);
}
}
@@ -230,13 +279,15 @@ void ServerApplication::HandleShutdown(NetworkPacket packet) {
packet.meta.type = NetworkPacket::Type::DISCONNECT;
PumpPacket(packet);
cout << "shutting down" << endl;
//finished this routine
cout << "Shutdown signal accepted" << endl;
}
void ServerApplication::HandlePlayerNew(NetworkPacket packet) {
//create the new player object
Player newPlayer;
PlayerEntry newPlayer;
newPlayer.clientIndex = packet.playerInfo.clientIndex;
newPlayer.mapIndex = 0;
newPlayer.handle = packet.playerInfo.handle;
newPlayer.avatar = packet.playerInfo.avatar;
newPlayer.position = {0,0};
@@ -263,7 +314,7 @@ void ServerApplication::HandlePlayerDelete(NetworkPacket packet) {
}
//delete players
erase_if(playerMap, [&](pair<int, Player> it) -> bool {
erase_if(playerMap, [&](pair<int, PlayerEntry> it) -> bool {
if (it.first == packet.playerInfo.playerIndex) {
NetworkPacket delPacket;
@@ -292,9 +343,19 @@ void ServerApplication::HandlePlayerUpdate(NetworkPacket packet) {
PumpPacket(packet);
}
void ServerApplication::HandleRegionRequest(NetworkPacket packet) {
char buffer[PACKET_BUFFER_SIZE];
packet.meta.type = NetworkPacket::Type::REGION_CONTENT;
packet.regionInfo.region = mapPager.GetRegion(packet.regionInfo.x, packet.regionInfo.y);
serialize(&packet, buffer);
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
}
void ServerApplication::PumpPacket(NetworkPacket packet) {
//send this packet to all clients
//I don't really like this, but it'll do for now
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
for (auto& it : clientMap) {
network.Send(&it.second.address, &packet, sizeof(NetworkPacket));
network.Send(&it.second.address, buffer, PACKET_BUFFER_SIZE);
}
}
+35 -12
View File
@@ -22,31 +22,48 @@
#ifndef SERVERAPPLICATION_HPP_
#define SERVERAPPLICATION_HPP_
//maps
#include "map_generator.hpp"
#include "map_file_format.hpp"
#include "region_pager.hpp"
//networking
#include "network_packet.hpp"
#include "udp_network_utility.hpp"
#include "serial.hpp"
//APIs
#include "sqlite3/sqlite3.h"
#include "SDL/SDL.h"
//misc
//common
#include "config_utility.hpp"
#include "vector2.hpp"
#include "client.hpp"
#include "player.hpp"
//APIs
#include "lua/lua.hpp"
#include "sqlite3/sqlite3.h"
#include "SDL/SDL.h"
//STL
#include <map>
#include <string>
struct ClientEntry {
IPaddress address;
};
struct PlayerEntry {
int clientIndex;
int mapIndex;
std::string handle;
std::string avatar;
Vector2 position;
Vector2 motion;
};
//The main application class
class ServerApplication {
public:
//standard functions
ServerApplication();
~ServerApplication();
ServerApplication() = default;
~ServerApplication() = default;
void Init(int argc, char** argv);
void Loop();
@@ -64,22 +81,28 @@ private:
void HandlePlayerNew(NetworkPacket);
void HandlePlayerDelete(NetworkPacket);
void HandlePlayerUpdate(NetworkPacket);
void HandleRegionRequest(NetworkPacket);
void PumpPacket(NetworkPacket);
//maps
RegionPager<LuaGenerator, LuaFormat> mapPager;
//networking
UDPNetworkUtility network;
//database
sqlite3* database = nullptr;
//lua
lua_State* luaState = nullptr;
//misc
bool running = true;
ConfigUtility config;
//global lists
ClientMap clientMap;
PlayerMap playerMap;
std::map<int, ClientEntry> clientMap;
std::map<int, PlayerEntry> playerMap;
int clientCounter = 0;
int playerCounter = 0;