Compare commits

..

192 Commits

Author SHA1 Message Date
Kayne Ruse 288b62d3f8 Merge branch 'develop' 2014-05-13 03:26:13 +10:00
Kayne Ruse c5e8f1b3af Added account and character saving on shutdown 2014-05-13 03:25:50 +10:00
Kayne Ruse 980717f9fd Merge branch 'develop' 2014-05-13 03:01:26 +10:00
Kayne Ruse 68475eee0f Created PumpCharacterUnload 2014-05-13 02:51:50 +10:00
Kayne Ruse eeb2400e79 Rearranged the server-side object hierarchy (read more)
This has been a long-running problem for days, but I've finally
implemented a correctly working hierarchy between the ClientData,
AccountData and CharacterData objects:

CharacterData -> AccountData -> ClientData

There doesn't seem to be any issues with it right now, touch wood.
2014-05-13 02:09:00 +10:00
Kayne Ruse 01244005e9 Minor file renaming and tweaks 2014-05-13 00:23:04 +10:00
Kayne Ruse c5005b9b07 Merge branch 'develop' 2014-05-12 22:40:21 +10:00
Kayne Ruse 80a26341b1 Finished the character management, but it needs testing. 2014-05-11 20:13:27 +10:00
Kayne Ruse b7877962f1 Implemented CreateCharacter() and LoadCharacter() (read more)
There are issues with the indexes. That is, the accounts and the
characters need each other's indexes upon creation. I'll need to rectify
this now.
2014-05-10 20:30:33 +10:00
Kayne Ruse 688d064085 Merge branch 'database'
Conflicts:
	todo.txt

Merging todo.txt into the master branch, despite trying to keep it
separate.
2014-05-07 21:12:22 +10:00
Kayne Ruse 1c4d53e3ef Updated TODO, might as well merge this into the master 2014-05-07 21:07:42 +10:00
Kayne Ruse a53a134163 Merge branch 'account'
Added the "accountIndex" variable to the SerialPacket.
2014-05-07 20:55:43 +10:00
Kayne Ruse 4d12788c53 Finished the server-side modifications (read more)
* There seems to be something iffy with this branch
* The size of SerialPacket may have changed

I've implemented the accountIndex variable as best I can, but I really
shouldn't code at night. I'll need to go over the changes again before
merging this.
2014-05-07 20:55:09 +10:00
Kayne Ruse 1beb7cbd5d Began adding basic authentication 2014-05-06 21:35:07 +10:00
Kayne Ruse 8358d72a98 Merge branch 'database' (read more)
* Implemented user accounts.
* Other minor tweaks

I think the general "clientIndex" variable needs to be changed to
"accountIndex", since this will allow for much easier authentication.
2014-05-06 19:21:52 +10:00
Kayne Ruse 4ebff4a25a Minor tweaks, prepping for a merge 2014-05-06 19:18:53 +10:00
Kayne Ruse 0ff787abda Added Unloading and Deletion of user accounts 2014-05-06 18:57:49 +10:00
Kayne Ruse 9b5b48a8ab Implemented saving of user accounts (read more)
To modify an existing user account, change the in memory copy and then
call the function SaveUserAccount(uid), where uid is the index of the
modified account. If the save function is not called immediately, then the
behaviour of the server is undefined.
2014-05-06 18:33:20 +10:00
Kayne Ruse 5dd0fb9e23 BUGFIX: Signal when a duplicate account is being loaded
If a duplicate account is being created or loaded then the functions
return -1. The higher code can take it from there.
2014-05-06 16:41:08 +10:00
Kayne Ruse 7c210e04a5 Switched to using a wildcard symbol 2014-05-06 00:17:50 +10:00
Kayne Ruse 9236e02101 Merge branch 'master' into database (read more)
Conflicts:
	todo.txt (kept)

Just merging the editor's deletion into this branch, nothing else major.
2014-05-06 00:08:06 +10:00
Kayne Ruse 8f4ebf20da Removed the editor, since it isn't currently needed 2014-05-06 00:07:02 +10:00
Kayne Ruse 910e51f637 Began to implement user accounts using the database
I'm mostly just testing the waters at this stage, and i've left some debug
code in. There's no way to unload, delete, etc. the accounts, but that
comes later.
2014-05-05 23:57:07 +10:00
Kayne Ruse 92fc9b4e25 Adjusted the lua's map API, requiring a large rewrite
One the whole nothing major has changed, but I think this makes things
more logical. I just hope its stable, since I'm releasing a new tag.
2014-04-29 15:53:04 +10:00
Kayne Ruse 2b8e7241c9 Merge branch 'tweaks'; nothing major 2014-04-29 13:12:39 +10:00
Kayne Ruse 124cb3ad13 Did some renaming and comment tweaks 2014-04-29 06:34:23 +10:00
Kayne Ruse 6d3400d948 Merge branch 'network' (read more)
I've refactored the network layout. Here is a brief list of changes:

* The new player object is created server-side rather than client-side
* serial.cpp now uses macros to prevent hard-to-find logic errors
* A few method definitions have been re-ordered
* SerialPacket's internals have been slightly changed
* SerialPacket now carries a datestamp defining the network protocol
* server_application.cpp has been split into two separate files
* HandleJoinRequest() has been modified to create the new player object
2014-04-29 02:14:25 +10:00
Kayne Ruse 5031352fe3 Fixed the bug (read more)
The bug was being caused by a lack of a new player object being sent to
some clients. Fixed this by adding in the sending code, and preventing the
new entries being "registered" until the end of the HandleJoinRequest()
method.

Hopefully I can simply abstract away some of this code soon.
2014-04-29 01:47:01 +10:00
Kayne Ruse 624369f147 Discovered a bug 2014-04-27 22:46:19 +10:00
Kayne Ruse 9a7f7b8684 Rewrote the TODO list 2014-04-27 03:55:44 +10:00
Kayne Ruse fa9487c2f2 Fixed the previous bug (read more)
The bug was being caused by not assigning default values to the player
objects' internals. I've added a quick fix to these structs, but I think
it's best to expand them into proper classes now.
2014-04-27 02:37:20 +10:00
Kayne Ruse 9ec1ddab99 Exceptions are being thrown; retiring for the night
I don't know what's causing these issues, so I'm leaving it for tonight.
2014-04-26 02:48:15 +10:00
Kayne Ruse 6f1c2d0555 Merge branch 'fragmented-server' into network (read more)
I've divided the server's source into several different files. This should hopefully make it a bit easier to manage.

Please note that I do know there's an exception being thrown by the client
in this build.
2014-04-26 02:34:17 +10:00
Kayne Ruse 01b50d5590 I guess it was easier to compile the fragmented server than I thought 2014-04-26 02:31:48 +10:00
Kayne Ruse 9c673928e6 Began segmenting the server's code
I've created a separate branch for this because it's gonna be a bitch to
get compiled, and then I'll still have to ensure that the client & server
are work together correctly.

This build does not compile.
2014-04-26 02:09:32 +10:00
Kayne Ruse d55dfb90e4 Worked the new protocol into the client (read more)
I've added the handle and avatar fields back into the PlayerInfo section
in the network code, because I need to be able to load a specific file
when a new player is created. This wasn't forseen, but it's fine. i'm
leaving the fields in ClientInfo as well, because LobbyMenu is using them
to login to the server.

PlayerIndex is now a shared parameter.

I've shifted some code around in InWorld, however the overall logic is the
same.

This build (as well as the last) does not compile.
2014-04-26 01:05:31 +10:00
Kayne Ruse 235a05d006 Rearranged the SerialPacket and serialization code
The serialization code is now using macros to simplify each line, and to
prevent errors. It should be noted that, apart from the region content,
the serialization and deserialization code is essentially identical.
2014-04-25 23:50:19 +10:00
Kayne Ruse dabb7b3b2e Compiled a list of tasks
The list in todo.txt are a list of tasks that will be needed to complete
the login/user accounts overhaul, and will hopefully make the server a
persistent system.

Once the server is persistent (via the database) I can start on the combat
system.
2014-04-22 01:55:09 +10:00
Kayne Ruse e756289c2b Adjusted a few comments 2014-04-22 01:54:26 +10:00
Kayne Ruse c534158c2e Merge branch 'login' (read more)
This branch was originally intended to rewrite the login system, but I've discovered some serious problems that could not wait. See the previous commit for more information. Hopefully I can get back to this soon.

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

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

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

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

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

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

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

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

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

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

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

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

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

The tiles are voxel integers.

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

This code compiles, but since it's incomplete, I can't test it properly.
2014-02-21 03:42:02 +11:00
Kayne Ruse 808fe570a3 Added empty RegionPager 2014-02-18 01:18:04 +11:00
Kayne Ruse e706cc9d13 Completed a simple region class 2014-02-15 20:06:20 +11:00
Kayne Ruse eb02cc4b6a Removed the old map system from the editor 2014-02-11 21:56:45 +11:00
Kayne Ruse 31cca61d1c Added position data to player objects 2013-12-31 02:25:16 +11:00
Kayne Ruse 071e0d9021 I'm sick of multithreading.
I'm also sick of bastards on the internet.
2013-12-30 14:11:44 +11:00
Kayne Ruse a494bfbb38 Fixed horrible naming convention 2013-12-25 22:09:59 +11:00
Kayne Ruse baadf554cd BUGFIX: Solved server failure
Cause:

server/server_application.cpp: line 93

The last argument to std::pair was simply a call to WorldRoom's
contructor. This created a temporary object that fufilled this line, but
after the new std::pair object was added to worldRoomMap, this WorldRoom
object went out of scope.

server/server_application.cpp: line 96

When OpenRoom() was called using an object that was out of scope, the
entire server simply failed.

Solution:

Changed worldRoomMap to hold a pointer to a WorldRoom object, rather than the
object itself. The new and delete operators should be used to create and
delete WorldRoom objects respectfully.
2013-12-14 00:23:20 +11:00
Kayne Ruse 9df16fede0 WARNING: Server fails on startup
For some reason, when trying to initiate the room thread, the entire
server simply fails. There is no crash, no error message, or anything. I
have no idea what's wrong.
2013-12-11 22:22:01 +11:00
Kayne Ruse dd0ad31ac6 Tweaked README.md 2013-12-11 18:54:51 +11:00
Kayne Ruse be26c9d103 Started working on multithreaded rooms 2013-12-08 15:55:49 +11:00
Kayne Ruse a448c8fb68 Added the nightly build link to the readme 2013-12-07 03:28:41 +11:00
Kayne Ruse de1a6a050f Fixed jittery lag and client closing issues 2013-12-07 03:24:39 +11:00
Kayne Ruse 49c9abe91b Added controls, it's now MP capable 2013-12-07 02:36:48 +11:00
Kayne Ruse 3b05476689 Connections and disconnections are working across different clients 2013-12-07 01:33:27 +11:00
Kayne Ruse 1c032bfc47 Implemented client-side player creation; incomplete 2013-12-06 23:03:46 +11:00
Kayne Ruse 1a7457f650 Imported and refactored PlayerCharacter from the old branch 2013-12-06 21:00:35 +11:00
Kayne Ruse e640eda771 Moved client scenes to a sub directory, reworked build process 2013-12-06 20:22:55 +11:00
Kayne Ruse fc2b67608f Added new graphics stuff, adjusted build process 2013-12-06 18:29:55 +11:00
Kayne Ruse a3a990cc01 Added player support to the server
This code is essentially copied from the old branch, since the two
branches are now functionally identical. How much time have I wasted
rewriting this?
2013-12-06 17:47:03 +11:00
Kayne Ruse f6a4674a2f Moved networking code into high cohesion functions 2013-12-02 17:54:47 +11:00
Kayne Ruse 865620b4a8 Renamed some things, and removed Client::index 2013-12-01 18:36:18 +11:00
Kayne Ruse 1e0ed350fc Removed Multithreading, simplifying the server
Networking and multithreading working at the same time is really fucking
hard. It's better to just have the one thread, and not worry about speed
at this stage.
2013-12-01 15:21:00 +11:00
Kayne Ruse 6ccc874583 Implemented the log on and log off systems
This is a pretty straight forward port of the old version, including the
incredibly hacky server list. But I just need to remember that this is a
prototype.
2013-11-23 17:53:36 +11:00
Kayne Ruse ca86dc5fb8 Added a delay, to give the machine a rest 2013-11-23 01:25:49 +11:00
Kayne Ruse e3605e4dc5 The client is receiving the list of servers 2013-11-22 23:19:29 +11:00
Kayne Ruse cb9aef95ec Reworked NetworkQueue as a template class 2013-11-22 19:57:24 +11:00
Kayne Ruse 09f97de0e6 Added HandlePacket() to the lobby 2013-11-22 19:56:15 +11:00
Kayne Ruse f5466b9982 Added config based directories 2013-11-17 00:13:16 +11:00
Kayne Ruse e176a60d28 client to server contact 2013-11-16 23:46:59 +11:00
Kayne Ruse dc24d1b059 Committing the empty WorldRoom class 2013-11-13 02:03:25 +11:00
Kayne Ruse fa3fc18ddf Imported and updated ConfigUtility 2013-11-09 21:13:00 +11:00
Kayne Ruse c2941cd3e8 Moved the thread out of the NetworkQueue class 2013-11-09 20:04:06 +11:00
Kayne Ruse bf15a5d957 Minor tweak 2013-11-09 16:32:35 +11:00
Kayne Ruse f01463bab3 Added and tested the network queue in the server
This is a reimplementation of the old network queue, but using a class.
This still uses a separate thread, so that packets can wait if there's any
lag. Really, thinking about it, I wonder how necessary this was.

On the upside, no singletons this time. Which means that you can have
several instances of UDPNetworkManager. That's unintentional, but good to
know.
2013-11-03 00:22:41 +11:00
Kayne Ruse 54cd26b76f Removed a lot of rubbish from the server 2013-11-02 19:00:08 +11:00
Kayne Ruse 2bd8adaf69 Added an empty navigation shell to the client 2013-10-27 22:00:09 +11:00
Kayne Ruse 26eba2def6 Moved some common/* files into directories 2013-10-27 20:17:37 +11:00
Kayne Ruse 43852ce755 Hooked the two scenes together
What the hell am I doing?
2013-10-27 00:43:37 +11:00
Kayne Ruse 81fab06e3b Dummied out the load & save functions 2013-10-22 20:22:35 +11:00
Kayne Ruse 77a90f9c0c Slight refactoring 2013-10-22 20:19:09 +11:00
Kayne Ruse bc32f2a2f0 The editor scene now works correctly with the TileSheetManager 2013-10-22 19:43:20 +11:00
Kayne Ruse 76bfecd466 RegionPager now uses a reference to TileSheetManager 2013-10-22 19:35:24 +11:00
Kayne Ruse d4eb1e7b8d Checking in the test scene and test tilesets 2013-10-22 19:22:18 +11:00
Kayne Ruse 2ec307510d Revised TileSheet & TileSheetManager 2013-10-22 19:18:35 +11:00
Kayne Ruse 0b4e6003d6 Created the TileSheetManager class
This class will manage the large(ish) number of tile sheets for a specific
map.
2013-10-21 23:53:36 +11:00
Kayne Ruse 7e603ffa89 Moved the map systems into their own directory 2013-10-17 23:33:02 +11:00
Kayne Ruse 6fc8570cf4 Added the saving function 2013-10-17 23:10:43 +11:00
Kayne Ruse 0bfd916df4 Fixed inverted camera, and added RegionPager::Prune() 2013-10-17 22:18:42 +11:00
Kayne Ruse 88aee0f4f5 Created the loadGameMap() function, still incomplete
Although the overall logic of this function is finished, I still need to
write the callbacks for RegionPager's onNew and onDelete.

I've also tested this using a hand written save/index file. I've written
up a map file format by hand, and I'll be implementing it over the next
few commits.
2013-10-14 21:12:09 +11:00
Kayne Ruse 0d3c3243a0 Added a debug display 2013-10-11 20:07:57 +11:00
Kayne Ruse 871b1136c2 Pager and menu bar working together without interfering with each other 2013-10-11 01:14:02 +11:00
Kayne Ruse f64c935ffe Imported revamped GUI classes, moved map classes 2013-10-11 00:30:31 +11:00
Kayne Ruse 600ec6789b Removed debug code from the editor 2013-10-07 02:32:36 +11:00
Kayne Ruse 65a3937592 Imported the rsc/ folder from the old branch 2013-10-07 01:32:29 +11:00
Kayne Ruse 719c8f49a6 Added region highlighting 2013-10-06 19:22:26 +11:00
Kayne Ruse 29928c0b92 Added a draw function to the pager
I'm also committing some simple debugging code in the scene.
2013-10-04 02:18:10 +10:00
Kayne Ruse a88a1f7cf7 Systems are working correctly, but needs cleaning 2013-10-04 00:34:57 +10:00
Kayne Ruse 46efbfbe9a Forgot to add the license 2013-10-03 23:20:04 +10:00
Kayne Ruse 26ff8dcc8f Created RegionPager 2013-10-03 23:04:16 +10:00
Kayne Ruse 9c91e9d5fd Decoupled the TileSheet class from the Map class
I moved the rangeEnd variable into the TileSheet class, making it static.
I also tweaked the return types for a few functions in Region, and removed
the sheetIndex member from Tile.
2013-10-03 21:29:11 +10:00
Kayne Ruse 3628d3c1fd Finished the delcaration of the Map class
This is actually a lot harder than I was expecting. When I program, I
approach from the angle of "What do I need to do?" rather than "how do I do
this?" At least this is finally done, so I can get to the implementation
stage. But, as I progress, I'll need to keep in mind what I need for the
index file.

Actually, I just realized that I didn't write the index functions. Well,
it should be interesting, at least.
2013-10-01 23:02:46 +10:00
Kayne Ruse 6c9406147a Added width & height members to Tile, moved local functions to utility.*pp
I've added more members to the Tile structure, namely the width & height
of the tile. This is to fix a circular logic problem, which is too
abstract for this commit message ;)

I've also moved the local/static/inline/etc. utility functions to their
own module in the common directory, because this is just cleaner that
redefining the same code a dozen times.

The map's logic is still the same, but I need to keep moving; I've been
procrastinating far too much.
2013-10-01 21:46:34 +10:00
Kayne Ruse aae244de39 Code tweak 2013-09-25 21:27:00 +10:00
Kayne Ruse d5b14c2679 Created the TileSheet class
This is incomplete on it's own, but used as part of the whole map system,
it should work well. This class keeps track of various, seemingly
unrelated states, which are used as part of the larger map system.

Also, fixed Region's members being public.
2013-09-25 20:39:59 +10:00
Kayne Ruse a54fbfb9e9 Added static linking 2013-09-21 16:26:01 +10:00
Kayne Ruse 9cbbfe77b7 After some testing Region seems OK 2013-09-19 22:52:26 +10:00
Kayne Ruse 9b64c67068 Finished a prototype of Region, needs testing 2013-09-19 16:52:15 +10:00
Kayne Ruse de0227a1cf Demonstration of Tile & Region classes 2013-09-19 01:22:52 +10:00
Kayne Ruse 1dfeabf195 SDL_net is working 2013-09-09 12:15:26 +10:00
Kayne Ruse 6c5197f3f2 The server runs the setup scripts on startup 2013-09-05 23:02:48 +10:00
Kayne Ruse 09453cc24e Added lua and SQL, but removed lsqlite3.c
lsqlite3.c looked like a good idea for connnecting SQL and lua, but I
couldn't get it to work and rather than struggle on this, I'll write my
own library later on.
2013-09-05 20:08:50 +10:00
Kayne Ruse 4b62310158 Revised build process to include the common/ directory 2013-09-04 20:49:55 +10:00
Kayne Ruse 43f2190c3e Created the database setup script 2013-09-04 19:17:16 +10:00
Kayne Ruse 3225da6b13 Added client scenes 2013-08-31 03:27:11 +10:00
Kayne Ruse 0c233b8764 Added readme.md 2013-08-29 21:55:09 +10:00
Kayne Ruse 027d0125ef Boilerplate, boilerplate, boilerplate!!!
I've created a project for client & editor programs, by simply copying one
to the other. Right now, the client still has the editor scene, but I'll
switch that out soon.

I've also added a license header to the server's source. I don't remember
what else I did, but at this point it should theoretically build out of
the box.
2013-08-29 21:17:43 +10:00
Kayne Ruse e4884c3e18 Added more placeholder files 2013-08-29 20:35:02 +10:00
Kayne Ruse b675f516e7 Beginning to create the placeholder classes 2013-08-29 19:57:25 +10:00
Kayne Ruse d5f7363c33 Minor rename 2013-08-25 13:59:13 +10:00
Kayne Ruse 7458962ad4 Rearranged the logic 2013-08-24 23:20:43 +10:00
Kayne Ruse 0a0b61287e Started working on the room system 2013-08-11 20:39:08 +10:00
173 changed files with 6905 additions and 17208 deletions
+21
View File
@@ -0,0 +1,21 @@
#Editor generated files
*.sln
*.vcproj
*.suo
*.ncb
*.user
#Directories
Release/
Debug/
Out/
#Project generated files
*.db
*.o
*.a
*.exe
#Shell files
*.bat
*.sh
+31
View File
@@ -0,0 +1,31 @@
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, 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.
## External Dependencies
* [SDL 1.2](http://www.libsdl.org/) - Simple DirectMedia Layer API
* [SDL_net 1.2](http://www.libsdl.org/projects/SDL_net/) - SDL's networking extension
* [lua 5.2](http://www.lua.org/) - The lua programming language
* [SQLite3](http://www.sqlite.org/) - A lightweight SQL database engine
## Documentation
[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, 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.
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.
Binary file not shown.
-57
View File
@@ -1,57 +0,0 @@
--TODO: each function needs to check it's parameter count
--TODO: Set metatables
--RoomManager interface
RoomMgr.GetRoom(index)
RoomMgr.CreateRoom([{params}])
RoomMgr.UnloadRoom(index)
--RoomData interface
Room.GetPager()
Room.GetGenerator()
Room.OnCreate([{params}])
Room.OnUnload()
Room.Get{params}()
--RegionPager interface
RegionPager.SetTile(x, y, z, v)
RegionPager.GetTile(x, y, z)
RegionPager.SetSolid(x, y, b)
RegionPager.GetSolid(x, y)
RegionPager.GetRegion(x, y)
RegionPager.SetDirectory(directory)
RegionPager.GetDirectory()
RegionPager.LoadRegion(x, y)
RegionPager.SaveRegion(x, y)
RegionPager.CreateRegion(x, y[, {params}])
RegionPager.UnloadRegion(x, y)
--Region interface
Region.SetTile(x, y, z, v)
Region.GetTile(x, y, z)
Region.SetSolid(x, y, b)
Region.GetSolid(x, y)
Region.GetX()
Region.GetY()
Region.GetWidth()
Region.GetHeight()
Region.GetDepth()
Region.OnLoad(directory)
Region.OnSave(directory)
Region.OnCreate([{params}])
Region.OnUnload([directory])
--*Generator interface
Generator.GetMapType()
Generator.GetChunk(x, y)
Generator.GetMapWidth()
Generator.GetMapHeight()
--Chunk interface
??
-19
View File
@@ -1,19 +0,0 @@
My game Tortuga will have permadeath; it's actually one of the first design decisions I made. How to implement it, however, is another decision all together.
A while ago, before the implementation of hardcore mode, I was playing on a Minecraft server that boasted something close to permadeath: your account would be banned for 15 days, so long that it's almost unavoidable that you'd lose all of your hidden items. This was a brutal server; the further you went from spawn, the more dangerous it became, not less. If the natural hazards didn't kill you, another player would.
I loved it.
Although I haven't been back to that server since I died for the last time, the experience will stay with me forever. I'd played and died on that server a few times, each time I had to wait for my ban to clear. I never really lost much, since I never survived for very long. Even today, in a single player world, I'm likely to die on the first night.
After playing for a while, I began to understand the mentality needed to survive there. Always fear other people, never take risks, and never hoard valuable items if they could be better spent keeping you alive. One day, the last day I played, I found a hole in the ground that someone was obviously using as a "hidden" base. I tried to get in, always careful not to trigger any traps. However, while I was trying to get in, the owner came home.
I was suddenly attacked from behind, I barely had enough sense to dig down, since they were wearing enchanted diamond armour. I had no chance against them. I thought I was safe, digging 10, 20, 30 meters down, but no, they poured lava down the hole and plugged it up. I was a gonner, and I knew it. I was futilely digging and thrashing around in what was now my tomb, about to lose my life. I'd survived for so long, only to lose it all by not keeping a lookout.
When the game over screen flashed up, I screamed. I screamed, and screamed, and screamed. For 5 minutes, my mind was blank, nothing but hatred and pain and loss. I'm sure you've seen the video of the angry German kid who died in WoW, but have you ever actually experienced that pain? Have you ever worked so hard, and lost it all?
For days afterwards, that loss was all I could think about. Even now, that experience stays with me. What about that game, that server, invoked so much pain that I almost lost consciousness from screaming? Me of all people, who thought he was invincible?
I've played games that have moved me, terrified me, made me fall in love and fight for the people that I care about. But never have I played a game that has made me feel pain and loss like that. I died that day. Me.
Pain and loss are part of life, but not games. Permadeath seems like the obvious choice for creating a sense of loss for the player, but there are so few games with permadeath, and even fewer multiplayer games. Pain and loss can be conveyed in other ways, I'm sure anybody who's played Final Fantasy 7 knows that, and some games are especially well suited to delivering that message. However, for a player to feel like they are the one who's died, that is a challenge.
-125
View File
@@ -1,125 +0,0 @@
Abstract:
The goal of this pseudocode is to create a collision system that brings several
colliding bodies to a near-contact state (no space between the bodies, but not
overlapping), while preserving the motion of said bodies. For simplicity, I've
decided to use a square box (BoundingBox, or BBox for short) for the collidable
bodies.
Example:
My current game has a tiled-map, where the tiles are arranged on a 2D grid. The
tiles each have a flag indicating if they are solid (i.e. collidable) or not. I
also have characters walking around on these tile maps, that must not intersect
with solid tiles. For stylistic reasons, I want characters moving at an angle
to "slide" along these walls, and continue along with their original velocity
when they've circumvented the obstacles.
I'd also like to keep the possibility of non-grid collisions using this logic
open (for objects like trees, etc.) if the code allows it.
Obviously, there are many in depth issues that I will need to take into
account when writing this logic, that have been glossed over or omitted in this
article.
-------------------------
```
velocity = motion + speed
if (collision(position + velocity)) then
if (collision(position + {velocity.x, 0})) then
velocity.x = 0
end
if (collision(position + {0, velocity.y})) then
velocity.y = 0
end
end
position = position + velocity
```
This code is a basic outline for a collision system that preserves the object's
motion, but it still leaves several pixels of space between the bounding boxes.
Notably, it also treats "collision" as an abstract concept, rather than as an
event that could happen multiple times per frame.
-------------------------
```
velocity = motion + speed
if (collisionSimple(BOXSET, position + velocity)) then
velocity.x = collisionX(BOXSET, velocity.x)
velocity.y = collisionY(BOXSET, velocity.y)
end
position = position + velocity
```
Here, collisions are still abstract, but "BOXSET" is defined externally
(probably as a set of solid boxes, and their positions). This does require more
in depth calculations, as well as three specialized utility functions, but the
results might be what I'm looking for.
If there are any collisions between the player object and the given box set,
then collisionX() and collisionY() are called to calculate the new distance
that the character will move.
-------------------------
```
bool collisionSimple(BOXSET, newPos):
for_each box in BOXSET do
if (box.overlap(PLAYER.box + newPos)) then
return true
end
end
return false
end
```
collisionSimple() first runs through the BOXSET, checking if any of the given
bounding boxes would collide with the player object's new position (just
pretend PLAYER is accessible). In this case, non-tile bounding boxes can be
included as part of BOXSET; they're treated just the same. The optimal outcome
is that there are no collisions.
A possible, but flawed, optimization that could be preformed here is to remove
any elements from BOXSET that do not collide with newPos, and let the other
utility functions operate only on what remains. However, if there are any
collisions, than newPos is not the algorithm's final result, therefore any
final result that the algorithm would calculate based on the remaining elements
would not have been checked against the removed elements.
Just something to note.
-------------------------
```
var collisionX(BOXSET, velocityX):
var ret = velocityX
for_each box in BOXSET do
if (box.overlap(PLAYER.box + PLAYER.position + {velocityX,0})) then
if (velocityX > 0) then
ret = min(ret, box.west - PLAYER.position.x)
else
ret = max(ret, box.east - PLAYER.position.x)
end
end
end
return ret
end
```
Two things: 1. collisionX() and collisionY() should be identical except for the
axis of operation and 2. if a player object is "sliding" along a wall (or
stuck), then these functions will be called every frame.
collisionX() and collisionY() check the sides of the elements in BOXSET, and if
there's a box that the player would collide with, given the current distance to
move, than the distance is reduced, based on if the character is moving left or
right (or up or down).
An unfortunate bug I can already see is that this logic doesn't check corners;
it might be possible to get stuck on a corner of a wall, but if this becomes an
issue in my implementation I will update this article with that information,
and you can promptly ignore it.
+8
View File
@@ -0,0 +1,8 @@
#ifndef CHANNELS_HPP_
#define CHANNELS_HPP_
enum Channels {
SERVER = 0
};
#endif
+138
View File
@@ -0,0 +1,138 @@
/* 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 ClientApplications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "client_application.hpp"
#include "serial.hpp"
#include <stdexcept>
#include <chrono>
//-------------------------
//Scene headers
//-------------------------
//Add the custom scene headers here
#include "splash_screen.hpp"
#include "main_menu.hpp"
#include "options_menu.hpp"
#include "lobby_menu.hpp"
#include "in_world.hpp"
#include "in_combat.hpp"
//-------------------------
//Public access members
//-------------------------
void ClientApplication::Init(int argc, char** argv) {
//load the prerequisites
config.Load("rsc\\config.cfg");
//initialize SDL
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_FULLSCREEN : SDL_HWSURFACE|SDL_DOUBLEBUF);
//initialize SDL_net
if (SDLNet_Init()) {
throw(std::runtime_error("Failed to initialize SDL_net"));
}
network.Open(0, PACKET_BUFFER_SIZE);
}
void ClientApplication::Proc() {
LoadScene(SceneList::FIRST);
//prepare the time system
typedef std::chrono::steady_clock Clock;
std::chrono::duration<int, std::milli> delta(16);
Clock::time_point simTime = Clock::now();
Clock::time_point realTime;
//The main loop
while(activeScene->GetNextScene() != SceneList::QUIT) {
//switch scenes when necessary
if (activeScene->GetNextScene() != SceneList::CONTINUE) {
LoadScene(activeScene->GetNextScene());
continue;
}
//update the current time
realTime = Clock::now();
//simulate game time
while (simTime < realTime) {
//call each user defined function
activeScene->RunFrame(double(delta.count()) / std::chrono::duration<int, std::milli>::period::den);
simTime += delta;
}
//draw the game to the screen
activeScene->RenderFrame();
}
UnloadScene();
}
void ClientApplication::Quit() {
network.Close();
SDLNet_Quit();
SDL_Quit();
}
//-------------------------
//Private access members
//-------------------------
void ClientApplication::LoadScene(SceneList sceneIndex) {
UnloadScene();
switch(sceneIndex) {
//add scene creation calls here
case SceneList::FIRST:
case SceneList::SPLASHSCREEN:
activeScene = new SplashScreen(&config);
break;
case SceneList::MAINMENU:
activeScene = new MainMenu(&config);
break;
case SceneList::OPTIONSMENU:
activeScene = new OptionsMenu(&config);
break;
case SceneList::LOBBYMENU:
activeScene = new LobbyMenu(&config, &network, &clientIndex, &accountIndex, &characterIndex);
break;
case SceneList::INWORLD:
activeScene = new InWorld(&config, &network, &clientIndex, &accountIndex, &characterIndex);
break;
case SceneList::INCOMBAT:
activeScene = new InCombat();
break;
default:
throw(std::logic_error("Failed to recognize the scene index"));
}
}
void ClientApplication::UnloadScene() {
delete activeScene;
activeScene = nullptr;
}
+55
View File
@@ -0,0 +1,55 @@
/* 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 CLIENTAPPLICATION_HPP_
#define CLIENTAPPLICATION_HPP_
#include "scene_list.hpp"
#include "base_scene.hpp"
#include "config_utility.hpp"
#include "udp_network_utility.hpp"
class ClientApplication {
public:
ClientApplication() = default;
~ClientApplication() = default;
void Init(int argc, char** argv);
void Proc();
void Quit();
private:
//Private access members
void LoadScene(SceneList sceneIndex);
void UnloadScene();
BaseScene* activeScene = nullptr;
//shared parameters
ConfigUtility config;
UDPNetworkUtility network;
int clientIndex = -1;
int accountIndex = -1;
int characterIndex = -1;
};
#endif
+43
View File
@@ -0,0 +1,43 @@
/* 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 "client_application.hpp"
#include <stdexcept>
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
cout << "Beginning client" << endl;
try {
ClientApplication app;
app.Init(argc, argv);
app.Proc();
app.Quit();
}
catch(exception& e) {
cerr << "Fatal exception thrown: " << e.what() << endl;
return 1;
}
cout << "Clean exit" << endl;
return 0;
}
+44
View File
@@ -0,0 +1,44 @@
#config
INCLUDES+=. scenes ../common ../common/graphics ../common/map ../common/network ../common/ui
LIBS+=libclient.a ../libcommon.a -lSDL_net -lwsock32 -liphlpapi -lmingw32 -lSDLmain -lSDL -llua -lsqlite3
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
OUT=$(addprefix $(OUTDIR)/,client)
#targets
all: $(OBJ) $(OUT)
$(MAKE) -C scenes
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
$(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
+117
View File
@@ -0,0 +1,117 @@
/* 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 "player_character.hpp"
#define WALKING_SPEED 140
void PlayerCharacter::Update(double delta) {
if (diagonal) {
constexpr double d = 1.0/sqrt(2);
position += motion * delta * d;
}
else {
position += motion * delta;
}
sprite.Update(delta);
}
void PlayerCharacter::AdjustDirection(Direction direction) {
//shift the movement in this direction
switch(direction) {
case Direction::NORTH:
if (motion.y >= 0) {
motion.y -= WALKING_SPEED;
}
break;
case Direction::SOUTH:
if (motion.y <= 0) {
motion.y += WALKING_SPEED;
}
break;
case Direction::WEST:
if (motion.x >= 0) {
motion.x -= WALKING_SPEED;
}
break;
case Direction::EAST:
if (motion.x <= 0) {
motion.x += WALKING_SPEED;
}
break;
}
//face the correct direction
ResetDirection();
}
void PlayerCharacter::FaceDirection(Direction direction) {
//this function depends on the format of the sprite sheets
switch(direction) {
case Direction::NORTH:
sprite.SetYIndex(1);
break;
case Direction::SOUTH:
sprite.SetYIndex(0);
break;
case Direction::WEST:
sprite.SetYIndex(2);
break;
case Direction::EAST:
sprite.SetYIndex(3);
break;
}
}
void PlayerCharacter::ResetDirection() {
//base the direction on the character's movement
if (motion.y > 0) {
FaceDirection(Direction::SOUTH);
}
else if (motion.y < 0) {
FaceDirection(Direction::NORTH);
}
else if (motion.x > 0) {
FaceDirection(Direction::EAST);
}
else if (motion.x < 0) {
FaceDirection(Direction::WEST);
}
ResetSpeed();
}
void PlayerCharacter::ResetSpeed() {
//diagonal
if (motion.x != 0 && motion.y != 0) {
sprite.SetDelay(0.1);
diagonal = true;
}
//cardinal
else if (motion != 0) {
sprite.SetDelay(0.1);
diagonal = false;
}
//not moving
else {
sprite.SetDelay(0);
sprite.SetXIndex(0);
diagonal = false;
}
}
+67
View File
@@ -0,0 +1,67 @@
/* 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 PLAYERCHARACTER_HPP_
#define PLAYERCHARACTER_HPP_
#include "vector2.hpp"
#include "sprite_sheet.hpp"
//TODO: correct the PlayerCharacter class and it's movement system
class PlayerCharacter {
public:
enum class Direction {
NORTH, SOUTH, EAST, WEST
};
PlayerCharacter() = default;
~PlayerCharacter() = default;
void Update(double delta);
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);
void FaceDirection(Direction);
void ResetDirection();
void ResetSpeed();
//accessors and mutators
Vector2 SetPosition(Vector2 v) { return position = v; }
Vector2 ShiftPosition(Vector2 v) { return position += v; }
Vector2 GetPosition() { return position; }
Vector2 SetMotion(Vector2 v) { return motion = v; }
Vector2 ShiftMotion(Vector2 v) { return motion += v; }
Vector2 GetMotion() { return motion; }
SpriteSheet* GetSprite() { return &sprite; }
private:
Vector2 position;
Vector2 motion;
SpriteSheet sprite;
//for moving diagonally
bool diagonal = false;
};
#endif
+40
View File
@@ -0,0 +1,40 @@
/* 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 SCENELIST_HPP_
#define SCENELIST_HPP_
enum class SceneList {
//these are reserved
QUIT,
CONTINUE,
FIRST,
//custom indexes
SPLASHSCREEN,
MAINMENU,
OPTIONSMENU,
LOBBYMENU,
INWORLD,
INCOMBAT,
};
#endif
+139
View File
@@ -0,0 +1,139 @@
/* 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 "base_scene.hpp"
#include <stdexcept>
//-------------------------
//Static declarations
//-------------------------
SDL_Surface* BaseScene::screen = nullptr;
//-------------------------
//Public access members
//-------------------------
BaseScene::BaseScene() {
//
}
BaseScene::~BaseScene() {
//
}
//-------------------------
//Program control
//-------------------------
SDL_Surface* BaseScene::SetScreen(int w, int h, int bpp, Uint32 flags) {
if (!bpp) {
bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
}
screen = SDL_SetVideoMode(w, h, bpp, flags);
if (!screen) {
throw(std::runtime_error("Failed to create the screen surface"));
}
return screen;
}
SDL_Surface* BaseScene::GetScreen() {
return screen;
}
SceneList BaseScene::SetNextScene(SceneList sceneIndex) {
return nextScene = sceneIndex;
}
SceneList BaseScene::GetNextScene() const {
return nextScene;
}
//-------------------------
//Frame loop
//-------------------------
void BaseScene::RunFrame(double delta) {
FrameStart();
HandleEvents();
Update(delta);
FrameEnd();
}
void BaseScene::RenderFrame() {
SDL_FillRect(screen, 0, 0);
Render(screen);
SDL_Flip(screen);
}
//-------------------------
//Event handlers
//-------------------------
void BaseScene::HandleEvents() {
SDL_Event event;
while(SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_QUIT:
QuitEvent();
break;
case SDL_VIDEORESIZE:
SetScreen(event.resize.w, event.resize.h, 0, screen->flags);
break;
case SDL_MOUSEMOTION:
MouseMotion(event.motion);
break;
case SDL_MOUSEBUTTONDOWN:
MouseButtonDown(event.button);
break;
case SDL_MOUSEBUTTONUP:
MouseButtonUp(event.button);
break;
case SDL_KEYDOWN:
KeyDown(event.key);
break;
case SDL_KEYUP:
KeyUp(event.key);
break;
#ifdef USE_EVENT_JOYSTICK
//TODO: joystick/gamepad support
#endif
#ifdef USE_EVENT_UNKNOWN
default:
UnknownEvent(event);
break;
#endif
}//switch
}//while
}
+74
View File
@@ -0,0 +1,74 @@
/* 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 BASESCENE_HPP_
#define BASESCENE_HPP_
#include "scene_list.hpp"
#include "SDL/SDL.h"
class BaseScene {
public:
//Public access members
BaseScene();
virtual ~BaseScene();
//Program control
static SDL_Surface* SetScreen(int w, int h, int bpp = 0, Uint32 flags = SDL_HWSURFACE|SDL_DOUBLEBUF);
static SDL_Surface* GetScreen();
SceneList SetNextScene(SceneList sceneIndex);
SceneList GetNextScene() const;
//Frame loop
virtual void RunFrame(double delta);
virtual void RenderFrame();
protected:
virtual void FrameStart() {}
virtual void HandleEvents();
virtual void Update(double delta) {}
virtual void FrameEnd() {}
virtual void Render(SDL_Surface* const screen) {}
//Event handlers
virtual void QuitEvent() { SetNextScene(SceneList::QUIT); }
virtual void MouseMotion(SDL_MouseMotionEvent const&) {}
virtual void MouseButtonDown(SDL_MouseButtonEvent const&) {}
virtual void MouseButtonUp(SDL_MouseButtonEvent const&) {}
virtual void KeyDown(SDL_KeyboardEvent const&) {}
virtual void KeyUp(SDL_KeyboardEvent const&) {}
#ifdef USE_EVENT_JOYSTICK
//TODO: joystick/gamepad support
#endif
#ifdef USE_EVENT_UNKNOWN
virtual void UnknownEvent(SDL_Event const&) {}
#endif
private:
static SDL_Surface* screen;
SceneList nextScene = SceneList::CONTINUE;
};
#endif
+82
View File
@@ -0,0 +1,82 @@
/* 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 "in_combat.hpp"
//-------------------------
//Public access members
//-------------------------
InCombat::InCombat() {
//
}
InCombat::~InCombat() {
//
}
//-------------------------
//Frame loop
//-------------------------
void InCombat::FrameStart() {
//
}
void InCombat::Update(double delta) {
//
}
void InCombat::FrameEnd() {
//
}
void InCombat::Render(SDL_Surface* const screen) {
//
}
//-------------------------
//Event handlers
//-------------------------
void InCombat::MouseMotion(SDL_MouseMotionEvent const& motion) {
//
}
void InCombat::MouseButtonDown(SDL_MouseButtonEvent const& button) {
//
}
void InCombat::MouseButtonUp(SDL_MouseButtonEvent const& button) {
//
}
void InCombat::KeyDown(SDL_KeyboardEvent const& key) {
switch(key.keysym.sym) {
case SDLK_ESCAPE:
QuitEvent();
break;
}
}
void InCombat::KeyUp(SDL_KeyboardEvent const& key) {
//
}
+48
View File
@@ -0,0 +1,48 @@
/* 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 INCOMBAT_HPP_
#define INCOMBAT_HPP_
#include "base_scene.hpp"
class InCombat : public BaseScene {
public:
//Public access members
InCombat();
~InCombat();
protected:
//Frame loop
void FrameStart();
void Update(double delta);
void FrameEnd();
void Render(SDL_Surface* const);
//Event handlers
void MouseMotion(SDL_MouseMotionEvent const&);
void MouseButtonDown(SDL_MouseButtonEvent const&);
void MouseButtonUp(SDL_MouseButtonEvent const&);
void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&);
};
#endif
+440
View File
@@ -0,0 +1,440 @@
/* 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 "in_world.hpp"
#include "channels.hpp"
#include <algorithm>
#include <cmath>
#include <stdexcept>
//-------------------------
//Public access members
//-------------------------
InWorld::InWorld(ConfigUtility* const argConfig, UDPNetworkUtility* const argNetwork, int* const argClientIndex, int* const argAccountIndex, int* const argCharacterIndex):
config(*argConfig),
network(*argNetwork),
clientIndex(*argClientIndex),
accountIndex(*argAccountIndex),
characterIndex(*argCharacterIndex)
{
//setup the utility objects
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(&buttonImage);
disconnectButton.SetFont(&font);
shutDownButton.SetImage(&buttonImage);
shutDownButton.SetFont(&font);
//set the button positions
disconnectButton.SetX(50);
disconnectButton.SetY(50 + buttonImage.GetClipH() * 0);
shutDownButton.SetX(50);
shutDownButton.SetY(50 + buttonImage.GetClipH() * 1);
//set the button texts
disconnectButton.SetText("Disconnect");
shutDownButton.SetText("Shut Down");
//load the tilesheet
//TODO: add the tilesheet to the map system?
tileSheet.Load(config["dir.tilesets"] + "terrain.bmp", 12, 15);
//TODO: move this into it's own function
//request a sync
SerialPacket packet;
char buffer[PACKET_STRING_SIZE];
packet.meta.type = SerialPacket::Type::SYNCHRONIZE;
packet.clientInfo.clientIndex = clientIndex;
packet.clientInfo.accountIndex = accountIndex;
packet.clientInfo.characterIndex = characterIndex;
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
//debug
// RequestRegion(0, 0);
}
InWorld::~InWorld() {
//
}
//-------------------------
//Frame loop
//-------------------------
void InWorld::FrameStart() {
//
}
void InWorld::Update(double delta) {
SerialPacket packet;
//suck in all waiting packets
while(network.Receive()) {
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());
fps.Calculate();
}
void InWorld::Render(SDL_Surface* const screen) {
//draw the map
for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
tileSheet.DrawRegionTo(screen, *it, camera.x, camera.y);
}
//draw 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);
}
//-------------------------
//Event handlers
//-------------------------
void InWorld::QuitEvent() {
//exit the game AND the server
RequestDisconnect();
}
void InWorld::MouseMotion(SDL_MouseMotionEvent const& motion) {
disconnectButton.MouseMotion(motion);
shutDownButton.MouseMotion(motion);
}
void InWorld::MouseButtonDown(SDL_MouseButtonEvent const& button) {
disconnectButton.MouseButtonDown(button);
shutDownButton.MouseButtonDown(button);
}
void InWorld::MouseButtonUp(SDL_MouseButtonEvent const& button) {
if (disconnectButton.MouseButtonUp(button) == Button::State::HOVER) {
RequestDisconnect();
}
if (shutDownButton.MouseButtonUp(button) == Button::State::HOVER) {
RequestShutDown();
}
}
void InWorld::KeyDown(SDL_KeyboardEvent const& key) {
switch(key.keysym.sym) {
case SDLK_ESCAPE: {
QuitEvent();
}
break;
//player movement
case SDLK_LEFT:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::WEST);
SendPlayerUpdate();
}
break;
case SDLK_RIGHT:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::EAST);
SendPlayerUpdate();
}
break;
case SDLK_UP:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::NORTH);
SendPlayerUpdate();
}
break;
case SDLK_DOWN:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::SOUTH);
SendPlayerUpdate();
}
break;
}
}
void InWorld::KeyUp(SDL_KeyboardEvent const& key) {
switch(key.keysym.sym) {
//player movement
case SDLK_LEFT:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::EAST);
SendPlayerUpdate();
}
break;
case SDLK_RIGHT:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::WEST);
SendPlayerUpdate();
}
break;
case SDLK_UP:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::SOUTH);
SendPlayerUpdate();
}
break;
case SDLK_DOWN:
if (localCharacter) {
localCharacter->AdjustDirection(PlayerCharacter::Direction::NORTH);
SendPlayerUpdate();
}
break;
}
}
//-------------------------
//Network handlers
//-------------------------
void InWorld::HandlePacket(SerialPacket packet) {
switch(packet.meta.type) {
case SerialPacket::Type::DISCONNECT:
HandleDisconnect(packet);
break;
case SerialPacket::Type::REGION_CONTENT:
HandleRegionContent(packet);
break;
case SerialPacket::Type::CHARACTER_UPDATE:
HandleCharacterUpdate(packet);
break;
case SerialPacket::Type::CHARACTER_NEW:
HandleCharacterNew(packet);
break;
case SerialPacket::Type::CHARACTER_DELETE:
HandleCharacterDelete(packet);
break;
//handle errors
default:
throw(std::runtime_error(std::string() + "Unknown SerialPacket::Type encountered in InWorld: " + to_string_custom(int(packet.meta.type))));
break;
}
}
void InWorld::HandleDisconnect(SerialPacket packet) {
network.Unbind(Channels::SERVER);
clientIndex = -1;
accountIndex = -1;
characterIndex = -1;
SetNextScene(SceneList::MAINMENU);
}
void InWorld::HandleRegionContent(SerialPacket packet) {
//replace existing regions
if (regionPager.FindRegion(packet.regionInfo.x, packet.regionInfo.y)) {
regionPager.UnloadRegion(packet.regionInfo.x, packet.regionInfo.y);
}
regionPager.PushRegion(packet.regionInfo.region);
packet.regionInfo.region = nullptr;
}
void InWorld::HandleCharacterUpdate(SerialPacket packet) {
if (playerCharacters.find(packet.characterInfo.characterIndex) == playerCharacters.end()) {
HandleCharacterNew(packet);
return;
}
//update only if the message didn't originate from here
if (packet.characterInfo.clientIndex != clientIndex) {
playerCharacters[packet.characterInfo.characterIndex].SetPosition(packet.characterInfo.position);
playerCharacters[packet.characterInfo.characterIndex].SetMotion(packet.characterInfo.motion);
}
playerCharacters[packet.characterInfo.characterIndex].ResetDirection();
}
void InWorld::HandleCharacterNew(SerialPacket packet) {
if (playerCharacters.find(packet.characterInfo.characterIndex) != playerCharacters.end()) {
throw(std::runtime_error("Cannot create duplicate characters"));
}
//TODO: set the player's handle
playerCharacters[packet.characterInfo.characterIndex].GetSprite()->LoadSurface(config["dir.sprites"] + packet.characterInfo.avatar, 4, 4);
playerCharacters[packet.characterInfo.characterIndex].SetPosition(packet.characterInfo.position);
playerCharacters[packet.characterInfo.characterIndex].SetMotion(packet.characterInfo.motion);
playerCharacters[packet.characterInfo.characterIndex].ResetDirection();
//catch this client's player object
if (packet.characterInfo.characterIndex == characterIndex && !localCharacter) {
localCharacter = &playerCharacters[characterIndex];
//setup the camera
camera.width = GetScreen()->w;
camera.height = GetScreen()->h;
//center on the player's character
camera.marginX = (GetScreen()->w / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2);
camera.marginY = (GetScreen()->h / 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2);
}
}
void InWorld::HandleCharacterDelete(SerialPacket packet) {
//TODO: authenticate
if (playerCharacters.find(packet.characterInfo.characterIndex) == playerCharacters.end()) {
throw(std::runtime_error("Cannot delete non-existant characters"));
}
playerCharacters.erase(packet.characterInfo.characterIndex);
//catch this client's player object
if (packet.characterInfo.characterIndex == characterIndex) {
characterIndex = -1;
localCharacter = nullptr;
}
}
//-------------------------
//Server control
//-------------------------
void InWorld::SendPlayerUpdate() {
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//pack the packet
packet.meta.type = SerialPacket::Type::CHARACTER_UPDATE;
packet.characterInfo.clientIndex = clientIndex;
packet.characterInfo.accountIndex = accountIndex;
packet.characterInfo.characterIndex = characterIndex;
packet.characterInfo.position = localCharacter->GetPosition();
packet.characterInfo.motion = localCharacter->GetMotion();
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
}
void InWorld::RequestDisconnect() {
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//send a disconnect request
packet.meta.type = SerialPacket::Type::DISCONNECT;
packet.clientInfo.clientIndex = clientIndex;
packet.clientInfo.accountIndex = accountIndex;
packet.clientInfo.characterIndex = characterIndex;
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
}
void InWorld::RequestShutDown() {
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//send a shutdown request
packet.meta.type = SerialPacket::Type::SHUTDOWN;
packet.clientInfo.clientIndex = clientIndex;
packet.clientInfo.accountIndex = accountIndex;
packet.clientInfo.characterIndex = characterIndex;
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
}
void InWorld::RequestRegion(int mapIndex, int x, int y) {
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//pack the region's data
packet.meta.type = SerialPacket::Type::REGION_REQUEST;
packet.regionInfo.mapIndex = mapIndex;
packet.regionInfo.x = x;
packet.regionInfo.y = y;
serialize(&packet, buffer);
network.Send(Channels::SERVER, buffer, PACKET_BUFFER_SIZE);
}
//-------------------------
//Utilities
//-------------------------
//TODO: convert this into a more generic function?; using parameters for the bounds
void InWorld::UpdateMap() {
//these represent the zone of regions that the client needs loaded, including the mandatory buffers (+1/-1)
int xStart = snapToBase(REGION_WIDTH, camera.x/tileSheet.GetTileW()) - REGION_WIDTH;
int xEnd = snapToBase(REGION_WIDTH, (camera.x+camera.width)/tileSheet.GetTileW()) + REGION_WIDTH;
int yStart = snapToBase(REGION_HEIGHT, camera.y/tileSheet.GetTileH()) - REGION_HEIGHT;
int yEnd = snapToBase(REGION_HEIGHT, (camera.y+camera.height)/tileSheet.GetTileH()) + REGION_HEIGHT;
//prune distant regions
for (auto it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); /* EMPTY */) {
//check if the region is outside off this area
if ((*it)->GetX() < xStart || (*it)->GetX() > xEnd || (*it)->GetY() < yStart || (*it)->GetY() > yEnd) {
//clunky, but the alternative was time consuming
int tmpX = (*it)->GetX();
int tmpY = (*it)->GetY();
++it;
regionPager.UnloadRegion(tmpX, tmpY);
continue;
}
++it;
}
//request empty regions within this zone
for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
if (!regionPager.FindRegion(i, j)) {
RequestRegion(0, i, j);
}
}
}
}
+122
View File
@@ -0,0 +1,122 @@
/* 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 INWORLD_HPP_
#define INWORLD_HPP_
//maps
#include "map_allocator.hpp"
#include "map_file_format.hpp"
#include "region_pager.hpp"
//networking
#include "udp_network_utility.hpp"
#include "serial_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 {
public:
//Public access members
InWorld(ConfigUtility* const, UDPNetworkUtility* const, int* const, int* const, int* const);
~InWorld();
protected:
//Frame loop
void FrameStart();
void Update(double delta);
void FrameEnd();
void RenderFrame();
void Render(SDL_Surface* const);
//Event handlers
void QuitEvent();
void MouseMotion(SDL_MouseMotionEvent const&);
void MouseButtonDown(SDL_MouseButtonEvent const&);
void MouseButtonUp(SDL_MouseButtonEvent const&);
void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&);
//Network handlers
void HandlePacket(SerialPacket);
void HandleDisconnect(SerialPacket);
void HandleCharacterNew(SerialPacket);
void HandleCharacterDelete(SerialPacket);
void HandleCharacterUpdate(SerialPacket);
void HandleRegionContent(SerialPacket);
//Server control
void SendPlayerUpdate();
void RequestDisconnect();
void RequestShutDown();
void RequestRegion(int mapIndex, int x, int y);
//utilities
void UpdateMap();
//shared parameters
ConfigUtility& config;
UDPNetworkUtility& network;
int& clientIndex;
int& accountIndex;
int& characterIndex;
//graphics
Image buttonImage;
RasterFont font;
TileSheet tileSheet;
//map
RegionPager<BlankAllocator, DummyFormat> regionPager;
//UI
Button disconnectButton;
Button shutDownButton;
//TODO: Fix the camera
struct {
int x = 0, y = 0;
int width = 0, height = 0;
int marginX = 0, marginY = 0;
} camera;
FrameRate fps;
//game
std::map<int, PlayerCharacter> playerCharacters;
PlayerCharacter* localCharacter = nullptr;
};
#endif
+236
View File
@@ -0,0 +1,236 @@
/* 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 "lobby_menu.hpp"
#include "channels.hpp"
#include "utility.hpp"
#include <stdexcept>
//-------------------------
//Public access members
//-------------------------
LobbyMenu::LobbyMenu(ConfigUtility* const argConfig, UDPNetworkUtility* const argNetwork, int* const argClientIndex, int* const argAccountIndex, int* const argCharacterIndex):
config(*argConfig),
network(*argNetwork),
clientIndex(*argClientIndex),
accountIndex(*argAccountIndex),
characterIndex(*argCharacterIndex)
{
//setup the utility objects
image.LoadSurface(config["dir.interface"] + "button_menu.bmp");
image.SetClipH(image.GetClipH()/3);
font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp");
//pass the utility objects
search.SetImage(&image);
search.SetFont(&font);
join.SetImage(&image);
join.SetFont(&font);
back.SetImage(&image);
back.SetFont(&font);
//set the button positions
search.SetX(50);
search.SetY(50 + image.GetClipH() * 0);
join.SetX(50);
join.SetY(50 + image.GetClipH() * 1);
back.SetX(50);
back.SetY(50 + image.GetClipH() * 2);
//set the button texts
search.SetText("Search");
join.SetText("Join");
back.SetText("Back");
//set the server list's position
listBox = {300, 50, 200, font.GetCharH()};
}
LobbyMenu::~LobbyMenu() {
//
}
//-------------------------
//Frame loop
//-------------------------
void LobbyMenu::FrameStart() {
//
}
void LobbyMenu::Update(double delta) {
//suck in all waiting packets
SerialPacket packet;
while(network.Receive()) {
deserialize(&packet, network.GetInData());
packet.meta.srcAddress = network.GetInPacket()->address;
HandlePacket(packet);
}
}
void LobbyMenu::FrameEnd() {
//
}
void LobbyMenu::Render(SDL_Surface* const screen) {
//TODO: I need a proper UI system for the entire client and the editor
//UI
search.DrawTo(screen);
join.DrawTo(screen);
back.DrawTo(screen);
//TODO: draw headers for the server list
for (int i = 0; i < serverInfo.size(); i++) {
//draw the selected server's highlight
if (selection == &serverInfo[i]) {
SDL_Rect r = listBox;
r.y += i * listBox.h;
SDL_FillRect(screen, &r, SDL_MapRGB(screen->format, 255, 127, 39));
}
//draw the server name
font.DrawStringTo(serverInfo[i].name, screen, listBox.x, listBox.y + i*listBox.h);
//draw the player count
font.DrawStringTo(to_string_custom(serverInfo[i].playerCount), screen, listBox.x + listBox.w, listBox.y + i*listBox.h);
//compatible?
if (!serverInfo[i].compatible) {
font.DrawStringTo("?", screen, listBox.x - font.GetCharW(), listBox.y + i*listBox.h);
}
//ping?
}
}
//-------------------------
//Event handlers
//-------------------------
void LobbyMenu::MouseMotion(SDL_MouseMotionEvent const& motion) {
search.MouseMotion(motion);
join.MouseMotion(motion);
back.MouseMotion(motion);
}
void LobbyMenu::MouseButtonDown(SDL_MouseButtonEvent const& button) {
search.MouseButtonDown(button);
join.MouseButtonDown(button);
back.MouseButtonDown(button);
}
void LobbyMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
if (search.MouseButtonUp(button) == Button::State::HOVER) {
//the vars
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//broadcast to the network, or a specific server
packet.meta.type = SerialPacket::Type::BROADCAST_REQUEST;
serialize(&packet, buffer);
network.Send(config["server.host"].c_str(), config.Int("server.port"), buffer, PACKET_BUFFER_SIZE);
//reset the server list
serverInfo.clear();
selection = nullptr;
}
else if (join.MouseButtonUp(button) == Button::State::HOVER && selection != nullptr && selection->compatible) {
//the vars
SerialPacket packet;
char buffer[PACKET_BUFFER_SIZE];
//pack the packet
packet.meta.type = SerialPacket::Type::JOIN_REQUEST;
strncpy(packet.clientInfo.username, config["client.username"].c_str(), PACKET_STRING_SIZE);
strncpy(packet.clientInfo.handle, config["client.handle"].c_str(), PACKET_STRING_SIZE);
strncpy(packet.clientInfo.avatar, config["client.avatar"].c_str(), PACKET_STRING_SIZE);
//join the selected server
serialize(&packet, buffer);
network.Send(&selection->address, buffer, PACKET_BUFFER_SIZE);
selection = nullptr;
}
else if (back.MouseButtonUp(button) == Button::State::HOVER) {
SetNextScene(SceneList::MAINMENU);
}
else if (
//has the user selected a server on the list?
button.x > listBox.x &&
button.x < listBox.x + listBox.w &&
button.y > listBox.y &&
button.y < listBox.y + listBox.h * serverInfo.size()
) {
selection = &serverInfo[(button.y - listBox.y)/listBox.h];
}
else {
selection = nullptr;
}
}
void LobbyMenu::KeyDown(SDL_KeyboardEvent const& key) {
switch(key.keysym.sym) {
case SDLK_ESCAPE:
SetNextScene(SceneList::MAINMENU);
break;
}
}
void LobbyMenu::KeyUp(SDL_KeyboardEvent const& key) {
//
}
void LobbyMenu::HandlePacket(SerialPacket packet) {
switch(packet.meta.type) {
case SerialPacket::Type::BROADCAST_RESPONSE: {
//extract the data
ServerInformation server;
server.address = packet.meta.srcAddress;
server.networkVersion = packet.serverInfo.networkVersion;
server.name = packet.serverInfo.name;
server.playerCount = packet.serverInfo.playerCount;
//NOTE: Check compatibility here
server.compatible = server.networkVersion == NETWORK_VERSION;
//push
serverInfo.push_back(server);
}
break;
case SerialPacket::Type::JOIN_RESPONSE:
clientIndex = packet.clientInfo.clientIndex;
accountIndex = packet.clientInfo.accountIndex;
characterIndex = packet.clientInfo.characterIndex;
network.Bind(&packet.meta.srcAddress, Channels::SERVER);
SetNextScene(SceneList::INWORLD);
break;
//handle errors
default:
throw(std::runtime_error(std::string() + "Unknown SerialPacket::Type encountered in LobbyMenu: " + to_string_custom(int(packet.meta.type))));
break;
}
}
+95
View File
@@ -0,0 +1,95 @@
/* 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 LOBBYMENU_HPP_
#define LOBBYMENU_HPP_
//graphics & utilities
#include "image.hpp"
#include "raster_font.hpp"
#include "button.hpp"
#include "config_utility.hpp"
//network
#include "udp_network_utility.hpp"
#include "serial_packet.hpp"
#include "serial.hpp"
//client
#include "base_scene.hpp"
//STL
#include <vector>
class LobbyMenu : public BaseScene {
public:
//Public access members
LobbyMenu(ConfigUtility* const, UDPNetworkUtility* const, int* const, int* const, int* const);
~LobbyMenu();
protected:
//Frame loop
void FrameStart();
void Update(double delta);
void FrameEnd();
void Render(SDL_Surface* const);
//Event handlers
void MouseMotion(SDL_MouseMotionEvent const&);
void MouseButtonDown(SDL_MouseButtonEvent const&);
void MouseButtonUp(SDL_MouseButtonEvent const&);
void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&);
void HandlePacket(SerialPacket);
//shared parameters
ConfigUtility& config;
UDPNetworkUtility& network;
int& clientIndex;
int& accountIndex;
int& characterIndex;
//members
Image image;
RasterFont font;
Button search;
Button join;
Button back;
//server list
struct ServerInformation {
IPaddress address;
int networkVersion;
std::string name;
int playerCount;
bool compatible;
};
std::vector<ServerInformation> serverInfo;
//a terrible hack, forgive me
//I'd love a proper gui system for this
SDL_Rect listBox;
ServerInformation* selection = nullptr;
};
#endif
+122
View File
@@ -0,0 +1,122 @@
/* 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 "main_menu.hpp"
//-------------------------
//Public access members
//-------------------------
MainMenu::MainMenu(ConfigUtility* const argConfig):
config(*argConfig)
{
//setup the utility objects
image.LoadSurface(config["dir.interface"] + "button_menu.bmp");
image.SetClipH(image.GetClipH()/3);
font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp");
//pass the utility objects
startButton.SetImage(&image);
startButton.SetFont(&font);
optionsButton.SetImage(&image);
optionsButton.SetFont(&font);
quitButton.SetImage(&image);
quitButton.SetFont(&font);
//set the button positions
startButton.SetX(50);
startButton.SetY(50 + image.GetClipH() * 0);
optionsButton.SetX(50);
optionsButton.SetY(50 + image.GetClipH() * 1);
quitButton.SetX(50);
quitButton.SetY(50 + image.GetClipH() * 2);
//set the button texts
startButton.SetText("Start");
optionsButton.SetText("Options");
quitButton.SetText("Quit");
}
MainMenu::~MainMenu() {
//
}
//-------------------------
//Frame loop
//-------------------------
void MainMenu::FrameStart() {
//
}
void MainMenu::Update(double delta) {
//
}
void MainMenu::FrameEnd() {
//
}
void MainMenu::Render(SDL_Surface* const screen) {
startButton.DrawTo(screen);
optionsButton.DrawTo(screen);
quitButton.DrawTo(screen);
}
//-------------------------
//Event handlers
//-------------------------
void MainMenu::MouseMotion(SDL_MouseMotionEvent const& motion) {
startButton.MouseMotion(motion);
optionsButton.MouseMotion(motion);
quitButton.MouseMotion(motion);
}
void MainMenu::MouseButtonDown(SDL_MouseButtonEvent const& button) {
startButton.MouseButtonDown(button);
optionsButton.MouseButtonDown(button);
quitButton.MouseButtonDown(button);
}
void MainMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
if (startButton.MouseButtonUp(button) == Button::State::HOVER) {
SetNextScene(SceneList::LOBBYMENU);
}
if (optionsButton.MouseButtonUp(button) == Button::State::HOVER) {
SetNextScene(SceneList::OPTIONSMENU);
}
if (quitButton.MouseButtonUp(button) == Button::State::HOVER) {
QuitEvent();
}
}
void MainMenu::KeyDown(SDL_KeyboardEvent const& key) {
switch(key.keysym.sym) {
case SDLK_ESCAPE:
QuitEvent();
break;
}
}
void MainMenu::KeyUp(SDL_KeyboardEvent const& key) {
//
}
+63
View File
@@ -0,0 +1,63 @@
/* 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 MAINMENU_HPP_
#define MAINMENU_HPP_
#include "base_scene.hpp"
#include "config_utility.hpp"
#include "image.hpp"
#include "raster_font.hpp"
#include "button.hpp"
class MainMenu : public BaseScene {
public:
//Public access members
MainMenu(ConfigUtility* const);
~MainMenu();
protected:
//Frame loop
void FrameStart();
void Update(double delta);
void FrameEnd();
void Render(SDL_Surface* const);
//Event handlers
void MouseMotion(SDL_MouseMotionEvent const&);
void MouseButtonDown(SDL_MouseButtonEvent const&);
void MouseButtonUp(SDL_MouseButtonEvent const&);
void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&);
//shared parameters
ConfigUtility& config;
//members
Image image;
RasterFont font;
Button startButton;
Button optionsButton;
Button quitButton;
};
#endif
+43
View File
@@ -0,0 +1,43 @@
#config
INCLUDES+=. .. ../../common ../../common/graphics ../../common/map ../../common/network ../../common/ui
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)/,libclient.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
+102
View File
@@ -0,0 +1,102 @@
/* 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 "options_menu.hpp"
//-------------------------
//Public access members
//-------------------------
OptionsMenu::OptionsMenu(ConfigUtility* const argConfig):
config(*argConfig)
{
//setup the utility objects
image.LoadSurface(config["dir.interface"] + "button_menu.bmp");
image.SetClipH(image.GetClipH()/3);
font.LoadSurface(config["dir.fonts"] + "pk_white_8.bmp");
//pass the utility objects
backButton.SetImage(&image);
backButton.SetFont(&font);
//set the button positions
backButton.SetX(50);
backButton.SetY(50 + image.GetClipH() * 0);
//set the button texts
backButton.SetText("Back");
}
OptionsMenu::~OptionsMenu() {
//
}
//-------------------------
//Frame loop
//-------------------------
void OptionsMenu::FrameStart() {
//
}
void OptionsMenu::Update(double delta) {
//
}
void OptionsMenu::FrameEnd() {
//
}
void OptionsMenu::Render(SDL_Surface* const screen) {
backButton.DrawTo(screen);
font.DrawStringTo("Oh, were you looking for the options screen?", screen, 50, 30);
}
//-------------------------
//Event handlers
//-------------------------
void OptionsMenu::MouseMotion(SDL_MouseMotionEvent const& motion) {
backButton.MouseMotion(motion);
}
void OptionsMenu::MouseButtonDown(SDL_MouseButtonEvent const& button) {
backButton.MouseButtonDown(button);
}
void OptionsMenu::MouseButtonUp(SDL_MouseButtonEvent const& button) {
if (backButton.MouseButtonUp(button) == Button::State::HOVER) {
SetNextScene(SceneList::MAINMENU);
}
}
void OptionsMenu::KeyDown(SDL_KeyboardEvent const& key) {
switch(key.keysym.sym) {
case SDLK_ESCAPE:
SetNextScene(SceneList::MAINMENU);
break;
}
}
void OptionsMenu::KeyUp(SDL_KeyboardEvent const& key) {
//
}
+61
View File
@@ -0,0 +1,61 @@
/* 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 OPTIONSMENU_HPP_
#define OPTIONSMENU_HPP_
#include "base_scene.hpp"
#include "config_utility.hpp"
#include "image.hpp"
#include "raster_font.hpp"
#include "button.hpp"
class OptionsMenu : public BaseScene {
public:
//Public access members
OptionsMenu(ConfigUtility* const);
~OptionsMenu();
protected:
//Frame loop
void FrameStart();
void Update(double delta);
void FrameEnd();
void Render(SDL_Surface* const);
//Event handlers
void MouseMotion(SDL_MouseMotionEvent const&);
void MouseButtonDown(SDL_MouseButtonEvent const&);
void MouseButtonUp(SDL_MouseButtonEvent const&);
void KeyDown(SDL_KeyboardEvent const&);
void KeyUp(SDL_KeyboardEvent const&);
//shared parameters
ConfigUtility& config;
//members
Image image;
RasterFont font;
Button backButton;
};
#endif
+51
View File
@@ -0,0 +1,51 @@
/* 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 "splash_screen.hpp"
//-------------------------
//Public access members
//-------------------------
SplashScreen::SplashScreen(ConfigUtility* const argConfig):
config(*argConfig)
{
logo.LoadSurface(config["dir.logos"] + "krstudios.bmp");
startTick = std::chrono::steady_clock::now();
}
SplashScreen::~SplashScreen() {
//
}
//-------------------------
//Frame loop
//-------------------------
void SplashScreen::Update(double delta) {
if (std::chrono::steady_clock::now() - startTick > std::chrono::duration<int>(1)) {
SetNextScene(SceneList::MAINMENU);
}
}
void SplashScreen::Render(SDL_Surface* const screen) {
logo.DrawTo(screen, (screen->w - logo.GetClipW()) / 2, (screen->h - logo.GetClipH()) / 2);
}
+51
View File
@@ -0,0 +1,51 @@
/* 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 SPLASHSCREEN_HPP_
#define SPLASHSCREEN_HPP_
#include "base_scene.hpp"
#include "config_utility.hpp"
#include "image.hpp"
#include <chrono>
class SplashScreen : public BaseScene {
public:
//Public access members
SplashScreen(ConfigUtility* const);
~SplashScreen();
protected:
//Frame loop
void Update(double delta);
void Render(SDL_Surface* const);
//shared parameters
ConfigUtility& config;
//members
std::chrono::steady_clock::time_point startTick;
Image logo;
};
#endif
+75
View File
@@ -0,0 +1,75 @@
/* Copyright: (c) Kayne Ruse 2013, 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef BBOX_HPP_
#define BBOX_HPP_
#include <type_traits>
#include <stdexcept>
#include <algorithm>
//TODO: This is supposed to interact with the vector
class BBox {
public:
double x, y;
double w, h;
BBox() = default;
BBox(double i, double j, double k, double l): x(i), y(j), w(k), h(l) {};
~BBox() = default;
BBox& operator=(BBox const&) = default;
double Size() {
return std::max(w*h,0.0);
}
bool IsCollision(BBox rhs) {
return not (
x >= rhs.x + rhs.w ||
y >= rhs.y + rhs.h ||
rhs.x >= x + w ||
rhs.y >= y + h
);
}
BBox Intersection(BBox rhs) {
if (!IsCollision(rhs)) {
return {0, 0, 0, 0};
}
BBox ret;
ret.x = std::max(x, rhs.x);
ret.y = std::max(y, rhs.y);
ret.w = std::min(x+w, rhs.x+rhs.w) - ret.x;
ret.h = std::min(y+h, rhs.y+rhs.h) - ret.y;
return ret;
}
double operator[](size_t i) {
if (i >= 4)
throw(std::domain_error("Out of range"));
return *(&x+i);
}
};
//This is explicitly a POD
static_assert(std::is_pod<BBox>::value, "BBox is not a POD");
#endif
+105
View File
@@ -0,0 +1,105 @@
/* 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 "config_utility.hpp"
#include <cstdlib>
#include <fstream>
#include <stdexcept>
using namespace std;
void ConfigUtility::Load(string fname) {
ifstream is(fname);
if (!is.is_open()) {
throw(runtime_error("Failed to open config file"));
}
string key, val;
for (;;) { //forever
//eat whitespace
while(isspace(is.peek()))
is.ignore();
//end of file
if (is.eof())
break;
//skip comment lines
if (is.peek() == '#') {
while(is.peek() != '\n' && !is.eof()) {
is.ignore();
}
continue;
}
//read in the pair
getline(is, key,'=');
getline(is, val);
//trim the strings at the start & end
while(key.size() && isspace(*key.begin())) key.erase(0, 1);
while(val.size() && isspace(*val.begin())) val.erase(0, 1);
while(key.size() && isspace(*(key.end()-1))) key.erase(key.end() - 1);
while(val.size() && isspace(*(val.end()-1))) val.erase(val.end() - 1);
//allow empty/wiped values
if (key.size() == 0) {
continue;
}
//save the pair
table[key] = val;
}
is.close();
}
std::string& ConfigUtility::String(std::string s) {
return table[s];
}
int ConfigUtility::Integer(std::string s) {
std::map<std::string, std::string>::iterator it = table.find(s);
if (it == table.end()) {
return 0;
}
return atoi(it->second.c_str());
}
double ConfigUtility::Double(std::string s) {
std::map<std::string, std::string>::iterator it = table.find(s);
if (it == table.end()) {
return 0.0;
}
return atof(it->second.c_str());
}
bool ConfigUtility::Boolean(std::string s) {
std::map<std::string, std::string>::iterator it = table.find(s);
if (it == table.end()) {
return false;
}
return it->second == "true";
}
+60
View File
@@ -0,0 +1,60 @@
/* 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 CONFIGUTILITY_HPP_
#define CONFIGUTILITY_HPP_
#include <map>
#include <string>
class ConfigUtility {
public:
ConfigUtility() = default;
ConfigUtility(std::string s) { Load(s); }
void Load(std::string fname);
//convert to a type
std::string& String(std::string);
int Integer(std::string);
double Double(std::string);
bool Boolean(std::string);
//shorthand
std::string& operator[](std::string s) {
return String(s);
}
int Int(std::string s) {
return Integer(s);
}
bool Bool(std::string s) {
return Boolean(s);
}
//OO breaker
std::map<std::string, std::string>* GetMap() {
return &table;
}
private:
std::map<std::string, std::string> table;
};
#endif
+48
View File
@@ -0,0 +1,48 @@
/* 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 FRAMERATE_HPP_
#define FRAMERATE_HPP_
#include <chrono>
class FrameRate {
public:
typedef std::chrono::high_resolution_clock Clock;
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();
};
#endif
+145
View File
@@ -0,0 +1,145 @@
/* 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 "image.hpp"
#include <stdexcept>
#include <sstream>
Image& Image::operator=(Image const& rhs) {
//don't screw yourself
if (this == &rhs) {
return *this;
}
FreeSurface();
//Copy the other Image's stuff
surface = rhs.surface;
clip = rhs.clip;
local = false;
}
Image& Image::operator=(Image&& rhs) {
//don't screw yourself
if (this == &rhs) {
return *this;
}
FreeSurface();
//Steal the other Image's stuff
surface = rhs.surface;
clip = rhs.clip;
local = rhs.local;
rhs.surface = nullptr;
rhs.clip = {0, 0, 0, 0};
rhs.local = false;
}
SDL_Surface* Image::LoadSurface(std::string fname) {
FreeSurface();
SDL_Surface* p = SDL_LoadBMP(fname.c_str());
if (!p) {
std::ostringstream os;
os << "Failed to load file: " << fname;
throw(std::runtime_error(os.str()));
}
surface = p;
clip = {0, 0, (Uint16)surface->w, (Uint16)surface->h};
local = true;
SetTransparentColor(255, 0, 255); //default
return surface;
}
SDL_Surface* Image::CreateSurface(Uint16 w, Uint16 h) {
FreeSurface();
Uint32 rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
rmask = 0xff000000;
gmask = 0x00ff0000;
bmask = 0x0000ff00;
amask = 0x000000ff;
#else
rmask = 0x000000ff;
gmask = 0x0000ff00;
bmask = 0x00ff0000;
amask = 0xff000000;
#endif
SDL_Surface* p = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 32, rmask, gmask, bmask, amask);
if (!p) {
throw(std::runtime_error("Failed to create Image surface"));
}
surface = p;
clip = {0, 0, (Uint16)surface->w, (Uint16)surface->h};
local = true;
SetTransparentColor(255, 0, 255); //default
return surface;
}
SDL_Surface* Image::SetSurface(SDL_Surface* p) {
FreeSurface();
if (!p) {
throw(std::invalid_argument("No surface pointer provided"));
}
surface = p;
clip = {0, 0, (Uint16)surface->w, (Uint16)surface->h};
local = false;
return surface;
}
void Image::FreeSurface() {
if (local) {
SDL_FreeSurface(surface);
local = false;
}
surface = nullptr;
clip = {0, 0, 0, 0};
}
void Image::DrawTo(SDL_Surface* dest, Sint16 x, Sint16 y) {
if (!surface) {
throw(std::logic_error("No image surface to draw"));
}
SDL_Rect sclip = clip, dclip = {x,y};
SDL_BlitSurface(surface, &sclip, dest, &dclip);
}
void Image::SetTransparentColor(Uint8 r, Uint8 g, Uint8 b) {
if (!surface) {
throw(std::logic_error("Failed to set the transparent color"));
}
if (!local) {
throw(std::logic_error("Cannot set the transparent color of a non-local surface"));
}
SDL_SetColorKey(surface, SDL_SRCCOLORKEY, SDL_MapRGB(surface->format, r, g, b));
}
void Image::ClearTransparentColor() {
if (!surface) {
throw(std::logic_error("Failed to clear the transparent color"));
}
if (!local) {
throw(std::logic_error("Cannot clear the transparent color of a non-local surface"));
}
SDL_SetColorKey(surface, 0, 0);
}
+73
View File
@@ -0,0 +1,73 @@
/* 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 IMAGE_HPP_
#define IMAGE_HPP_
#include "SDL/SDL.h"
#include <string>
class Image {
public:
Image() = default;
Image(Image const& rhs) { *this = rhs; }
Image(Image&& rhs) { *this = std::move(rhs); }
Image(std::string fname) { LoadSurface(fname); }
Image(Uint16 w, Uint16 h) { CreateSurface(w, h); }
Image(SDL_Surface* p) { SetSurface(p); }
~Image() { FreeSurface(); }
Image& operator=(Image const&);
Image& operator=(Image&&);
SDL_Surface* LoadSurface(std::string fname);
SDL_Surface* CreateSurface(Uint16 w, Uint16 h);
SDL_Surface* SetSurface(SDL_Surface*);
SDL_Surface* GetSurface() const { return surface; }
void FreeSurface();
void DrawTo(SDL_Surface* const, Sint16 x, Sint16 y);
//Clip handlers
SDL_Rect SetClip(SDL_Rect r) { return clip = r; }
SDL_Rect GetClip() const { return clip; }
Sint16 SetClipX(Sint16 x) { return clip.x = x; }
Sint16 SetClipY(Sint16 y) { return clip.y = y; }
Uint16 SetClipW(Uint16 w) { return clip.w = w; }
Uint16 SetClipH(Uint16 h) { return clip.h = h; }
Sint16 GetClipX() const { return clip.x; }
Sint16 GetClipY() const { return clip.y; }
Uint16 GetClipW() const { return clip.w; }
Uint16 GetClipH() const { return clip.h; }
bool GetLocal() const { return local; }
void SetTransparentColor(Uint8 r, Uint8 g, Uint8 b);
void ClearTransparentColor();
protected:
SDL_Surface* surface = nullptr;
SDL_Rect clip = {0, 0, 0, 0};
bool local = false;
};
#endif
+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
+102
View File
@@ -0,0 +1,102 @@
/* 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 "sprite_sheet.hpp"
#include <stdexcept>
#include <sstream>
void SpriteSheet::Update(double delta) {
if (delay && (tick += delta) >= delay) {
if (++xIndex >= xCount) {
xIndex = 0;
}
tick = 0;
}
image.SetClipX(xIndex * image.GetClipW());
image.SetClipY(yIndex * image.GetClipH());
}
SDL_Surface* SpriteSheet::LoadSurface(std::string fname, Uint16 xCellCount, Uint16 yCellCount) {
image.LoadSurface(fname);
xCount = xCellCount;
yCount = yCellCount;
image.SetClipW(image.GetSurface()->w / xCount);
image.SetClipH(image.GetSurface()->h / yCount);
xIndex = yIndex = 0;
delay = tick = 0.0;
}
SDL_Surface* SpriteSheet::SetSurface(SDL_Surface* surface, Uint16 xCellCount, Uint16 yCellCount) {
image.SetSurface(surface);
xCount = xCellCount;
yCount = yCellCount;
image.SetClipW(image.GetSurface()->w / xCount);
image.SetClipH(image.GetSurface()->h / yCount);
xIndex = yIndex = 0;
delay = tick = 0.0;
}
void SpriteSheet::FreeSurface() {
image.FreeSurface();
xCount = yCount = 0;
xIndex = yIndex = 0;
delay = tick = 0.0;
}
Uint16 SpriteSheet::SetXCount(Uint16 i) {
xIndex = 0;
return xCount = i;
}
Uint16 SpriteSheet::SetYCount(Uint16 i) {
yIndex = 0;
return yCount = i;
}
Uint16 SpriteSheet::SetXIndex(Uint16 i) {
if (i > xCount) {
std::ostringstream os;
os << "Cannot set x index to " << i;
throw(std::invalid_argument(os.str()));
}
return xIndex = i;
}
Uint16 SpriteSheet::SetYIndex(Uint16 i) {
if (i > yCount) {
std::ostringstream os;
os << "Cannot set y index to " << i;
throw(std::invalid_argument(os.str()));
}
return yIndex = i;
}
double SpriteSheet::SetDelay(double d) {
tick = 0;
return delay = d;
}
+66
View File
@@ -0,0 +1,66 @@
/* 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 SPRITESHEET_HPP_
#define SPRITESHEET_HPP_
#include "image.hpp"
class SpriteSheet {
public:
SpriteSheet() = default;
SpriteSheet(std::string fname, Uint16 xCellCount, Uint16 yCellCount) { LoadSurface(fname, xCellCount, yCellCount); }
SpriteSheet(SDL_Surface* surface, Uint16 xCellCount, Uint16 yCellCount) { SetSurface(surface, xCellCount, yCellCount); }
~SpriteSheet() { FreeSurface(); };
void Update(double delta);
SDL_Surface* LoadSurface(std::string fname, Uint16 xCellCount, Uint16 yCellCount);
SDL_Surface* SetSurface(SDL_Surface* surface, Uint16 xCellCount, Uint16 yCellCount);
SDL_Surface* GetSurface() { return image.GetSurface(); }
void FreeSurface();
void DrawTo(SDL_Surface* const dest, Sint16 x, Sint16 y) { image.DrawTo(dest, x, y); }
//accessors and mutators
Image* GetImage() { return &image; } //OO breaker
Uint16 SetXCount(Uint16);
Uint16 SetYCount(Uint16);
Uint16 SetXIndex(Uint16);
Uint16 SetYIndex(Uint16);
Uint16 GetXCount() const { return xCount; }
Uint16 GetYCount() const { return yCount; }
Uint16 GetXIndex() const { return xIndex; }
Uint16 GetYIndex() const { return yIndex; }
double SetDelay(double d);
double GetDelay() const { return delay; }
private:
Image image;
Uint16 xCount = 0, yCount = 0; //number of cells
Uint16 xIndex = 0, yIndex = 0; //current cell being drawn
double delay = 0.0, tick = 0.0;
};
#endif
+61
View File
@@ -0,0 +1,61 @@
/* Copyright: (c) Kayne Ruse 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "tile_sheet.hpp"
void TileSheet::Load(std::string fname, int xc, int yc) {
XCount = xc;
YCount = yc;
image.LoadSurface(fname);
image.SetClipW(image.GetClipW()/XCount);
image.SetClipH(image.GetClipH()/YCount);
}
void TileSheet::Unload() {
image.FreeSurface();
XCount = YCount = 0;
}
void TileSheet::DrawTo(SDL_Surface* const dest, int x, int y, Region::type_t tile) {
//0 is invisible
if (tile == 0) return;
image.SetClipX((tile-1) % XCount * image.GetClipW());
image.SetClipY((tile-1) / XCount * image.GetClipH());
image.DrawTo(dest, x, y);
}
void TileSheet::DrawRegionTo(SDL_Surface* const dest, Region* const region, int camX, int camY) {
Region::type_t tile = 0;
for (register int i = 0; i < REGION_WIDTH; ++i) {
for (register int j = 0; j < REGION_HEIGHT; ++j) {
for (register int k = 0; k < REGION_DEPTH; ++k) {
tile = region->GetTile(i, j, k);
//0 is invisible
if (tile == 0) continue;
image.SetClipX((tile-1) % XCount * image.GetClipW());
image.SetClipY((tile-1) / XCount * image.GetClipH());
image.DrawTo(dest,
(region->GetX() + i) * image.GetClipW() - camX,
(region->GetY() + j) * image.GetClipH() - camY);
}
}
}
}
+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
+48
View File
@@ -0,0 +1,48 @@
#config
INCLUDES+=.
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)
$(MAKE) -C graphics
$(MAKE) -C map
$(MAKE) -C script
$(MAKE) -C network
$(MAKE) -C ui
$(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
+43
View File
@@ -0,0 +1,43 @@
#config
INCLUDES+=. .. ../graphics
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
+60
View File
@@ -0,0 +1,60 @@
/* Copyright: (c) Kayne Ruse 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "map_allocator.hpp"
#include <stdexcept>
void BlankAllocator::Create(Region** const ptr, int x, int y) {
(*ptr) = new Region(x, y);
}
void BlankAllocator::Unload(Region* const ptr) {
delete ptr;
}
void LuaAllocator::Create(Region** const ptr, int x, int y) {
//something to work on
(*ptr) = new Region(x, y);
//API hook
lua_getglobal(state, "map");
lua_getfield(state, -1, "create");
lua_pushlightuserdata(state, *ptr);
if (lua_pcall(state, 1, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
}
lua_pop(state, 1);
}
void LuaAllocator::Unload(Region* const ptr) {
//API hook
lua_getglobal(state, "map");
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;
}
+48
View File
@@ -0,0 +1,48 @@
/* 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 MAPALLOCATOR_HPP_
#define MAPALLOCATOR_HPP_
#include "region.hpp"
#include "lua/lua.hpp"
class BlankAllocator {
public:
void Create(Region** const, int x, int y);
void Unload(Region* const);
private:
//
};
class LuaAllocator {
public:
void Create(Region** const, int x, int y);
void Unload(Region* const);
lua_State* SetLuaState(lua_State* L) { return state = L; }
lua_State* GetLuaState() { return state; }
private:
lua_State* state = nullptr;
};
#endif
+66
View File
@@ -0,0 +1,66 @@
/* Copyright: (c) Kayne Ruse 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "map_file_format.hpp"
#include <stdexcept>
void DummyFormat::Load(Region** const ptr, int x, int y) {
//EMPTY
}
void DummyFormat::Save(Region* const ptr) {
//EMPTY
}
void LuaFormat::Load(Region** const ptr, int x, int y) {
//something to load into
if (!(*ptr)) {
(*ptr) = new Region(x, y);
}
//API hook
lua_getglobal(state, "map");
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, "map");
lua_getfield(state, -1, "save");
lua_pushlightuserdata(state, ptr);
lua_pushstring(state, saveDir.c_str());
if (lua_pcall(state, 2, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(state, -1) ));
}
lua_pop(state, 1);
}
+60
View File
@@ -0,0 +1,60 @@
/* Copyright: (c) Kayne Ruse 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef MAPFILEFORMAT_HPP_
#define MAPFILEFORMAT_HPP_
#include "region.hpp"
#include "lua/lua.hpp"
#include <string>
class DummyFormat {
public:
void Load(Region** const, int x, int y);
void Save(Region* const);
std::string SetSaveDir(std::string s) { return saveDir = s; }
std::string GetSaveDir() { return saveDir; }
private:
std::string saveDir;
};
//TODO: verbose save file format
//TODO: compact save file format
class LuaFormat {
public:
void Load(Region** const, int x, int y);
void Save(Region* const);
std::string SetSaveDir(std::string s) { return saveDir = s; }
std::string GetSaveDir() { return saveDir; }
lua_State* SetLuaState(lua_State* L) { return state = L; }
lua_State* GetLuaState() { return state; }
private:
std::string saveDir;
lua_State* state = nullptr;
};
#endif
+39
View File
@@ -0,0 +1,39 @@
/* 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.hpp"
Region::Region(int argX, int argY):
x(argX),
y(argY)
{
for (register int i = 0; i < REGION_WIDTH*REGION_HEIGHT*REGION_DEPTH; ++i) {
*(reinterpret_cast<type_t*>(tiles) + i) = 0;
}
}
Region::type_t Region::SetTile(int x, int y, int z, type_t v) {
return tiles[x][y][z] = v;
}
Region::type_t Region::GetTile(int x, int y, int z) {
return tiles[x][y][z];
}
+50
View File
@@ -0,0 +1,50 @@
/* Copyright: (c) Kayne Ruse 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef REGION_HPP_
#define REGION_HPP_
#define REGION_WIDTH 20
#define REGION_HEIGHT 20
#define REGION_DEPTH 3
class Region {
public:
typedef unsigned short type_t;
Region() = delete;
Region(int x, int y);
~Region() = default;
type_t SetTile(int x, int y, int z, type_t v);
type_t GetTile(int x, int y, int z);
//accessors
int GetX() const { return x; }
int GetY() const { return y; }
private:
const int x;
const int y;
type_t tiles[REGION_WIDTH][REGION_HEIGHT][REGION_DEPTH];
};
#endif
+67
View File
@@ -0,0 +1,67 @@
/* Copyright: (c) Kayne Ruse 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "region_pager.hpp"
#include "utility.hpp"
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(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//get the region by various means
Region* ptr = nullptr;
ptr = FindRegion(x, y);
if (ptr) return ptr;
ptr = LoadRegion(x, y);
if (ptr) return ptr;
return CreateRegion(x, y);
}
Region* RegionPagerBase::FindRegion(int x, int y) {
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//find the region
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); it++) {
if ((*it)->GetX() == x && (*it)->GetY() == y) {
return *it;
}
}
return nullptr;
}
Region* RegionPagerBase::PushRegion(Region* ptr) {
regionList.push_front(ptr);
return regionList.front();
}
+133
View File
@@ -0,0 +1,133 @@
/* 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 REGIONPAGER_HPP_
#define REGIONPAGER_HPP_
#include "region.hpp"
#include "utility.hpp"
#include <list>
class RegionPagerBase {
public:
RegionPagerBase() {};
virtual ~RegionPagerBase() {};
//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);
//region manipulation
Region* GetRegion(int x, int y);
Region* FindRegion(int x, int y);
Region* PushRegion(Region*);
//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 existing regions
//accessors & mutators
std::list<Region*>* GetContainer() { return &regionList; }
protected:
std::list<Region*> regionList;
};
template<typename Allocator, typename FileFormat>
class RegionPager : public RegionPagerBase {
public:
RegionPager() {};
~RegionPager() {
UnloadAll();
}
Region* LoadRegion(int x, int y) {
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//load the region if possible
Region* ptr = nullptr;
format.Load(&ptr, x, y);
if (ptr) {
return PushRegion(ptr);
}
return nullptr;
}
Region* SaveRegion(int x, int y) {
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//find & save the region
Region* ptr = FindRegion(x, y);
if (ptr) {
format.Save(ptr);
}
return ptr;
}
Region* CreateRegion(int x, int y) {
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//create and push the object
Region* ptr = nullptr;
allocator.Create(&ptr, x, y);
return PushRegion(ptr);
}
void UnloadRegion(int x, int y) {
//snap the coords
x = snapToBase(REGION_WIDTH, x);
y = snapToBase(REGION_HEIGHT, y);
//custom loop
for (std::list<Region*>::iterator it = regionList.begin(); it != regionList.end(); /* EMPTY */) {
if ((*it)->GetX() == x && (*it)->GetY() == y) {
allocator.Unload(*it);
it = regionList.erase(it);
continue;
}
++it;
}
}
void UnloadAll() {
for (auto& it : regionList) {
allocator.Unload(it);
}
regionList.clear();
}
//accessors
Allocator* GetAllocator() { return &allocator; }
FileFormat* GetFormat() { return &format; }
protected:
Allocator allocator;
FileFormat format;
};
#endif
+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
+286
View File
@@ -0,0 +1,286 @@
/* Copyright: (c) Kayne Ruse 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "serial.hpp"
#include "map_allocator.hpp"
#include <cstring>
//-------------------------
//Convenience Macros
//-------------------------
#define SERIALIZE(buffer, data, size) memcpy(buffer, data, size); buffer += size;
#define DESERIALIZE(buffer, data, size) memcpy(data, buffer, size); buffer += size;
//-------------------------
//internal serialization functions
//-------------------------
void serializeType(SerialPacket* packet, char* buffer) {
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
}
void serializeServer(SerialPacket* packet, char* buffer) {
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//server info
SERIALIZE(buffer, &packet->serverInfo.networkVersion, sizeof(int));
SERIALIZE(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
SERIALIZE(buffer, &packet->serverInfo.playerCount, sizeof(int));
}
void serializeClient(SerialPacket* packet, char* buffer) {
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//indexes
SERIALIZE(buffer, &packet->clientInfo.clientIndex, sizeof(int));
SERIALIZE(buffer, &packet->clientInfo.accountIndex, sizeof(int));
SERIALIZE(buffer, &packet->clientInfo.characterIndex, sizeof(int));
//texts
SERIALIZE(buffer, packet->clientInfo.username, PACKET_STRING_SIZE);
SERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE);
SERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE);
}
void serializeRegionFormat(SerialPacket* packet, char* buffer) {
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//format
SERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
SERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
SERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
}
void serializeRegionContent(SerialPacket* packet, char* buffer) {
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//format
SERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
SERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
SERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
//content
for (register int i = 0; i < REGION_WIDTH; i++) {
for (register int j = 0; j < REGION_HEIGHT; j++) {
for (register int k = 0; k < REGION_DEPTH; k++) {
*reinterpret_cast<Region::type_t*>(buffer) = packet->regionInfo.region->GetTile(i, j, k);
buffer += sizeof(Region::type_t);
}
}
}
}
void serializeCharacter(SerialPacket* packet, char* buffer) {
SERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//indexes
SERIALIZE(buffer, &packet->characterInfo.clientIndex, sizeof(int));
SERIALIZE(buffer, &packet->characterInfo.accountIndex, sizeof(int));
SERIALIZE(buffer, &packet->characterInfo.characterIndex, sizeof(int));
//texts
SERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE);
SERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE);
//vectors
SERIALIZE(buffer, &packet->characterInfo.position.x, sizeof(double));
SERIALIZE(buffer, &packet->characterInfo.position.y, sizeof(double));
SERIALIZE(buffer, &packet->characterInfo.motion.x, sizeof(double));
SERIALIZE(buffer, &packet->characterInfo.motion.y, sizeof(double));
}
//-------------------------
//internal deserialization functions
//-------------------------
void deserializeType(SerialPacket* packet, char* buffer) {
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
}
void deserializeServer(SerialPacket* packet, char* buffer) {
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//server info
DESERIALIZE(buffer, &packet->serverInfo.networkVersion, sizeof(int));
DESERIALIZE(buffer, packet->serverInfo.name, PACKET_STRING_SIZE);
DESERIALIZE(buffer, &packet->serverInfo.playerCount, sizeof(int));
}
void deserializeClient(SerialPacket* packet, char* buffer) {
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//indexes
DESERIALIZE(buffer, &packet->clientInfo.clientIndex, sizeof(int));
DESERIALIZE(buffer, &packet->clientInfo.accountIndex, sizeof(int));
DESERIALIZE(buffer, &packet->clientInfo.characterIndex, sizeof(int));
//texts
DESERIALIZE(buffer, packet->clientInfo.username, PACKET_STRING_SIZE);
DESERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE);
DESERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE);
}
void deserializeRegionFormat(SerialPacket* packet, char* buffer) {
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//format
DESERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
DESERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
DESERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
}
void deserializeRegionContent(SerialPacket* packet, char* buffer) {
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//format
DESERIALIZE(buffer, &packet->regionInfo.mapIndex, sizeof(int));
DESERIALIZE(buffer, &packet->regionInfo.x, sizeof(int));
DESERIALIZE(buffer, &packet->regionInfo.y, sizeof(int));
//an object to work on
BlankAllocator().Create(
&packet->regionInfo.region,
packet->regionInfo.x,
packet->regionInfo.y
);
//content
for (register int i = 0; i < REGION_WIDTH; i++) {
for (register int j = 0; j < REGION_HEIGHT; j++) {
for (register int k = 0; k < REGION_DEPTH; k++) {
packet->regionInfo.region->SetTile(i, j, k, *reinterpret_cast<Region::type_t*>(buffer));
buffer += sizeof(Region::type_t);
}
}
}
}
void deserializeCharacter(SerialPacket* packet, char* buffer) {
DESERIALIZE(buffer, &packet->meta.type, sizeof(SerialPacket::Type));
//indexes
DESERIALIZE(buffer, &packet->characterInfo.clientIndex, sizeof(int));
DESERIALIZE(buffer, &packet->characterInfo.accountIndex, sizeof(int));
DESERIALIZE(buffer, &packet->characterInfo.characterIndex, sizeof(int));
//texts
DESERIALIZE(buffer, packet->clientInfo.handle, PACKET_STRING_SIZE);
DESERIALIZE(buffer, packet->clientInfo.avatar, PACKET_STRING_SIZE);
//vectors
DESERIALIZE(buffer, &packet->characterInfo.position.x, sizeof(double));
DESERIALIZE(buffer, &packet->characterInfo.position.y, sizeof(double));
DESERIALIZE(buffer, &packet->characterInfo.motion.x, sizeof(double));
DESERIALIZE(buffer, &packet->characterInfo.motion.y, sizeof(double));
}
//-------------------------
//the interface functions
//-------------------------
void serialize(SerialPacket* packet, void* buffer) {
switch(packet->meta.type) {
//No extra data
case SerialPacket::Type::NONE:
case SerialPacket::Type::PING:
case SerialPacket::Type::PONG:
case SerialPacket::Type::BROADCAST_REQUEST:
serializeType(packet, reinterpret_cast<char*>(buffer));
break;
//Server info
case SerialPacket::Type::BROADCAST_RESPONSE:
serializeServer(packet, reinterpret_cast<char*>(buffer));
break;
//Client info
case SerialPacket::Type::JOIN_REQUEST:
case SerialPacket::Type::JOIN_RESPONSE:
case SerialPacket::Type::SYNCHRONIZE:
case SerialPacket::Type::DISCONNECT:
case SerialPacket::Type::SHUTDOWN:
serializeClient(packet, reinterpret_cast<char*>(buffer));
break;
//region info
case SerialPacket::Type::REGION_REQUEST:
serializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
break;
case SerialPacket::Type::REGION_CONTENT:
serializeRegionContent(packet, reinterpret_cast<char*>(buffer));
break;
//Character info
case SerialPacket::Type::CHARACTER_NEW:
case SerialPacket::Type::CHARACTER_DELETE:
case SerialPacket::Type::CHARACTER_UPDATE:
serializeCharacter(packet, reinterpret_cast<char*>(buffer));
break;
}
}
void deserialize(SerialPacket* packet, void* buffer) {
//find the type, so that you can actually deserialize the packet!
deserializeType(packet, reinterpret_cast<char*>(buffer));
switch(packet->meta.type) {
//No extra data
case SerialPacket::Type::NONE:
case SerialPacket::Type::PING:
case SerialPacket::Type::PONG:
case SerialPacket::Type::BROADCAST_REQUEST:
//NOTHING
break;
//Server info
case SerialPacket::Type::BROADCAST_RESPONSE:
deserializeServer(packet, reinterpret_cast<char*>(buffer));
break;
//Client info
case SerialPacket::Type::JOIN_REQUEST:
case SerialPacket::Type::JOIN_RESPONSE:
case SerialPacket::Type::SYNCHRONIZE:
case SerialPacket::Type::DISCONNECT:
case SerialPacket::Type::SHUTDOWN:
deserializeClient(packet, reinterpret_cast<char*>(buffer));
break;
//region info
case SerialPacket::Type::REGION_REQUEST:
deserializeRegionFormat(packet, reinterpret_cast<char*>(buffer));
break;
case SerialPacket::Type::REGION_CONTENT:
deserializeRegionContent(packet, reinterpret_cast<char*>(buffer));
break;
//Character info
case SerialPacket::Type::CHARACTER_NEW:
case SerialPacket::Type::CHARACTER_DELETE:
case SerialPacket::Type::CHARACTER_UPDATE:
deserializeCharacter(packet, reinterpret_cast<char*>(buffer));
break;
}
}
+38
View File
@@ -0,0 +1,38 @@
/* Copyright: (c) Kayne Ruse 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef SERIAL_HPP_
#define SERIAL_HPP_
#include "serial_packet.hpp"
/* NOTE: Keep the PACKET_BUFFER_SIZE up to date
* NOTE: REGION_CONTENT is currently the largest type of packet
* map content: REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizoeof(region::type_t)
* map format: sizeof(int) * 3
* metadata: sizeof(metadata)
*/
#define PACKET_BUFFER_SIZE REGION_WIDTH * REGION_HEIGHT * REGION_DEPTH * sizeof(Region::type_t) + sizeof(int) * 3 + sizeof(SerialPacket::Metadata)
void serialize(SerialPacket* const, void*);
void deserialize(SerialPacket* const, void*);
#endif
+131
View File
@@ -0,0 +1,131 @@
/* 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 SERIALPACKET_HPP_
#define SERIALPACKET_HPP_
#include "vector2.hpp"
#include "region.hpp"
#include "SDL/SDL_net.h"
#define NETWORK_VERSION 20140512
#define PACKET_STRING_SIZE 100
#pragma pack(push, 0)
union SerialPacket {
//types of packets
enum class Type {
//default: there is something wrong
NONE = 0,
//not used
PING = 1,
PONG = 2,
//TODO: rejection message
//Searching for a server to join
BROADCAST_REQUEST = 3,
BROADCAST_RESPONSE = 4,
//try to join the server
JOIN_REQUEST = 5,
JOIN_RESPONSE = 6,
//mass update
SYNCHRONIZE = 7,
//disconnect from the server
DISCONNECT = 8,
//shut down the server
SHUTDOWN = 9,
//map data
REGION_REQUEST = 10,
REGION_CONTENT = 11,
//Character movement, etc.
CHARACTER_NEW = 12,
CHARACTER_DELETE = 13,
CHARACTER_UPDATE = 14,
//TODO: combat packets
};
//metadata on the packet itself
struct Metadata {
Type type;
IPaddress srcAddress;
}meta;
//information about the server
struct ServerInformation {
Metadata meta;
int networkVersion;
char name[PACKET_STRING_SIZE];
int playerCount;
}serverInfo;
//information about the client
struct ClientInformation {
Metadata meta;
int clientIndex;
int accountIndex;
int characterIndex;
char username[PACKET_STRING_SIZE];
char handle[PACKET_STRING_SIZE];
char avatar[PACKET_STRING_SIZE];
}clientInfo;
//map data
struct RegionInformation {
Metadata meta;
int mapIndex;
int x, y;
Region* region;
}regionInfo;
//information about a character
struct CharacterInformation {
Metadata meta;
int clientIndex;
int accountIndex;
int characterIndex;
char handle[PACKET_STRING_SIZE];
char avatar[PACKET_STRING_SIZE];
int mapIndex;
Vector2 position;
Vector2 motion;
}characterInfo;
//defaults
SerialPacket() {
meta.type = Type::NONE;
meta.srcAddress = {0,0};
}
};
#pragma pack(pop)
#endif
+148
View File
@@ -0,0 +1,148 @@
/* 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 "udp_network_utility.hpp"
#include <stdexcept>
void UDPNetworkUtility::Open(int port, int packSize) {
if (!(socket = SDLNet_UDP_Open(port))) {
Close();
throw(std::runtime_error("Failed to open a UDP socket"));
}
if (!(packOut = SDLNet_AllocPacket(packSize))) {
Close();
throw(std::runtime_error("Failed to allocate the out packet"));
}
if (!(packIn = SDLNet_AllocPacket(packSize))) {
Close();
throw(std::runtime_error("Failed to allocate the in packet"));
}
}
void UDPNetworkUtility::Close() {
SDLNet_UDP_Close(socket);
SDLNet_FreePacket(packOut);
SDLNet_FreePacket(packIn);
socket = nullptr;
packOut = nullptr;
packIn = nullptr;
}
int UDPNetworkUtility::Bind(const char* ip, int port, int channel) {
IPaddress add;
if (SDLNet_ResolveHost(&add, ip, port) == -1) {
throw(std::runtime_error("Failed to resolve a host"));
}
return Bind(&add, channel);
}
int UDPNetworkUtility::Bind(IPaddress* add, int channel) {
int ret = SDLNet_UDP_Bind(socket, channel, add);
if (ret == -1) {
throw(std::runtime_error("Failed to bind to a channel"));
}
return ret;
}
void UDPNetworkUtility::Unbind(int channel) {
SDLNet_UDP_Unbind(socket, channel);
}
int UDPNetworkUtility::Send(const char* ip, int port, void* data, int len) {
IPaddress add;
if (SDLNet_ResolveHost(&add, ip, port) == -1) {
throw(std::runtime_error("Failed to resolve a host"));
}
Send(&add, data, len);
}
int UDPNetworkUtility::Send(IPaddress* add, void* data, int len) {
if (len > packOut->maxlen) {
throw(std::runtime_error("Failed to copy the data into the packet"));
}
memset(packOut->data, 0, packOut->maxlen);
memcpy(packOut->data, data, len);
packOut->len = len;
packOut->address = *add;
int ret = SDLNet_UDP_Send(socket, -1, packOut);
if (ret <= 0) {
throw(std::runtime_error("Failed to send a packet"));
}
return ret;
}
int UDPNetworkUtility::Send(int channel, void* data, int len) {
if (len > packOut->maxlen) {
throw(std::runtime_error("Failed to copy the data into the packet"));
}
memset(packOut->data, 0, packOut->maxlen);
memcpy(packOut->data, data, len);
packOut->len = len;
int ret = SDLNet_UDP_Send(socket, channel, packOut);
if (ret <= 0) {
throw(std::runtime_error("Failed to send a packet"));
}
return ret;
}
int UDPNetworkUtility::SendAll(void* data, int len) {
if (len > packOut->maxlen) {
throw(std::runtime_error("Failed to copy the data into the packet"));
}
memset(packOut->data, 0, packOut->maxlen);
memcpy(packOut->data, data, len);
packOut->len = len;
int sent = 0;
//send to all bound channels
for (int i = 0; i < SDLNET_MAX_UDPCHANNELS; i++) {
if (SDLNet_UDP_GetPeerAddress(socket, i)) {
sent += SDLNet_UDP_Send(socket, i, packOut);
}
}
return sent;
}
int UDPNetworkUtility::Receive() {
memset(packIn->data, 0, packIn->maxlen);
int ret = SDLNet_UDP_Recv(socket, packIn);
if (ret < 0) {
throw(std::runtime_error("Unknown network error occured"));
}
return ret;
}
+71
View File
@@ -0,0 +1,71 @@
/* 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 UDPNETWORKUTILITY_HPP_
#define UDPNETWORKUTILITY_HPP_
#include "SDL/SDL_net.h"
class UDPNetworkUtility {
public:
UDPNetworkUtility() = default;
~UDPNetworkUtility() = default;
void Open(int port, int packSize);
void Close();
//bind to a channel
int Bind(const char* ip, int port, int channel = -1);
int Bind(IPaddress* add, int channel = -1);
void Unbind(int channel);
IPaddress* GetIPAddress(int channel) {
return SDLNet_UDP_GetPeerAddress(socket, channel);
}
int Send(const char* ip, int port, void* data, int len);
int Send(IPaddress* add, void* data, int len);
int Send(int channel, void* data, int len);
int SendAll(void* data, int len);
int Receive();
void* GetOutData() const {
return reinterpret_cast<void*>(packOut->data);
};
void* GetInData() const {
return reinterpret_cast<void*>(packIn->data);
};
UDPpacket* GetOutPacket() const {
return packOut;
}
UDPpacket* GetInPacket() const {
return packIn;
}
UDPsocket GetSocket() const {
return socket;
}
private:
UDPsocket socket = nullptr;
UDPpacket* packOut = nullptr;
UDPpacket* packIn = nullptr;
};
#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 "map_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_MAPLIBNAME, luaopen_mapapi},
{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
+126
View File
@@ -0,0 +1,126 @@
/* Copyright: (c) Kayne Ruse 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "map_api.hpp"
//map headers
#include "map_allocator.hpp"
#include "map_file_format.hpp"
#include "region_pager.hpp"
//NOTE: When operating on a region, setTile() & getTile() *are not* zero indexed, but when operating on the entire map they *are* zero indexed.
static int setTile(lua_State* L) {
if (lua_gettop(L) == 5) {
//operating on a region
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));
}
else {
//operating on the whole map
lua_pushstring(L, "pager");
lua_gettable(L, LUA_REGISTRYINDEX);
//assume the pager is using lua
RegionPager<LuaAllocator, LuaFormat>* pager = reinterpret_cast<RegionPager<LuaAllocator, LuaFormat>*>(lua_touserdata(L, -1));
//balance the stack
lua_pop(L, 1);
pager->SetTile(lua_tointeger(L, 1), lua_tointeger(L, 2), lua_tointeger(L, 3), lua_tointeger(L, 4));
}
return 0;
}
static int getTile(lua_State* L) {
if (lua_gettop(L) == 4) {
//operating on a region
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);
}
else {
//operating on the whole map
lua_pushstring(L, "pager");
lua_gettable(L, LUA_REGISTRYINDEX);
//assume the pager is using lua
RegionPager<LuaAllocator, LuaFormat>* pager = reinterpret_cast<RegionPager<LuaAllocator, LuaFormat>*>(lua_touserdata(L, -1));
//balance the stack
lua_pop(L, 1);
int ret = pager->GetTile(lua_tointeger(L, 1), lua_tointeger(L, 2), lua_tointeger(L, 3));
lua_pushnumber(L, ret);
}
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 getRegionWidth(lua_State* L) {
lua_pushinteger(L, REGION_WIDTH);
return 1;
}
static int getRegionHeight(lua_State* L) {
lua_pushinteger(L, REGION_HEIGHT);
return 1;
}
static int getRegionDepth(lua_State* L) {
lua_pushinteger(L, REGION_DEPTH);
return 1;
}
static int dummy(lua_State* L) {
return 0;
}
static const luaL_Reg regionlib[] = {
{"create", dummy},
{"unload", dummy},
{"load", dummy},
{"save", dummy},
{"settile",setTile},
{"gettile",getTile},
{"getx",getX},
{"gety",getY},
{"getregionwidth",getRegionWidth},
{"getregionheight",getRegionHeight},
{"getregiondepth",getRegionDepth},
{nullptr, nullptr}
};
LUAMOD_API int luaopen_mapapi(lua_State* L) {
luaL_newlib(L, regionlib);
return 1;
}
+30
View File
@@ -0,0 +1,30 @@
/* Copyright: (c) Kayne Ruse 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#ifndef MAPAPI_HPP_
#define MAPAPI_HPP_
#include "lua/lua.hpp"
#define LUA_MAPLIBNAME "map"
LUAMOD_API int luaopen_mapapi(lua_State* L);
#endif
+50
View File
@@ -0,0 +1,50 @@
/* Copyright: (c) Kayne Ruse 2014
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "sql_utility.hpp"
#include "utility.hpp"
#include <stdexcept>
#include <fstream>
#include <cstdlib>
int runSQLScript(sqlite3* db, std::string fname, int (*callback)(void*,int,char**,char**), void* argPtr) {
//load the file into a string
std::ifstream is(fname);
if (!is.is_open()) {
return -1;
}
std::string script;
getline(is, script, '\0');
is.close();
//run the SQL loaded from the file
char* errmsg = nullptr;
int ret = sqlite3_exec(db, script.c_str(), callback, argPtr, &errmsg);
if (ret != SQLITE_OK) {
//handle any errors received from the SQL
std::runtime_error e(std::string() + "SQL Script Error " + to_string_custom(ret) + ": " + errmsg);
free(errmsg);
throw(e);
}
return ret;
}
+31
View File
@@ -0,0 +1,31 @@
/* 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 SERVERUTILITY_HPP_
#define SERVERUTILITY_HPP_
#include "sqlite3/sqlite3.h"
#include <string>
int runSQLScript(sqlite3* db, std::string fname, int (*callback)(void*,int,char**,char**) = nullptr, void* argPtr = nullptr);
#endif
+81
View File
@@ -0,0 +1,81 @@
/* 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 "button.hpp"
#include <stdexcept>
Button::State Button::MouseMotion(SDL_MouseMotionEvent const& motion) {
return CalcState(motion.x, motion.y, motion.state & SDL_BUTTON_LMASK);
}
Button::State Button::MouseButtonDown(SDL_MouseButtonEvent const& button) {
if (button.button == SDL_BUTTON_LEFT) {
return CalcState(button.x, button.y, true);
}
return state;
}
Button::State Button::MouseButtonUp(SDL_MouseButtonEvent const& button) {
if (button.button == SDL_BUTTON_LEFT) {
return CalcState(button.x, button.y, false);
}
return state;
}
void Button::DrawTo(SDL_Surface* const dest) {
if (!image || !font) {
throw(std::runtime_error("Surface not set for Button"));
}
image->SetClipY(state * image->GetClipH());
image->DrawTo(dest, x, y);
font->DrawStringTo(text, dest, textX + x, textY + y);
}
std::string Button::SetText(std::string t) {
if (!image || !font) {
throw(std::runtime_error("Surface not set for Button"));
}
//one line, cache the position
text = t;
textX = (image->GetClipW() / 2) - (font->GetCharW() * text.size() / 2);
textY = (image->GetClipH() / 2) - (font->GetCharH() / 2);
return text;
}
Button::State Button::CalcState(Sint16 i, Sint16 j, bool leftPressed) {
if (!image || !font) {
throw(std::runtime_error("Surface not set for Button"));
}
//if out of bounds
if (i < x || i >= (x + image->GetClipW()) ||
j < y || j >= (y + image->GetClipH())
) {
return state = State::NORMAL;
}
if (leftPressed) {
return state = State::PRESSED;
}
else {
return state = State::HOVER;
}
}
+94
View File
@@ -0,0 +1,94 @@
/* 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 BUTTON_HPP_
#define BUTTON_HPP_
#include "image.hpp"
#include "raster_font.hpp"
#include <string>
/* 3-phases, no toggle, centred text
* This class uses the size of the provided image as its bounds. Also,
* The provided image should be formatted correctly.
*
* The button's image should be divided into 3 sections virtucally,
* which act as the different button images. The clip width & height of the
* Image should be set manually, and the height should be 1/3 of the total
* graphical data.
*/
class Button {
public:
enum State {
NORMAL = 0, HOVER = 1, PRESSED = 2
};
Button() = default;
~Button() = default;
//handle input
State MouseMotion(SDL_MouseMotionEvent const&);
State MouseButtonDown(SDL_MouseButtonEvent const&);
State MouseButtonUp(SDL_MouseButtonEvent const&);
//yet another draw function
void DrawTo(SDL_Surface* const);
//accessors and mutators
Image* SetImage(Image* const ptr) { return image = ptr; }
Image* GetImage() { return image; }
RasterFont* SetFont(RasterFont* const ptr) { return font = ptr; }
RasterFont* GetFont() { return font; }
Sint16 SetX(Sint16 i) { return x = i; }
Sint16 SetY(Sint16 i) { return y = i; }
Sint16 GetX() const { return x; }
Sint16 GetY() const { return y; }
Sint16 SetTextX(Sint16 i) { return textX = i; }
Sint16 SetTextY(Sint16 i) { return textY = i; }
Sint16 GetTextX() const { return textX; }
Sint16 GetTextY() const { return textY; }
State SetState(State s) { return state = s; }
State GetState() const { return state; }
std::string SetText(std::string);
std::string GetText() const { return text; }
private:
State CalcState(Sint16 x, Sint16 y, bool leftPressed);
//point to the provided external objects
Image* image = nullptr;
RasterFont* font = nullptr;
//positions
Sint16 x = 0, y = 0;
Sint16 textX = 0, textY = 0;
//
State state = State::NORMAL;
std::string text;
};
#endif
+43
View File
@@ -0,0 +1,43 @@
#config
INCLUDES+=. .. ../graphics
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
+139
View File
@@ -0,0 +1,139 @@
/* 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 "menu_bar.hpp"
#include <stdexcept>
#include <sstream>
void MenuBar::DrawTo(SDL_Surface* const dest) {
for (auto& i : entries) {
i.DrawTo(dest);
}
}
void MenuBar::MouseMotion(SDL_MouseMotionEvent const& motion) {
for (auto& i : entries) {
i.MouseMotion(motion);
}
}
void MenuBar::MouseButtonDown(SDL_MouseButtonEvent const& button) {
for (auto& i : entries) {
i.MouseButtonDown(button);
}
}
void MenuBar::MouseButtonUp(SDL_MouseButtonEvent const& button, int* entry, int* butt) {
*entry = *butt = -1;
int ret = -1;
for (auto& i : entries) {
ret = i.MouseButtonUp(button);
if (ret != -1) {
*entry = (&i - entries.data());
*butt = ret;
}
}
}
void MenuBar::SetEntries(std::vector<std::vector<std::string>> info) {
if (!image || !font) {
throw(std::runtime_error("Surfaces not loaded into the menu bar"));
}
entries.clear();
for (int i = 0; i < info.size(); i++) {
//create the entry & the main button
entries.push_back(MenuBarEntry());
entries[i].mainButton.SetImage(image);
entries[i].mainButton.SetFont(font);
entries[i].mainButton.SetText(info[i][0]);
entries[i].mainButton.SetX(i * image->GetClipW());
entries[i].mainButton.SetY(0);
for (int j = 0; j < info[i].size()-1; j++) {
//create each drop button in this entry
entries[i].dropButtons.push_back(Button());
entries[i].dropButtons[j].SetImage(image);
entries[i].dropButtons[j].SetFont(font);
entries[i].dropButtons[j].SetText(info[i][j+1]);
entries[i].dropButtons[j].SetX(i * image->GetClipW());
entries[i].dropButtons[j].SetY((j+1) * image->GetClipH());
}
}
}
void MenuBar::MenuBarEntry::DrawTo(SDL_Surface* const dest) {
//only draw the dropButtons in the user has this menu open
mainButton.DrawTo(dest);
if (!open) {
return;
}
for (auto& i : dropButtons) {
i.DrawTo(dest);
}
}
void MenuBar::MenuBarEntry::MouseMotion(SDL_MouseMotionEvent const& motion) {
//open the menu
bool o = mainButton.MouseMotion(motion) == Button::State::PRESSED;
if (!(open |= o)) {
return;
}
for (auto& i : dropButtons) {
//dragging down the menu
o |= i.MouseMotion(motion) == Button::State::PRESSED;
}
open = o;
}
void MenuBar::MenuBarEntry::MouseButtonDown(SDL_MouseButtonEvent const& button) {
//open the menu
if (!(open = mainButton.MouseButtonDown(button) == Button::State::PRESSED)) {
return;
}
//update the others anyway
for (auto& i : dropButtons) {
i.MouseButtonDown(button);
}
}
int MenuBar::MenuBarEntry::MouseButtonUp(SDL_MouseButtonEvent const& button) {
int ret = -1;
mainButton.MouseButtonUp(button);
for (auto& i : dropButtons) {
//the user just released this button
if (i.GetState() != i.MouseButtonUp(button) && i.GetState() == Button::State::HOVER && open) {
//get this button's index
ret = (&i - dropButtons.data());
}
}
open = false;
return ret;
}
+91
View File
@@ -0,0 +1,91 @@
/* 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 MENUBAR_HPP_
#define MENUBAR_HPP_
#include "image.hpp"
#include "raster_font.hpp"
#include "button.hpp"
#include <string>
#include <vector>
/* I've redesigned this so that the contents of the menu bar can't change during run time.
* This is more restrictive but I'm focusing on getting this working first.
* The Image and Font pointers must be set before the text data is entered.
*
* This class needs a rewrite.
*/
class MenuBar {
public:
MenuBar() = default;
~MenuBar() = default;
//yet another draw function
void DrawTo(SDL_Surface* const dest);
//user inputs
void MouseMotion(SDL_MouseMotionEvent const&);
void MouseButtonDown(SDL_MouseButtonEvent const&);
void MouseButtonUp(SDL_MouseButtonEvent const&, int* entry, int* button);
//manage the entries & buttons
void SetEntries(std::vector<std::vector<std::string>> info);
void ClearEntries() { entries.clear(); }
//Accessors and mutators
Image* SetImage(Image* const ptr) { return image = ptr; }
Image* GetImage() { return image; }
RasterFont* SetFont(RasterFont* const ptr) { return font = ptr; }
RasterFont* GetFont() { return font; }
private:
class MenuBarEntry;
std::vector<MenuBarEntry> entries;
Image* image = nullptr;
RasterFont* font = nullptr;
};
class MenuBar::MenuBarEntry {
public:
MenuBarEntry() = default;
~MenuBarEntry() = default;
void DrawTo(SDL_Surface* const dest);
void MouseMotion(SDL_MouseMotionEvent const&);
void MouseButtonDown(SDL_MouseButtonEvent const&);
int MouseButtonUp(SDL_MouseButtonEvent const&);
private:
Button mainButton;
std::vector<Button> dropButtons;
bool open = false;
friend class MenuBar;
};
#endif
+60
View File
@@ -0,0 +1,60 @@
/* 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 "raster_font.hpp"
#include <stdexcept>
/* It might be more efficient to render to a different surface (like an Image)
* rather than calling this function with all of it's '%' and '/'.
*/
void RasterFont::DrawStringTo(std::string s, SDL_Surface* const dest, Sint16 x, Sint16 y) {
if (!image.GetSurface()) {
throw(std::runtime_error("RasterFont not loaded"));
}
const Uint16 w = image.GetClipW();
const Uint16 h = image.GetClipH();
for (int i = 0; i < s.size(); i++) {
image.SetClipX(s[i] % 16 * w);
image.SetClipY(s[i] / 16 * h);
image.DrawTo(dest, x + i * w, y);
}
}
/* Note: This class can only take a raster font with 16*16 characters, and the
* indevidual characters must have the same dimensions. Overall this class is too
* restrictive; I suggest using a 3rd party library.
*/
SDL_Surface* RasterFont::LoadSurface(std::string fname) {
image.LoadSurface(fname);
image.SetClipW(image.GetSurface()->w/16);
image.SetClipH(image.GetSurface()->h/16);
return image.GetSurface();
}
SDL_Surface* RasterFont::SetSurface(SDL_Surface* p) {
image.SetSurface(p);
image.SetClipW(image.GetSurface()->w/16);
image.SetClipH(image.GetSurface()->h/16);
return image.GetSurface();
}
+54
View File
@@ -0,0 +1,54 @@
/* 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 RASTERFONT_HPP_
#define RASTERFONT_HPP_
#include "image.hpp"
class RasterFont {
public:
RasterFont() = default;
RasterFont(RasterFont const& rhs) { *this = rhs; }
RasterFont(RasterFont&& rhs) { *this = std::move(rhs); }
RasterFont(std::string fname) { LoadSurface(fname); }
RasterFont(SDL_Surface* p) { SetSurface(p); }
~RasterFont() = default;
RasterFont& operator=(RasterFont const& rhs) { image = rhs.image; }
RasterFont& operator=(RasterFont&& rhs) { image = std::move(rhs.image); }
void DrawStringTo(std::string, SDL_Surface* const, Sint16 x, Sint16 y);
//Accessors and Mutators
SDL_Surface* LoadSurface(std::string);
SDL_Surface* SetSurface(SDL_Surface*);
SDL_Surface* GetSurface() const { return image.GetSurface(); }
void FreeSurface() { image.FreeSurface(); }
Uint16 GetCharW() const { return image.GetClipW(); }
Uint16 GetCharH() const { return image.GetClipH(); }
private:
Image image;
};
#endif
+59
View File
@@ -0,0 +1,59 @@
/* 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 "utility.hpp"
#include <algorithm>
int snapToBase(int base, int x) {
//snap to a grid
if (x < 0) {
x++;
return x / base * base - base;
}
return x / base * base;
}
std::string truncatePath(std::string pathname) {
return std::string(
std::find_if(
pathname.rbegin(),
pathname.rend(),
[](char ch) -> bool {
//windows only
return ch == '/' || ch == '\\';
// //unix only
// return ch == '/';
}).base(),
pathname.end());
}
std::string to_string_custom(int i) {
char buffer[20];
snprintf(buffer, 20, "%d", i);
return std::string(buffer);
}
int to_integer_custom(std::string s) {
int ret = 0;
sscanf(s.c_str(), "%d", &ret);
return ret;
}
+48
View File
@@ -0,0 +1,48 @@
/* 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 UTILITY_HPP_
#define UTILITY_HPP_
#include <string>
int snapToBase(int base, int x);
std::string truncatePath(std::string pathname);
//fixing known bugs in g++
std::string to_string_custom(int i);
int to_integer_custom(std::string);
//wow
template<typename ContainerT, typename PredicateT>
void erase_if(ContainerT& items, const PredicateT& predicate) {
for(auto it = items.begin(); it != items.end(); /* empty */) {
if(predicate(*it)) {
it = items.erase(it);
}
else {
++it;
}
}
};
#endif
+118
View File
@@ -0,0 +1,118 @@
/* 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 VECTOR2_HPP_
#define VECTOR2_HPP_
#include <type_traits>
#include <stdexcept>
#include <cmath>
class Vector2 {
public:
double x, y;
Vector2() = default;
Vector2(double i, double j): x(i), y(j) {};
~Vector2() = default;
Vector2& operator=(Vector2 const&) = default;
double Length() const {
return sqrt(x*x+y*y);
}
double SquaredLength() const {
return x*x+y*y;
}
double operator[](size_t i) {
if (i >= 2)
throw(std::domain_error("Out of range"));
return *(&x+i);
}
//Arithmetic operators
Vector2 operator+(Vector2 v) const {
Vector2 ret;
ret.x = x + v.x;
ret.y = y + v.y;
return ret;
}
Vector2 operator-(Vector2 v) const {
Vector2 ret;
ret.x = x - v.x;
ret.y = y - v.y;
return ret;
}
Vector2 operator*(Vector2 v) const {
Vector2 ret;
ret.x = x * v.x;
ret.y = y * v.y;
return ret;
}
Vector2 operator*(double d) const {
Vector2 ret;
ret.x = x * d;
ret.y = y * d;
return ret;
}
Vector2 operator/(Vector2 v) {
if (!v.x || !v.y)
throw(std::domain_error("Divide by zero"));
Vector2 ret;
ret.x = x / v.x;
ret.y = y / v.y;
return ret;
}
Vector2 operator/(double d) {
if (!d)
throw(std::domain_error("Divide by zero"));
Vector2 ret;
ret.x = x / d;
ret.y = y / d;
return ret;
}
bool operator==(Vector2 v) { return (x == v.x && y == v.y); }
bool operator!=(Vector2 v) { return (x != v.x || y != v.y); }
//member templates (curry the above operators)
template<typename T> Vector2 operator+=(T t) { return *this = *this + t; }
template<typename T> Vector2 operator-=(T t) { return *this = *this - t; }
template<typename T> Vector2 operator*=(T t) { return *this = *this * t; }
template<typename T> Vector2 operator/=(T t) { return *this = *this / t; }
template<typename T> bool operator==(T t) { return (x == t && y == t); }
template<typename T> bool operator!=(T t) { return (x != t || y != t); }
};
//non-member templates (flip the order)
template<typename T> Vector2 operator+(T t, Vector2 v) { return v + t; }
template<typename T> Vector2 operator-(T t, Vector2 v) { return v - t; }
template<typename T> Vector2 operator*(T t, Vector2 v) { return v * t; }
template<typename T> Vector2 operator/(T t, Vector2 v) { return v / t; }
template<typename T> bool operator==(T t, Vector2 v) { return v == t; }
template<typename T> bool operator!=(T t, Vector2 v) { return v != t; }
//This is explicitly a POD
static_assert(std::is_pod<Vector2>::value, "Vector2 is not a POD");
#endif
-84
View File
@@ -1,84 +0,0 @@
The Game Map
This section outlines the games map system. This system utilizes pagination to create a theoretically infinite game map, as well as supporting multiple tilesets in the same map. The goal of this design is to create a system with as much flexibility as possible, and simply enforcing a more rigid approach higher in the tool chain.
Tile
The Tile class is the basic unit of the map system, and is explicitly a POD (plain old data) structure. A tile has these members:
X Position
Y Position
Depth
Width
Height
Tile Index
The tiles X and Y positions are relative to their container regions location. A tiles depth allows multiple tiles to be drawn at the same location, and in the correct order; tiles with lower depths (including below zero) are drawn first. If a new tile has the same X position, Y position and depth as an existing tile, the old tile is overwritten.
The width and height members indicate the graphical size of the tile (not actually used when drawing), while the tile index is the specific tile for the sheet manager to draw. A negative value here is considered an error message.
Region
The region class has these members:
X Position
Y Position
Width
Height
Tile Container
Each region in a certain map must have the same width and height, and its X and Y positions must be multiples of those width and height values, respectfully. The outcome of this restriction is a theoretically infinite grid of region objects.
Each region holds a set of tiles corresponding to the regions bounds. The tiles X and Y positions are relative to the regions, so moving the region will move the tiles as well. A region object is created or loaded when a tile is place in its bounds; similarly, if a region has no tiles it should be deleted or removed from memory.
The exact width and height of a region has no significant impact, other than loading or transmission costs. The width and height of a map can be adjusted as needed.
Region Pager
The region pager class has these members:
Region Width
Region Height
On New Callback
On Delete Callback
Region Container
The Region Pager class holds a series of region objects, as well as creating and deleting them as needed. Every region theoretically exists at any time, so if a non-existent region object is requested, it is created and then returned. This class also has the Prune() method, which removes all regions out of bounds from memory, and the DrawTo method, which takes (among other things) the sheet manager for the map.
The width and height members must be set before the pager is used, and must not be changed while it still has regions loaded. These are used to create region objects as needed.
Each pager can also have two different callbacks set: “on new” and “on delete”. If either of these are set (that is, not null) then each region objects address is passed to these after it is created or before it is destroyed, respectfully. The callbacks are intended to be used for domain specific processes, such as loading or saving data, or even requesting data from a remote server.
Tile Sheet
A tileset is a series of tile graphics stored in a single file. The tile sheet class loads a tile set into memory, and provides utilities for drawing them to the screen. The tile sheet class has these members:
Image
X Count
Y Count
Total Count
Begin
End
The Image class is utilized heavily here by storing the graphical data and the tile size. Any file loaded into a sheet object must have all tile images arranged in a grid pattern, and they must all have the same width and height. The width and height must be provided when the file is loaded.
The X and Y counts are the number of tiles along the X and Y axis of the sheets image, and the total count is the number of tiles in the whole sheet (which is equal to the product of the X and Y counts).
Begin is the index of the first tile on the sheet (default is zero), and end is the index after the last tile (defaults to the value of total count). These indicate the range of the tiles, and are mostly used by the sheet manager. They are also used by the InRange() method, which checks to see if a certain tile is in that sheet.
Tile Sheet Manager
This class has these members:
Tile Sheet Container
Range End
This class is a wrapper around a key-value container, using strings as the keys. Given a specific tile index, this class will draw the correct tile from the loaded sheets, or it throws an error.
Also, this class keeps track of the end of the sheets ranges.
TODO
Map File Format
TODO
-3
View File
@@ -1,3 +0,0 @@
This particular refactoring stage was absolute hell, mostly because I was wrestling with a severe bout of depression too. So, I've added the diffs, and a scary screenshot of the git console.
There are three diff files because server/server_application.cpp was split into two files: server/server_internals.cpp and server/server_connections.cpp, each with it's own diff.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because it is too large Load Diff
@@ -1,394 +0,0 @@
diff --git a/server/server_connections.cpp b/server/server_connections.cpp
index 1a96d5b..2f35566 100644
--- a/server/server_connections.cpp
+++ b/server/server_connections.cpp
@@ -21,212 +21,106 @@
*/
#include "server_application.hpp"
-#include "utility.hpp"
-
#include <stdexcept>
#include <iostream>
-#include <string>
-
-//-------------------------
-//Define the public members
-//-------------------------
-
-void ServerApplication::Init(int argc, char** argv) {
- //NOTE: I might need to rearrange the init process so that lua & SQL can interact with the map system as needed.
- std::cout << "Beginning startup" << std::endl;
-
- //initial setup
- ClientEntry::uidCounter = 0;
- PlayerEntry::uidCounter = 0;
- config.Load("rsc\\config.cfg");
-
- //Init SDL
- if (SDL_Init(0)) {
- throw(std::runtime_error("Failed to initialize SDL"));
- }
- std::cout << "Initialized SDL" << std::endl;
-
- //Init SDL_net
- if (SDLNet_Init()) {
- throw(std::runtime_error("Failed to initialize SDL_net"));
- }
- network.Open(config.Int("server.port"), PACKET_BUFFER_SIZE);
- std::cout << "Initialized SDL_net" << std::endl;
-
- //Init SQL
- int ret = sqlite3_open_v2(config["server.dbname"].c_str(), &database, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, nullptr);
- if (ret != SQLITE_OK || !database) {
- throw(std::runtime_error(std::string() + "Failed to initialize SQL: " + sqlite3_errmsg(database) ));
- }
- std::cout << "Initialized SQL" << std::endl;
-
- //setup the database
- if (runSQLScript(database, config["dir.scripts"] + "setup_server.sql")) {
- throw(std::runtime_error("Failed to initialize SQL's setup script"));
- }
- std::cout << "Initialized SQL's setup script" << std::endl;
-
- //lua
- luaState = luaL_newstate();
- if (!luaState) {
- throw(std::runtime_error("Failed to initialize lua"));
- }
- luaL_openlibs(luaState);
- std::cout << "Initialized lua" << std::endl;
-
- //run the startup script
- if (luaL_dofile(luaState, (config["dir.scripts"] + "setup_server.lua").c_str())) {
- throw(std::runtime_error(std::string() + "Failed to initialize lua's setup script: " + lua_tostring(luaState, -1) ));
- }
- std::cout << "Initialized lua's setup script" << std::endl;
-
- //setup the map object
- regionPager.GetAllocator()->SetLuaState(luaState);
- regionPager.GetFormat()->SetLuaState(luaState);
- //TODO: config parameter
- regionPager.GetFormat()->SetSaveDir("save/mapname/");
-
- std::cout << "Initialized the map system" << std::endl;
- std::cout << "\tsizeof(SerialPacket): " << sizeof(SerialPacket) << std::endl;
- std::cout << "\tPACKET_BUFFER_SIZE: " << PACKET_BUFFER_SIZE << std::endl;
-
- //finalize the startup
- std::cout << "Startup completed successfully" << std::endl;
-
- //debugging
- //
-}
-
-void ServerApplication::Proc() {
- SerialPacket packet;
- while(running) {
- //suck in the waiting packets & process them
- 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);
- }
- //give the computer a break
- SDL_Delay(10);
- }
-}
-
-void ServerApplication::Quit() {
- std::cout << "Shutting down" << std::endl;
- //empty the members
- regionPager.UnloadAll();
-
- //APIs
- lua_close(luaState);
- sqlite3_close_v2(database);
- network.Close();
- SDLNet_Quit();
- SDL_Quit();
- std::cout << "Shutdown finished" << std::endl;
-}
-
-//-------------------------
-//Define the uber switch
-//-------------------------
-
-void ServerApplication::HandlePacket(SerialPacket packet) {
- switch(packet.meta.type) {
- case SerialPacket::Type::BROADCAST_REQUEST:
- HandleBroadcastRequest(packet);
- break;
- case SerialPacket::Type::JOIN_REQUEST:
- HandleJoinRequest(packet);
- break;
- case SerialPacket::Type::DISCONNECT:
- HandleDisconnect(packet);
- break;
- case SerialPacket::Type::SYNCHRONIZE:
- HandleSynchronize(packet);
- break;
- case SerialPacket::Type::SHUTDOWN:
- HandleShutdown(packet);
- break;
- case SerialPacket::Type::PLAYER_NEW:
- HandlePlayerNew(packet);
- break;
- case SerialPacket::Type::PLAYER_DELETE:
- HandlePlayerDelete(packet);
- break;
- case SerialPacket::Type::PLAYER_UPDATE:
- HandlePlayerUpdate(packet);
- break;
- case SerialPacket::Type::REGION_REQUEST:
- HandleRegionRequest(packet);
- break;
- //handle errors
- default:
- throw(std::runtime_error("Unknown SerialPacket::Type encountered"));
- break;
- }
-}
//-------------------------
//Handle various network input
//-------------------------
void ServerApplication::HandleBroadcastRequest(SerialPacket packet) {
- //send back the server's metadata
+ //pack the server's data
packet.meta.type = SerialPacket::Type::BROADCAST_RESPONSE;
-
- //pack the data
+ packet.serverInfo.networkVersion = NETWORK_VERSION;
snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str());
packet.serverInfo.playerCount = playerMap.size();
- packet.serverInfo.regionWidth = REGION_WIDTH;
- packet.serverInfo.regionHeight = REGION_HEIGHT;
- packet.serverInfo.regionDepth = REGION_DEPTH;
- //send the data
+ //bounce this packet
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
}
void ServerApplication::HandleJoinRequest(SerialPacket packet) {
- //register the new client
+ //create the new client
ClientEntry newClient;
newClient.address = packet.meta.srcAddress;
- clientMap[ClientEntry::uidCounter] = newClient;
- //send the client their index
- char buffer[PACKET_BUFFER_SIZE];
+ //TODO: move this into the player management code
+ //create the new player
+ PlayerEntry newPlayer;
+ newPlayer.clientIndex = ClientEntry::uidCounter;
+ newPlayer.player = packet.clientInfo.player;
+ newPlayer.handle = packet.clientInfo.handle;
+ newPlayer.avatar = packet.clientInfo.avatar;
+
+ //send the client their info
packet.meta.type = SerialPacket::Type::JOIN_RESPONSE;
- packet.clientInfo.index = ClientEntry::uidCounter;
- serialize(&packet, buffer);
+ packet.clientInfo.clientIndex = ClientEntry::uidCounter;
+ packet.clientInfo.playerIndex = PlayerEntry::uidCounter;
//bounce this packet
+ char buffer[PACKET_BUFFER_SIZE];
+ serialize(&packet, buffer);
network.Send(&newClient.address, buffer, PACKET_BUFFER_SIZE);
+ //send the new player to all clients
+ packet.meta.type = SerialPacket::Type::PLAYER_NEW;
+ packet.playerInfo.playerIndex = PlayerEntry::uidCounter;
+ strncpy(packet.playerInfo.handle, newPlayer.handle.c_str(), PACKET_STRING_SIZE);
+ strncpy(packet.playerInfo.avatar, newPlayer.avatar.c_str(), PACKET_STRING_SIZE);
+ packet.playerInfo.position = newPlayer.position;
+ packet.playerInfo.motion = newPlayer.motion;
+ PumpPacket(packet);
+
//finished this routine
+ clientMap[ClientEntry::uidCounter] = newClient;
+ playerMap[PlayerEntry::uidCounter] = newPlayer;
ClientEntry::uidCounter++;
+ PlayerEntry::uidCounter++;
std::cout << "Connect, total: " << clientMap.size() << std::endl;
}
+void ServerApplication::HandleSynchronize(SerialPacket packet) {
+ //TODO: compensate for large distances
+
+ //send all the server's data to this client
+ SerialPacket newPacket;
+ char buffer[PACKET_BUFFER_SIZE];
+
+ //players
+ newPacket.meta.type = SerialPacket::Type::PLAYER_UPDATE;
+ for (auto& it : playerMap) {
+ //TODO: update this for the expanded PlayerEntry structure
+ newPacket.playerInfo.playerIndex = it.first;
+ snprintf(newPacket.playerInfo.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str());
+ snprintf(newPacket.playerInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str());
+ newPacket.playerInfo.mapIndex = it.second.mapIndex;
+ newPacket.playerInfo.position = it.second.position;
+ newPacket.playerInfo.motion = it.second.motion;
+ serialize(&newPacket, buffer);
+ network.Send(&clientMap[packet.clientInfo.clientIndex].address, buffer, PACKET_BUFFER_SIZE);
+ }
+}
+
void ServerApplication::HandleDisconnect(SerialPacket packet) {
//TODO: authenticate who is disconnecting/kicking
+ //TODO: define the difference between unloading and deletng a player
//disconnect the specified client
char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
- network.Send(&clientMap[packet.clientInfo.index].address, buffer, PACKET_BUFFER_SIZE);
- clientMap.erase(packet.clientInfo.index);
+ network.Send(&clientMap[packet.clientInfo.clientIndex].address, buffer, PACKET_BUFFER_SIZE);
+ clientMap.erase(packet.clientInfo.clientIndex);
//prep the delete packet
SerialPacket delPacket;
delPacket.meta.type = SerialPacket::Type::PLAYER_DELETE;
- //TODO: can this use DeletePlayer() instead?
//delete server and client side players
- erase_if(playerMap, [&](std::pair<unsigned int, PlayerEntry> it) -> bool {
+ erase_if(playerMap, [&](std::pair<int, PlayerEntry> it) -> bool {
//find the internal players to delete
- if (it.second.clientIndex == packet.clientInfo.index) {
+ if (it.second.clientIndex == packet.clientInfo.clientIndex) {
//send the delete player command to all clients
delPacket.playerInfo.playerIndex = it.first;
PumpPacket(delPacket);
@@ -243,102 +137,23 @@ void ServerApplication::HandleDisconnect(SerialPacket packet) {
std::cout << "Disconnect, total: " << clientMap.size() << std::endl;
}
-void ServerApplication::HandleSynchronize(SerialPacket packet) {
- //TODO: compensate for large distances
-
- //send all the server's data to this client
- SerialPacket newPacket;
- char buffer[PACKET_BUFFER_SIZE];
-
- //players
- newPacket.meta.type = SerialPacket::Type::PLAYER_UPDATE;
- for (auto& it : playerMap) {
- //TODO: update this for the expanded PlayerEntry structure
- newPacket.playerInfo.playerIndex = it.first;
- snprintf(newPacket.playerInfo.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str());
- snprintf(newPacket.playerInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str());
- newPacket.playerInfo.position = it.second.position;
- newPacket.playerInfo.motion = it.second.motion;
- serialize(&newPacket, buffer);
- network.Send(&clientMap[packet.clientInfo.index].address, buffer, PACKET_BUFFER_SIZE);
- }
-}
-
void ServerApplication::HandleShutdown(SerialPacket packet) {
+ //TODO: authenticate who is shutting the server down
+
//end the server
running = false;
//disconnect all clients
packet.meta.type = SerialPacket::Type::DISCONNECT;
+ packet.clientInfo.clientIndex = -1;
PumpPacket(packet);
//finished this routine
std::cout << "Shutdown signal accepted" << std::endl;
}
-void ServerApplication::HandlePlayerNew(SerialPacket packet) {
- //register the new PlayerEntry
- //NOTE: assigning each field one-by-one so adding or moving a field doesn't break this code
- PlayerEntry newPlayer;
-
- //metadata
- newPlayer.clientIndex = packet.playerInfo.clientIndex;
- newPlayer.handle = packet.playerInfo.handle;
- newPlayer.avatar = packet.playerInfo.avatar;
-
- //position
- newPlayer.mapIndex = 0;
- newPlayer.position = {0,0};
- newPlayer.motion = {0,0};
- newPlayer.bbox = {0, 0, 0, 0};
-
- //TODO: Add the statistic creation code here
-
- //push this player
- playerMap[PlayerEntry::uidCounter] = newPlayer;
-
- //send the client their info
- packet.playerInfo.playerIndex = PlayerEntry::uidCounter;
- packet.playerInfo.position = newPlayer.position;
- packet.playerInfo.motion = newPlayer.motion;
-
- //actually send to everyone
- PumpPacket(packet);
-
- //finish this routine
- PlayerEntry::uidCounter++;
-}
-
-//TODO: differentiate between delete and unload
-void ServerApplication::HandlePlayerDelete(SerialPacket packet) {
- //TODO: authenticate who is deleting this player
- if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) {
- throw(std::runtime_error("Cannot delete a non-existant player"));
- }
-
- //TODO: remove the deleted player from the database?
-
- //prep the delete packet
- SerialPacket delPacket;
- delPacket.meta.type = SerialPacket::Type::PLAYER_DELETE;
-
- //delete the specified playerEntry
- erase_if(playerMap, [&](std::pair<unsigned int, PlayerEntry> it) -> bool {
- //find the specified PlayerEntry
- if (it.first == packet.playerInfo.playerIndex) {
- //send to all
- delPacket.playerInfo.playerIndex = it.first;
- PumpPacket(delPacket);
-
- //delete this player
- return true;
- }
- //skip this player
- return false;
- });
-}
-
void ServerApplication::HandlePlayerUpdate(SerialPacket packet) {
+ //TODO: this should be moved elsewhere
if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) {
throw(std::runtime_error("Cannot update a non-existant player"));
}
@@ -351,9 +166,12 @@ void ServerApplication::HandlePlayerUpdate(SerialPacket packet) {
}
void ServerApplication::HandleRegionRequest(SerialPacket packet) {
- char buffer[PACKET_BUFFER_SIZE];
+ //TODO: this should be moved elsewhere
packet.meta.type = SerialPacket::Type::REGION_CONTENT;
packet.regionInfo.region = regionPager.GetRegion(packet.regionInfo.x, packet.regionInfo.y);
+
+ //send the content
+ char buffer[PACKET_BUFFER_SIZE];
serialize(&packet, buffer);
network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
}
@@ -1,284 +0,0 @@
diff --git a/server/server_internals.cpp b/server/server_internals.cpp
index 1a96d5b..e1a9cb9 100644
--- a/server/server_internals.cpp
+++ b/server/server_internals.cpp
@@ -1,4 +1,4 @@
-/* Copyright: (c) Kayne Ruse 2013, 2014
+/* 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,7 +21,7 @@
*/
#include "server_application.hpp"
-#include "utility.hpp"
+#include "server_utility.hpp"
#include <stdexcept>
#include <iostream>
@@ -36,8 +36,6 @@ void ServerApplication::Init(int argc, char** argv) {
std::cout << "Beginning startup" << std::endl;
//initial setup
- ClientEntry::uidCounter = 0;
- PlayerEntry::uidCounter = 0;
config.Load("rsc\\config.cfg");
//Init SDL
@@ -109,6 +107,8 @@ void ServerApplication::Proc() {
//we need to go deeper
HandlePacket(packet);
}
+ //update the internals
+ //TODO: update the internals i.e. player positions
//give the computer a break
SDL_Delay(10);
}
@@ -116,6 +116,10 @@ void ServerApplication::Proc() {
void ServerApplication::Quit() {
std::cout << "Shutting down" << std::endl;
+
+ //save the server state
+ //TODO: save the existing players
+
//empty the members
regionPager.UnloadAll();
@@ -125,6 +129,7 @@ void ServerApplication::Quit() {
network.Close();
SDLNet_Quit();
SDL_Quit();
+
std::cout << "Shutdown finished" << std::endl;
}
@@ -140,21 +145,15 @@ void ServerApplication::HandlePacket(SerialPacket packet) {
case SerialPacket::Type::JOIN_REQUEST:
HandleJoinRequest(packet);
break;
- case SerialPacket::Type::DISCONNECT:
- HandleDisconnect(packet);
- break;
case SerialPacket::Type::SYNCHRONIZE:
HandleSynchronize(packet);
break;
+ case SerialPacket::Type::DISCONNECT:
+ HandleDisconnect(packet);
+ break;
case SerialPacket::Type::SHUTDOWN:
HandleShutdown(packet);
break;
- case SerialPacket::Type::PLAYER_NEW:
- HandlePlayerNew(packet);
- break;
- case SerialPacket::Type::PLAYER_DELETE:
- HandlePlayerDelete(packet);
- break;
case SerialPacket::Type::PLAYER_UPDATE:
HandlePlayerUpdate(packet);
break;
@@ -167,202 +166,3 @@ void ServerApplication::HandlePacket(SerialPacket packet) {
break;
}
}
-
-//-------------------------
-//Handle various network input
-//-------------------------
-
-void ServerApplication::HandleBroadcastRequest(SerialPacket packet) {
- //send back the server's metadata
- packet.meta.type = SerialPacket::Type::BROADCAST_RESPONSE;
-
- //pack the data
- snprintf(packet.serverInfo.name, PACKET_STRING_SIZE, "%s", config["server.name"].c_str());
- packet.serverInfo.playerCount = playerMap.size();
- packet.serverInfo.regionWidth = REGION_WIDTH;
- packet.serverInfo.regionHeight = REGION_HEIGHT;
- packet.serverInfo.regionDepth = REGION_DEPTH;
-
- //send the data
- char buffer[PACKET_BUFFER_SIZE];
- serialize(&packet, buffer);
- network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
-}
-
-void ServerApplication::HandleJoinRequest(SerialPacket packet) {
- //register the new client
- ClientEntry newClient;
- newClient.address = packet.meta.srcAddress;
- clientMap[ClientEntry::uidCounter] = newClient;
-
- //send the client their index
- char buffer[PACKET_BUFFER_SIZE];
- packet.meta.type = SerialPacket::Type::JOIN_RESPONSE;
- packet.clientInfo.index = ClientEntry::uidCounter;
- serialize(&packet, buffer);
-
- //bounce this packet
- network.Send(&newClient.address, buffer, PACKET_BUFFER_SIZE);
-
- //finished this routine
- ClientEntry::uidCounter++;
- std::cout << "Connect, total: " << clientMap.size() << std::endl;
-}
-
-void ServerApplication::HandleDisconnect(SerialPacket packet) {
- //TODO: authenticate who is disconnecting/kicking
-
- //disconnect the specified client
- char buffer[PACKET_BUFFER_SIZE];
- serialize(&packet, buffer);
- network.Send(&clientMap[packet.clientInfo.index].address, buffer, PACKET_BUFFER_SIZE);
- clientMap.erase(packet.clientInfo.index);
-
- //prep the delete packet
- SerialPacket delPacket;
- delPacket.meta.type = SerialPacket::Type::PLAYER_DELETE;
-
- //TODO: can this use DeletePlayer() instead?
- //delete server and client side players
- erase_if(playerMap, [&](std::pair<unsigned int, PlayerEntry> it) -> bool {
- //find the internal players to delete
- if (it.second.clientIndex == packet.clientInfo.index) {
- //send the delete player command to all clients
- delPacket.playerInfo.playerIndex = it.first;
- PumpPacket(delPacket);
-
- //delete this player object
- return true;
- }
-
- //don't delete this player object
- return false;
- });
-
- //finished this routine
- std::cout << "Disconnect, total: " << clientMap.size() << std::endl;
-}
-
-void ServerApplication::HandleSynchronize(SerialPacket packet) {
- //TODO: compensate for large distances
-
- //send all the server's data to this client
- SerialPacket newPacket;
- char buffer[PACKET_BUFFER_SIZE];
-
- //players
- newPacket.meta.type = SerialPacket::Type::PLAYER_UPDATE;
- for (auto& it : playerMap) {
- //TODO: update this for the expanded PlayerEntry structure
- newPacket.playerInfo.playerIndex = it.first;
- snprintf(newPacket.playerInfo.handle, PACKET_STRING_SIZE, "%s", it.second.handle.c_str());
- snprintf(newPacket.playerInfo.avatar, PACKET_STRING_SIZE, "%s", it.second.avatar.c_str());
- newPacket.playerInfo.position = it.second.position;
- newPacket.playerInfo.motion = it.second.motion;
- serialize(&newPacket, buffer);
- network.Send(&clientMap[packet.clientInfo.index].address, buffer, PACKET_BUFFER_SIZE);
- }
-}
-
-void ServerApplication::HandleShutdown(SerialPacket packet) {
- //end the server
- running = false;
-
- //disconnect all clients
- packet.meta.type = SerialPacket::Type::DISCONNECT;
- PumpPacket(packet);
-
- //finished this routine
- std::cout << "Shutdown signal accepted" << std::endl;
-}
-
-void ServerApplication::HandlePlayerNew(SerialPacket packet) {
- //register the new PlayerEntry
- //NOTE: assigning each field one-by-one so adding or moving a field doesn't break this code
- PlayerEntry newPlayer;
-
- //metadata
- newPlayer.clientIndex = packet.playerInfo.clientIndex;
- newPlayer.handle = packet.playerInfo.handle;
- newPlayer.avatar = packet.playerInfo.avatar;
-
- //position
- newPlayer.mapIndex = 0;
- newPlayer.position = {0,0};
- newPlayer.motion = {0,0};
- newPlayer.bbox = {0, 0, 0, 0};
-
- //TODO: Add the statistic creation code here
-
- //push this player
- playerMap[PlayerEntry::uidCounter] = newPlayer;
-
- //send the client their info
- packet.playerInfo.playerIndex = PlayerEntry::uidCounter;
- packet.playerInfo.position = newPlayer.position;
- packet.playerInfo.motion = newPlayer.motion;
-
- //actually send to everyone
- PumpPacket(packet);
-
- //finish this routine
- PlayerEntry::uidCounter++;
-}
-
-//TODO: differentiate between delete and unload
-void ServerApplication::HandlePlayerDelete(SerialPacket packet) {
- //TODO: authenticate who is deleting this player
- if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) {
- throw(std::runtime_error("Cannot delete a non-existant player"));
- }
-
- //TODO: remove the deleted player from the database?
-
- //prep the delete packet
- SerialPacket delPacket;
- delPacket.meta.type = SerialPacket::Type::PLAYER_DELETE;
-
- //delete the specified playerEntry
- erase_if(playerMap, [&](std::pair<unsigned int, PlayerEntry> it) -> bool {
- //find the specified PlayerEntry
- if (it.first == packet.playerInfo.playerIndex) {
- //send to all
- delPacket.playerInfo.playerIndex = it.first;
- PumpPacket(delPacket);
-
- //delete this player
- return true;
- }
- //skip this player
- return false;
- });
-}
-
-void ServerApplication::HandlePlayerUpdate(SerialPacket packet) {
- if (playerMap.find(packet.playerInfo.playerIndex) == playerMap.end()) {
- throw(std::runtime_error("Cannot update a non-existant player"));
- }
-
- //TODO: the server needs it's own movement system too
- playerMap[packet.playerInfo.playerIndex].position = packet.playerInfo.position;
- playerMap[packet.playerInfo.playerIndex].motion = packet.playerInfo.motion;
-
- PumpPacket(packet);
-}
-
-void ServerApplication::HandleRegionRequest(SerialPacket packet) {
- char buffer[PACKET_BUFFER_SIZE];
- packet.meta.type = SerialPacket::Type::REGION_CONTENT;
- packet.regionInfo.region = regionPager.GetRegion(packet.regionInfo.x, packet.regionInfo.y);
- serialize(&packet, buffer);
- network.Send(&packet.meta.srcAddress, buffer, PACKET_BUFFER_SIZE);
-}
-
-void ServerApplication::PumpPacket(SerialPacket packet) {
- //NOTE: 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, buffer, PACKET_BUFFER_SIZE);
- }
-}
-76
View File
@@ -1,76 +0,0 @@
#include <iostream>
#include <cstring>
using namespace std;
union Foo {
enum class Type {
INT,
FLOAT
}type;
struct {
Type type;
int i;
}i;
struct {
Type type;
float f;
}f;
};
void serialize(Foo* f, void* buffer) {
int len = 0;
memcpy((void*)((int)buffer + len), &f->type, sizeof(Foo::Type));
len += sizeof(Foo::Type);
switch(f->type) {
case Foo::Type::INT:
memcpy((void*)((int)buffer + len), &f->i.i, sizeof(int));
len += sizeof(int);
break;
case Foo::Type::FLOAT:
memcpy((void*)((int)buffer + len), &f->f.f, sizeof(float));
len += sizeof(float);
break;
}
}
void deserialize(Foo* f, void* buffer) {
int len = 0;
memcpy(&f->type, (void*)((int)buffer + len), sizeof(Foo::Type));
len += sizeof(Foo::Type);
switch(f->type) {
case Foo::Type::INT:
memcpy(&f->i.i, (void*)((int)buffer + len), sizeof(int));
len += sizeof(int);
break;
case Foo::Type::FLOAT:
memcpy(&f->f.f, (void*)((int)buffer + len), sizeof(float));
len += sizeof(float);
break;
}
}
int main() {
Foo f;
f.type = Foo::Type::FLOAT;
f.f.f = 3.14;
Foo i;
i.type = Foo::Type::INT;
i.i.i = 42;
char buffer[sizeof(Foo)];
serialize(&f, buffer);
deserialize(&i, buffer);
switch(i.type) {
case Foo::Type::INT:
cout << i.i.i << endl;
break;
case Foo::Type::FLOAT:
cout << i.f.f << endl;
break;
}
return 0;
}
@@ -1,12 +0,0 @@
The palette is extracted from the frog images. It's only meant as areference, and can change later. Hot pink (255, 0, 255) is used to fill the gaps.
[blank], mid highlight, high highlight
low base, mid base, high base
[blank], mid shadow, high shadow
inner cheek
tongue outline, tongue shadow, tongue base
leather shadow, leather base, leather hightlight
wood shadow, wood base, wood highlight
sharp shadow, sharp base, [blank]
dull shadow, dull base, [blank]
frog outline, metal outline, wood outline
Binary file not shown.

Before

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 687 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 838 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 577 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 363 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

@@ -1,7 +0,0 @@
pay attention to each frog's eyes
frogs are green
bog toad is yellow/orange with spots (gradient?)
princess dress is an ugly pink
frog king wears a gold crown and red cape with gold trimmings
the knight's helmet has a purple plume, and it's wearing boxer shorts with loveheart patterns
Binary file not shown.

Before

Width:  |  Height:  |  Size: 974 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 984 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1004 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 506 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Some files were not shown because too many files have changed in this diff Show More