Compare commits

..

69 Commits

Author SHA1 Message Date
Kayne Ruse f82b0a8843 Merge branch 'develop', read more
* moved network_api.*pp
* Added copyright notices to scripts
* Changed SQL table names (including hardcoded usage)
* Added monster tables to the database
* Made updates.sql (unneeded, and deleted)
* Added ForEachMonster() to the room API (incomplete)
* Created class MonsterData (incomplete)
* Created class MonsterManager (incomplete)
* Created MonsterManager API (incomplete)
2015-07-07 12:52:46 +10:00
Kayne Ruse 210bccbe0d Pruned the usage of the incomplete monster system 2015-07-07 12:41:57 +10:00
Kayne Ruse 68429806d1 Merge branch 'master' into develop 2015-05-18 21:29:15 +10:00
Kayne Ruse a8cf0a6947 Updated .gitignore 2015-05-18 21:28:55 +10:00
Kayne Ruse 822d0636cc Merge branch 'master' into develop 2015-05-17 12:38:44 +10:00
Kayne Ruse 164a3e18d9 Fixed formatting 2015-05-17 12:36:43 +10:00
Kayne Ruse 3498b5d154 Merge branch 'ubuntu-build'
Conflicts:
	README.md

After setting up my new PC's build environment, I've made some changes to make
both setups compatible.
2015-05-17 12:33:31 +10:00
Kayne Ruse 96c10da527 Tweaked README.md 2015-05-17 09:48:49 +10:00
Kayne Ruse 3856b3cdd2 DELETE ME: temporary commit 2015-05-17 09:36:37 +10:00
Kayne Ruse 661f6db82c Added the linux release to README.md 2015-05-17 09:28:37 +10:00
Kayne Ruse 99b35483f8 Tenative port for Linux 2015-05-17 09:18:46 +10:00
Kayne Ruse 102ba18b7b Finally wrote the monster manager API 2015-05-08 23:17:35 +10:00
Kayne Ruse 07faf1b96b Moved a file 2015-05-08 22:33:46 +10:00
Kayne Ruse 1d70e271b6 Merge branch 'master' into develop 2015-04-28 11:03:58 +10:00
Kayne Ruse 0bf5ccee4d Spelling correction 2015-04-28 11:03:44 +10:00
Kayne Ruse 35e7d0cf61 Tweaked scripts, added ForEachMonster()
(cherry picked from commit 0cf6a3dceb56a85969e8248e19f9143364b75c68)
2015-04-28 10:25:12 +10:00
Kayne Ruse 27fd810cfd Added a simple database update script, and comment headers
I don't know why it took me this long to add those headers in the first
place.

(cherry picked from commit 3c28b6c3bf75c4bdb42e5ea9d9864efaa855620c)
2015-04-28 10:24:47 +10:00
Kayne Ruse 8903b1e28d Began marking changes for monsters
These changes include storing monsters on shutdown, storing dead
characters and monsters, etc. Also fleshed out the MonsterManager's
internals a bit.

(cherry picked from commit af982710f6de050c09ef503cf2f8e1c9fdd34979)
2015-04-28 10:24:17 +10:00
Kayne Ruse c1ace69e19 Merge branch 'bug-hunting' 2015-04-28 06:04:06 +10:00
Kayne Ruse 5c404c572e Patched bug #45 without resolving it 2015-04-28 06:01:58 +10:00
Kayne Ruse 878d502b8b Looking for the bug 2015-04-27 01:35:14 +10:00
Kayne Ruse 2a1ee4acbf tmp 2015-04-26 03:29:33 +10:00
Kayne Ruse 0e149acc62 Pointless tweak 2015-04-26 03:24:25 +10:00
Kayne Ruse 63e4394583 I can't seem to pinpoint the cause 2015-04-26 03:11:00 +10:00
Kayne Ruse 7aeabf0d14 Hunting a strange networking bug 2015-04-26 02:14:26 +10:00
Kayne Ruse 9d5a668045 Merge branch 'develop', read more
The trigger system has been fully implemented, as well as a few other
tweaks as the occasional thought came to mind.

Multiple rooms are now fully functional, mostly as a way to test the
triggers. Although there are still no real generation algorithms, a
utility for creating door pairs between given rooms is included in the
scripts directory.

Other changes in this merge include:

* Network updates via lua
* Entity types can be determined in lua
* Database columns are now order independant

It should be noted that only two types of userdata will work as far as
entity names are concerned: Characters and Monsters. I tried getting it to
work for all objects passed to lua, but it proved to be too obtuse.

In theory, I could create a teleport puzzle using what I've written here.
That might be a side project, or a way to test saving & loading systems. I
don't see any reason to delay monsters any longer; hopefully, I can get
them going soon too.
2015-03-13 21:28:05 +11:00
Kayne Ruse 0efb541074 Moved the door pair script to it's own file 2015-03-13 21:24:31 +11:00
Kayne Ruse 4ae58550b5 Changed SetRoomIndex() to SetRoom() 2015-03-13 21:05:24 +11:00
Kayne Ruse d82e3a8b79 Triggers now support exclusion lists 2015-03-13 20:43:47 +11:00
Kayne Ruse 954213f1ff Minor tweak to hCharacterMovement() 2015-03-13 19:36:03 +11:00
Kayne Ruse d2bb3575fc Removed initial world query
The world is queried once the client has the player's character.
2015-03-13 19:12:34 +11:00
Kayne Ruse ca6afb72ad Minor comment tweaks 2015-03-11 20:23:52 +11:00
Kayne Ruse 670ab22e96 Using an entity stack for trigger comparisons 2015-03-11 18:22:09 +11:00
Kayne Ruse 4d71d4cc40 Room transitions are working smoothly, read more
Although the room transitions are working fairly well, it is still heavy
handed, and a number of optimizations can be done. On the whole, this
needs a review.
2015-03-09 23:26:37 +11:00
Kayne Ruse 81b3769188 Implemented networked room chainging function 2015-03-09 21:28:28 +11:00
Kayne Ruse c3c6d42a80 Characters moving via scripts are pushed & popped from the rooms
The delete & create messages still need to be implemented.
2015-03-09 10:27:50 +11:00
Kayne Ruse 3d8ee25ae7 AccountManager's SQL is order-independant 2015-03-09 09:34:38 +11:00
Kayne Ruse decc77e21c Implemented entity.GetType() in lua
This will only work for userdata decented from the Entity base class.
Using something else results in undefined behavior.
2015-03-09 09:04:12 +11:00
Kayne Ruse 501b1e9814 Reduced script verbosity to a degree 2015-03-08 20:08:12 +11:00
Kayne Ruse 01502372c9 Correcting a bug with unimplemented MonsterManager 2015-03-07 15:09:33 +11:00
Kayne Ruse a8c309ec9d Minor comment tweaks 2015-03-06 00:13:12 +11:00
Kayne Ruse 41d6314beb Triggers have a basic response to character collision
I've hacked the trigger system to create a really basic teleport pad,
using the dirt tile as an indicator. This behaviour is not coded into the
engine, but is in fact scripted in lua.

This commit is messy, due to lack of sleep.
2015-03-04 06:16:12 +11:00
Kayne Ruse 74ed93ddc7 Character bounds are stored in the server database
This allows for customization of bounding boxes, as well as highlighting
aspects needed when adding new fields to the characters.
2015-03-04 04:06:16 +11:00
Kayne Ruse 18a7143926 Full trigger creation 2015-03-04 02:21:56 +11:00
Kayne Ruse bd68af5875 Added character iteration to the rooms 2015-03-02 04:26:34 +11:00
Kayne Ruse b8806cc209 Implemented CharacterManager::ForEach() 2015-03-02 02:41:37 +11:00
Kayne Ruse edcb6f05ce Implemented trigger creation & deletion via lua
Triggers now have handles for simple understanding, but there's nothing
preventing multiple triggers from sharing the same name.
2015-03-02 01:00:58 +11:00
Kayne Ruse cb63c9b07c Minor comment tweaks 2015-02-27 05:43:20 +11:00
Kayne Ruse a00ddb3142 Updated trigger names in the server 2015-02-27 05:33:47 +11:00
Kayne Ruse 3431d323e5 Renamed the waypoint system to trogger system 2015-02-27 05:21:40 +11:00
Kayne Ruse 84c4dd0497 Placeholder monster spawn function in map maker 2015-02-27 04:28:28 +11:00
Kayne Ruse 3e6a05307e Minor TODO tweaks 2015-02-27 03:36:47 +11:00
Kayne Ruse c45bda645b Switched TODO: empty to TODO: *function name* 2015-02-27 03:27:37 +11:00
Kayne Ruse 1210d2d24f Minor comment tweaks 2015-02-27 03:06:29 +11:00
Kayne Ruse 894b53e760 Merge branch 'develop' 2015-02-27 02:45:19 +11:00
Kayne Ruse 4630b7e403 PumpCharacterUpdate() works from lua to client, read more
There was a bug in the entity API, where getMotion() was pushing the
origin instead of the motion. This has been corrected. Since this is an
important bug, and because the features for this leg is finished, I'll
merge this to master.
2015-02-27 02:39:27 +11:00
Kayne Ruse 067bf40be7 Moved some utility methods out of the "god class"
These methods are are now functions in server_utilities.hpp
2015-02-27 01:20:05 +11:00
Kayne Ruse d8045ae339 Minor comment tweaks 2015-02-25 21:16:03 +11:00
Kayne Ruse eff23352aa Merge branch 'develop'
Changes:

* "ticking" rooms
* character API
* bare-bones character manager API
* bounds checking in serial_utility.cpp

I have an idea for swapping the existing utility/singleton classes for
namesapces, as I think this would reduce the verbosity that I have to deal
with.
2015-02-23 01:54:46 +11:00
Kayne Ruse 46df0f17b7 Changed a massive swap statement for bounds checks
Instead of using a massive block of case statements in serial_utility.cpp,
I've added FORMAT_* tags to SerialPacketType as a way to destinguish
between type values, at least internally. I can't believe I missed this
for so long.

I've also added a placeholder for the network API, as I was working on
that when I ran into this problem.
2015-02-21 23:46:50 +11:00
Kayne Ruse ddedc06e47 Implemented bare-bones character system API
I need to devise a way to update the clients about changes to their
characters directly from the lua scripts. This isn't too important per se,
but the pattern will be important for the monster and trigger systems.
2015-02-21 21:46:22 +11:00
Kayne Ruse 6a999a8a72 Room API hooks are updated automatically 2015-02-19 03:40:20 +11:00
Kayne Ruse 8a97cb8c2c Checked the tick in Hertz 2015-02-18 00:21:38 +11:00
Kayne Ruse e011e6bdc5 The rooms are ticking 2015-02-18 00:07:38 +11:00
Kayne Ruse a106134dd1 Added hooks to the room system 2015-02-17 23:37:11 +11:00
Kayne Ruse a538cf73d5 Merge branch 'ticks' into develop 2015-02-17 22:23:36 +11:00
Kayne Ruse b273b4c04a Added character API 2015-02-17 22:10:07 +11:00
Kayne Ruse 248d142c2b Reconsidering the server's structure 2015-02-17 21:03:30 +11:00
Kayne Ruse 2cc7260552 Server can handle multiple dropped clients at once 2015-02-17 20:48:03 +11:00
111 changed files with 2152 additions and 1175 deletions
+3
View File
@@ -9,6 +9,9 @@
Release/ Release/
Debug/ Debug/
Out/ Out/
release/
debug/
out/
#Project generated files #Project generated files
*.db *.db
+7 -5
View File
@@ -1,12 +1,13 @@
## Outline ## Outline
Tortuga is a 2D multiplayer JRPG featuring permadeath, with an emphasis on multiplayer cooperation, exploration and customization. The game runs on customizable public and private servers. Tortuga is a 2D MMORPG featuring permadeath, with an emphasis on multiplayer cooperation, exploration and customization. The game runs on customizable public and private servers.
This game is inspired by classic 2D RPGs (Final Fantasy, The Legend of Zelda), as well as more modern sandboxes amd MMOs (Minecraft, EVE Online). This project is currently independently created and funded, with the goal of creating a game that will engage the players and inspire a large community. This game is inspired by classic 2D RPGs (Final Fantasy, The Legend of Zelda), as well as more modern sandboxes and MMOs (Minecraft, EVE Online). This project is currently independently created and funded, with the goal of creating a game that will engage the players and inspire a large community.
## Releases ## Releases
The most recent stable build for Windows can be found [here](https://dl.dropboxusercontent.com/u/46669050/Tortuga.rar). * The most recent stable build for Windows can be found [here](https://dl.dropboxusercontent.com/u/46669050/Tortuga-win.rar).
* The most recent stable build for Linux can be found [here](https://dl.dropboxusercontent.com/u/46669050/Tortuga-linux.tar).
## Documentation ## Documentation
@@ -16,13 +17,14 @@ The most recent stable build for Windows can be found [here](https://dl.dropboxu
## External Dependencies ## External Dependencies
* [SDL 1.2](http://www.libsdl.org/) - Simple DirectMedia Layer API * [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 * [SDL_net 2.0](http://www.libsdl.org/projects/SDL_net/) - SDL's networking extension
* [lua 5.2](http://www.lua.org/) - The lua programming language * [lua 5.2](http://www.lua.org/) - The lua programming language
* [SQLite3](http://www.sqlite.org/) - A lightweight SQL database engine * [SQLite3](http://www.sqlite.org/) - A lightweight SQL database engine
## Tools ## Tools
* [WinRAR](http://www.rarlab.com/) - The best compression tool available IMO; only needed for distribution * [WinRAR](http://www.rarlab.com/) - The best compression tool available IMO; only needed for Windows distribution
* [Dropbox](https://www.dropbox.com/) - For hosting and distribution
## Copyright ## Copyright
+5 -1
View File
@@ -27,6 +27,7 @@
#include <stdexcept> #include <stdexcept>
#include <chrono> #include <chrono>
#include <iostream> #include <iostream>
#include <sstream>
//------------------------- //-------------------------
//Scene headers //Scene headers
@@ -57,7 +58,9 @@ void ClientApplication::Init(int argc, char* argv[]) {
//initialize SDL //initialize SDL
if (SDL_Init(SDL_INIT_VIDEO)) { if (SDL_Init(SDL_INIT_VIDEO)) {
throw(std::runtime_error("Failed to initialize SDL")); std::ostringstream os;
os << "Failed to initialize SDL: " << SDL_GetError();
throw(std::runtime_error(os.str()));
} }
std::cout << "Initialized SDL" << std::endl; std::cout << "Initialized SDL" << std::endl;
@@ -169,6 +172,7 @@ void ClientApplication::Quit() {
//------------------------- //-------------------------
void ClientApplication::LoadScene(SceneList sceneIndex) { void ClientApplication::LoadScene(SceneList sceneIndex) {
//BUG: #16 Resources are being reloaded between scenes
UnloadScene(); UnloadScene();
switch(sceneIndex) { switch(sceneIndex) {
//add scene creation calls here //add scene creation calls here
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
+1 -1
View File
@@ -24,7 +24,7 @@
#include "config_utility.hpp" #include "config_utility.hpp"
void BaseMonster::CorrectSprite() { void BaseMonster::CorrectSprite() {
//TODO: (9) empty //TODO: (9) BaseMonster::CorrectSprite()
} }
std::string BaseMonster::SetHandle(std::string s) { std::string BaseMonster::SetHandle(std::string s) {
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
+1
View File
@@ -96,6 +96,7 @@ protected:
void UpdateMap(); void UpdateMap();
//character management //character management
void hCharacterUpdate(CharacterPacket* const);
void hCharacterCreate(CharacterPacket* const); void hCharacterCreate(CharacterPacket* const);
void hCharacterDelete(CharacterPacket* const); void hCharacterDelete(CharacterPacket* const);
void hQueryCharacterExists(CharacterPacket* const); void hQueryCharacterExists(CharacterPacket* const);
+47 -14
View File
@@ -23,6 +23,7 @@
#include "channels.hpp" #include "channels.hpp"
#include <cstring>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
@@ -35,6 +36,24 @@
//DOCS: new characters will result in create messages //DOCS: new characters will result in create messages
//DOCS: this client's character will exist in both (skipped) //DOCS: this client's character will exist in both (skipped)
void World::hCharacterUpdate(CharacterPacket* const argPacket) {
//TODO: (1) Authentication
//NOTE: applies to the local character too
//check that this character exists
std::map<int, BaseCharacter>::iterator characterIt = characterMap.find(argPacket->characterIndex);
if (characterIt != characterMap.end()) {
//update the origin and motion, if there's a difference
if (characterIt->second.GetOrigin() != argPacket->origin) {
characterIt->second.SetOrigin(argPacket->origin);
}
if (characterIt->second.GetMotion() != argPacket->motion) {
characterIt->second.SetMotion(argPacket->motion);
characterIt->second.CorrectSprite(); //only correct the sprite if the motion changes
}
}
}
void World::hCharacterCreate(CharacterPacket* const argPacket) { void World::hCharacterCreate(CharacterPacket* const argPacket) {
//prevent double message //prevent double message
if (characterMap.find(argPacket->characterIndex) != characterMap.end()) { if (characterMap.find(argPacket->characterIndex) != characterMap.end()) {
@@ -49,25 +68,35 @@ void World::hCharacterCreate(CharacterPacket* const argPacket) {
BaseCharacter* character = &characterMap[argPacket->characterIndex]; BaseCharacter* character = &characterMap[argPacket->characterIndex];
//fill the character's info //fill the character's info
character->SetOrigin(argPacket->origin);
character->SetMotion(argPacket->motion);
character->SetBounds({CHARACTER_BOUNDS_X, CHARACTER_BOUNDS_Y, CHARACTER_BOUNDS_WIDTH, CHARACTER_BOUNDS_HEIGHT}); //TODO: (1) send the bounds from the server
character->SetHandle(argPacket->handle); character->SetHandle(argPacket->handle);
character->SetAvatar(argPacket->avatar); character->SetAvatar(argPacket->avatar);
character->SetOwner(argPacket->accountIndex); character->SetOwner(argPacket->accountIndex);
character->SetOrigin(argPacket->origin);
character->SetMotion(argPacket->motion);
character->SetBounds(argPacket->bounds);
character->CorrectSprite(); character->CorrectSprite();
//check for this player's character //check for this player's character
if (character->GetOwner() == accountIndex) { if (character->GetOwner() == accountIndex) {
localCharacter = static_cast<LocalCharacter*>(character); localCharacter = static_cast<LocalCharacter*>(character);
//focus the camera on this character //focus the camera on this character's sprite
camera.marginX = (camera.width / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2); camera.marginX = (camera.width / 2 - localCharacter->GetSprite()->GetImage()->GetClipW() / 2);
camera.marginY = (camera.height/ 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2); camera.marginY = (camera.height/ 2 - localCharacter->GetSprite()->GetImage()->GetClipH() / 2);
//focus on this character's info //focus on this character's info
characterIndex = argPacket->characterIndex; characterIndex = argPacket->characterIndex;
roomIndex = argPacket->roomIndex; roomIndex = argPacket->roomIndex;
//query the world state (room)
CharacterPacket newPacket;
memset(&newPacket, 0, MAX_PACKET_SIZE);
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
newPacket.roomIndex = roomIndex;
network.SendTo(Channels::SERVER, &newPacket);
newPacket.type = SerialPacketType::QUERY_MONSTER_EXISTS;
network.SendTo(Channels::SERVER, &newPacket);
} }
//debug //debug
@@ -91,10 +120,14 @@ void World::hCharacterDelete(CharacterPacket* const argPacket) {
//clear the room //clear the room
roomIndex = -1; roomIndex = -1;
regionPager.UnloadAll();
characterMap.clear();
monsterMap.clear();
}
else {
//remove this character
characterMap.erase(characterIt);
} }
//remove this character
characterMap.erase(characterIt);
//debug //debug
std::cout << "Character Delete, total: " << characterMap.size() << std::endl; std::cout << "Character Delete, total: " << characterMap.size() << std::endl;
@@ -102,9 +135,9 @@ void World::hCharacterDelete(CharacterPacket* const argPacket) {
void World::hQueryCharacterExists(CharacterPacket* const argPacket) { void World::hQueryCharacterExists(CharacterPacket* const argPacket) {
//prevent a double message about this player's character //prevent a double message about this player's character
if (argPacket->accountIndex == accountIndex) { // if (argPacket->accountIndex == accountIndex) {
return; // return;
} // }
//ignore characters in a different room (sub-optimal) //ignore characters in a different room (sub-optimal)
if (argPacket->roomIndex != roomIndex) { if (argPacket->roomIndex != roomIndex) {
@@ -128,11 +161,11 @@ void World::hQueryCharacterExists(CharacterPacket* const argPacket) {
} }
void World::hQueryCharacterStats(CharacterPacket* const argPacket) { void World::hQueryCharacterStats(CharacterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) World::hQueryCharacterStats()
} }
void World::hQueryCharacterLocation(CharacterPacket* const argPacket) { void World::hQueryCharacterLocation(CharacterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) World::hQueryCharacterLocation()
} }
void World::hCharacterMovement(CharacterPacket* const argPacket) { void World::hCharacterMovement(CharacterPacket* const argPacket) {
@@ -152,11 +185,11 @@ void World::hCharacterMovement(CharacterPacket* const argPacket) {
} }
void World::hCharacterAttack(CharacterPacket* const argPacket) { void World::hCharacterAttack(CharacterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) World::hCharacterAttack()
} }
void World::hCharacterDamage(CharacterPacket* const argPacket) { void World::hCharacterDamage(CharacterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) World::hCharacterDamage()
} }
//------------------------- //-------------------------
+3 -3
View File
@@ -26,14 +26,14 @@
//------------------------- //-------------------------
void World::hTextBroadcast(TextPacket* const argPacket) { void World::hTextBroadcast(TextPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) World::hTextBroadcast()
} }
void World::hTextSpeech(TextPacket* const argPacket) { void World::hTextSpeech(TextPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) World::hTextSpeech()
} }
void World::hTextWhisper(TextPacket* const argPacket) { void World::hTextWhisper(TextPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) World::hTextWhisper()
} }
+1 -2
View File
@@ -91,10 +91,9 @@ void World::SendDisconnectRequest() {
} }
void World::SendAdminDisconnectForced() { void World::SendAdminDisconnectForced() {
//TODO: (9) empty //TODO: (9) World::SendAdminDisconnectForced()
} }
void World::SendAdminShutdownRequest() { void World::SendAdminShutdownRequest() {
ClientPacket newPacket; ClientPacket newPacket;
+23 -13
View File
@@ -22,11 +22,12 @@
#include "world.hpp" #include "world.hpp"
#include "channels.hpp" #include "channels.hpp"
#include "terminal_error.hpp" #include "terminal_error.hpp"
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <cstring>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@@ -60,7 +61,7 @@ World::World(int* const argClientIndex, int* const argAccountIndex):
shutDownButton.SetText("Shut Down"); shutDownButton.SetText("Shut Down");
//load the tilesheet //load the tilesheet
//TODO: (1) Tile size and tile sheet should be loaded elsewhere //TODO: (2) Tile size and tile sheet should be loaded elsewhere
tileSheet.Load(config["dir.tilesets"] + "overworld.bmp", 32, 32); tileSheet.Load(config["dir.tilesets"] + "overworld.bmp", 32, 32);
//Send the character data //Send the character data
@@ -71,13 +72,6 @@ World::World(int* const argClientIndex, int* const argAccountIndex):
newPacket.accountIndex = accountIndex; newPacket.accountIndex = accountIndex;
network.SendTo(Channels::SERVER, &newPacket); network.SendTo(Channels::SERVER, &newPacket);
//query the world state
memset(&newPacket, 0, MAX_PACKET_SIZE);
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
network.SendTo(Channels::SERVER, &newPacket);
newPacket.type = SerialPacketType::QUERY_MONSTER_EXISTS;
network.SendTo(Channels::SERVER, &newPacket);
//set the camera's values //set the camera's values
camera.width = GetScreen()->w; camera.width = GetScreen()->w;
camera.height = GetScreen()->h; camera.height = GetScreen()->h;
@@ -132,8 +126,16 @@ void World::Update() {
it.second.Update(); it.second.Update();
} }
//update the map try {
UpdateMap(); //update the map
UpdateMap();
}
catch(terminal_error& e) {
throw(e);
}
catch(std::exception& e) {
std::cerr << "UpdateMap Error: " << e.what() << std::endl;
}
//skip the rest without a local character //skip the rest without a local character
if (!localCharacter) { if (!localCharacter) {
@@ -169,11 +171,16 @@ void World::Render(SDL_Surface* const screen) {
//draw the map //draw the map
for (std::list<Region>::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) { for (std::list<Region>::iterator it = regionPager.GetContainer()->begin(); it != regionPager.GetContainer()->end(); it++) {
tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y); tileSheet.DrawRegionTo(screen, &(*it), camera.x, camera.y);
//debugging
// std::ostringstream msg;
// msg << it->GetX() << ", " << it->GetY();
// font.DrawStringTo(msg.str(), screen, it->GetX() * tileSheet.GetImage()->GetClipW() - camera.x, it->GetY() * tileSheet.GetImage()->GetClipH() - camera.y);
} }
//draw the entities //draw the entities
for (auto& it : characterMap) { for (auto& it : characterMap) {
//TODO: (1) depth ordering //BUG: #29 Characters (and other entities) are drawn out of order
it.second.DrawTo(screen, camera.x, camera.y); it.second.DrawTo(screen, camera.x, camera.y);
} }
for (auto& it : monsterMap) { for (auto& it : monsterMap) {
@@ -221,7 +228,7 @@ void World::KeyDown(SDL_KeyboardEvent const& key) {
//hotkeys //hotkeys
switch(key.keysym.sym) { switch(key.keysym.sym) {
case SDLK_ESCAPE: case SDLK_ESCAPE:
//TODO: (1) the escape key should actually control menus and stuff //TODO: (3) the escape key should actually control menus and stuff
SendLogoutRequest(); SendLogoutRequest();
return; return;
} }
@@ -335,6 +342,9 @@ void World::HandlePacket(SerialPacket* const argPacket) {
break; break;
//character management //character management
case SerialPacketType::CHARACTER_UPDATE:
hCharacterUpdate(static_cast<CharacterPacket*>(argPacket));
break;
case SerialPacketType::CHARACTER_CREATE: case SerialPacketType::CHARACTER_CREATE:
hCharacterCreate(static_cast<CharacterPacket*>(argPacket)); hCharacterCreate(static_cast<CharacterPacket*>(argPacket));
break; break;
+40 -1
View File
@@ -23,6 +23,24 @@
#include "channels.hpp" #include "channels.hpp"
#include <sstream>
//-------------------------
//static functions
//-------------------------
static int regionChecksum(Region* const region) {
int sum = 0;
for(int i = 0; i < REGION_WIDTH; i++) {
for (int j = 0; j < REGION_HEIGHT; j++) {
for (int k = 0; k < REGION_DEPTH; k++) {
sum += region->GetTile(i, j, k);
}
}
}
return sum;
}
//------------------------- //-------------------------
//map management //map management
//------------------------- //-------------------------
@@ -40,6 +58,13 @@ void World::SendRegionRequest(int roomIndex, int x, int y) {
} }
void World::hRegionContent(RegionPacket* const argPacket) { void World::hRegionContent(RegionPacket* const argPacket) {
//checksum
if (regionChecksum(argPacket->region) == 0) {
std::ostringstream msg;
msg << "Received region checksum failed: " << argPacket->x << ", " << argPacket->y;
throw(std::runtime_error(msg.str()));
}
//replace existing regions //replace existing regions
regionPager.UnloadIf([&](Region const& region) -> bool { regionPager.UnloadIf([&](Region const& region) -> bool {
return region.GetX() == argPacket->x && region.GetY() == argPacket->y; return region.GetX() == argPacket->x && region.GetY() == argPacket->y;
@@ -71,9 +96,23 @@ void World::UpdateMap() {
//request empty regions within this zone //request empty regions within this zone
for (int i = xStart; i <= xEnd; i += REGION_WIDTH) { for (int i = xStart; i <= xEnd; i += REGION_WIDTH) {
for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) { for (int j = yStart; j <= yEnd; j += REGION_HEIGHT) {
if (!regionPager.FindRegion(i, j)) { Region* region = regionPager.FindRegion(i, j);
if (!region) {
//request absent region
SendRegionRequest(roomIndex, i, j); SendRegionRequest(roomIndex, i, j);
} }
else if (regionChecksum(region) == 0) {
//checksum failed
//NOTE: this patches bug #45, but does not resolve it
regionPager.UnloadIf([region](Region const& ref) -> bool {
//remove the erroneous region
return region == &ref;
});
SendRegionRequest(roomIndex, i, j);
std::ostringstream msg;
msg << "Existing region checksum failed: " << roomIndex << ", " << i << ", " << j;
throw(std::runtime_error(msg.str()));
}
} }
} }
} }
+4 -4
View File
@@ -99,11 +99,11 @@ void World::hQueryMonsterExists(MonsterPacket* const argPacket) {
} }
void World::hQueryMonsterStats(MonsterPacket* const argPacket) { void World::hQueryMonsterStats(MonsterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) World::hQueryMonsterStats()
} }
void World::hQueryMonsterLocation(MonsterPacket* const argPacket) { void World::hQueryMonsterLocation(MonsterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) World::hQueryMonsterLocation()
} }
void World::hMonsterMovement(MonsterPacket* const argPacket) { void World::hMonsterMovement(MonsterPacket* const argPacket) {
@@ -118,9 +118,9 @@ void World::hMonsterMovement(MonsterPacket* const argPacket) {
} }
void World::hMonsterAttack(MonsterPacket* const argPacket) { void World::hMonsterAttack(MonsterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) World::hMonsterAttack()
} }
void World::hMonsterDamage(MonsterPacket* const argPacket) { void World::hMonsterDamage(MonsterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) World::hMonsterDamage()
} }
+7 -1
View File
@@ -1,5 +1,5 @@
#include directories #include directories
INCLUDES+=. client_utilities entities gameplay_scenes menu_scenes ../common/debugging ../common/gameplay ../common/graphics ../common/map ../common/network ../common/network/packet_types ../common/ui ../common/utilities INCLUDES+=SDL . client_utilities entities gameplay_scenes menu_scenes ../common/debugging ../common/gameplay ../common/graphics ../common/map ../common/network ../common/network/packet_types ../common/ui ../common/utilities
#libraries #libraries
#the order of the $(LIBS) is important, at least for MinGW #the order of the $(LIBS) is important, at least for MinGW
@@ -45,6 +45,12 @@ $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean: clean:
ifeq ($(OS),Windows_NT)
$(RM) *.o *.a *.exe $(RM) *.o *.a *.exe
else ifeq ($(shell uname), Linux)
find . -type f -name *.o -exec rm -f -r -v {} \;
find . -type f -name *.a -exec rm -f -r -v {} \;
rm -f -v out/client out/server
endif
rebuild: clean all rebuild: clean all
+4 -3
View File
@@ -107,7 +107,8 @@ void LobbyMenu::Render(SDL_Surface* const screen) {
join.DrawTo(screen); join.DrawTo(screen);
back.DrawTo(screen); back.DrawTo(screen);
//TODO: (1) draw headers for the server list //TODO: (3) draw headers for the server list
//TODO: (3) ping/delay displayed in the server list
for (int i = 0; i < serverInfo.size(); i++) { for (int i = 0; i < serverInfo.size(); i++) {
//draw the selected server's highlight //draw the selected server's highlight
if (selection == &serverInfo[i]) { if (selection == &serverInfo[i]) {
@@ -252,11 +253,11 @@ void LobbyMenu::HandleLoginResponse(ClientPacket* const argPacket) {
} }
void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) { void LobbyMenu::HandleJoinRejection(TextPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) LobbyMenu::HandleJoinRejection()
} }
void LobbyMenu::HandleLoginRejection(TextPacket* const argPacket) { void LobbyMenu::HandleLoginRejection(TextPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) LobbyMenu::HandleLoginRejection
} }
//------------------------- //-------------------------
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
-5
View File
@@ -6,8 +6,3 @@ all:
$(MAKE) -C network $(MAKE) -C network
$(MAKE) -C ui $(MAKE) -C ui
$(MAKE) -C utilities $(MAKE) -C utilities
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
-55
View File
@@ -1,55 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "map_system_api.hpp"
//all map API headers
#include "region_api.hpp"
#include "region_pager_api.hpp"
//useful "globals"
//...
//This mimics linit.c to create a nested collection of all map modules.
static const luaL_Reg funcs[] = {
{nullptr, nullptr}
};
static const luaL_Reg libs[] = {
{"Region", openRegionAPI},
{"RegionPager", openRegionPagerAPI},
{nullptr, nullptr}
};
int openMapSystemAPI(lua_State* L) {
//create the table
luaL_newlibtable(L, libs);
//push the "global" functions
luaL_setfuncs(L, funcs, 0);
//push the substable
for (const luaL_Reg* lib = libs; lib->func; lib++) {
lib->func(L);
lua_setfield(L, -2, lib->name);
}
return 1;
}
+1 -1
View File
@@ -24,7 +24,7 @@
#include "lua.hpp" #include "lua.hpp"
#define TORTUGA_REGION_NAME "region" #define TORTUGA_REGION_API "region"
LUAMOD_API int openRegionAPI(lua_State* L); LUAMOD_API int openRegionAPI(lua_State* L);
#endif #endif
+1
View File
@@ -25,6 +25,7 @@
#include "region.hpp" #include "region.hpp"
//DOCS: These glue functions simply wrap RegionPagerLua's methods //DOCS: These glue functions simply wrap RegionPagerLua's methods
//NOTE: zero indexing is used here, but not in the region API
static int setTile(lua_State* L) { static int setTile(lua_State* L) {
RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1)); RegionPagerLua* pager = reinterpret_cast<RegionPagerLua*>(lua_touserdata(L, 1));
+1 -1
View File
@@ -24,7 +24,7 @@
#include "lua.hpp" #include "lua.hpp"
#define TORTUGA_REGION_PAGER_NAME "region_pager" #define TORTUGA_REGION_PAGER_API "region_pager"
LUAMOD_API int openRegionPagerAPI(lua_State* L); LUAMOD_API int openRegionPagerAPI(lua_State* L);
#endif #endif
+1
View File
@@ -70,6 +70,7 @@ Region* RegionPagerBase::FindRegion(int x, int y) {
} }
Region* RegionPagerBase::PushRegion(Region* const ptr) { Region* RegionPagerBase::PushRegion(Region* const ptr) {
//BUG: #45 Some regions are occasionally losing their tile data
regionList.push_front(*ptr); regionList.push_front(*ptr);
return &regionList.front(); return &regionList.front();
} }
-5
View File
@@ -31,8 +31,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
@@ -36,11 +36,18 @@ void serializeCharacter(void* buffer, CharacterPacket* packet) {
//location //location
serialCopy(&buffer, &packet->roomIndex, sizeof(int)); serialCopy(&buffer, &packet->roomIndex, sizeof(int));
serialCopy(&buffer, &packet->origin.x, sizeof(double)); serialCopy(&buffer, &packet->origin.x, sizeof(double));
serialCopy(&buffer, &packet->origin.y, sizeof(double)); serialCopy(&buffer, &packet->origin.y, sizeof(double));
serialCopy(&buffer, &packet->motion.x, sizeof(double)); serialCopy(&buffer, &packet->motion.x, sizeof(double));
serialCopy(&buffer, &packet->motion.y, sizeof(double)); serialCopy(&buffer, &packet->motion.y, sizeof(double));
serialCopy(&buffer, &packet->bounds.x, sizeof(int));
serialCopy(&buffer, &packet->bounds.y, sizeof(int));
serialCopy(&buffer, &packet->bounds.w, sizeof(int));
serialCopy(&buffer, &packet->bounds.h, sizeof(int));
//gameplay components: equipment, items, buffs, debuffs... //gameplay components: equipment, items, buffs, debuffs...
} }
@@ -57,10 +64,17 @@ void deserializeCharacter(void* buffer, CharacterPacket* packet) {
//location //location
deserialCopy(&buffer, &packet->roomIndex, sizeof(int)); deserialCopy(&buffer, &packet->roomIndex, sizeof(int));
deserialCopy(&buffer, &packet->origin.x, sizeof(double)); deserialCopy(&buffer, &packet->origin.x, sizeof(double));
deserialCopy(&buffer, &packet->origin.y, sizeof(double)); deserialCopy(&buffer, &packet->origin.y, sizeof(double));
deserialCopy(&buffer, &packet->motion.x, sizeof(double)); deserialCopy(&buffer, &packet->motion.x, sizeof(double));
deserialCopy(&buffer, &packet->motion.y, sizeof(double)); deserialCopy(&buffer, &packet->motion.y, sizeof(double));
deserialCopy(&buffer, &packet->bounds.x, sizeof(int));
deserialCopy(&buffer, &packet->bounds.y, sizeof(int));
deserialCopy(&buffer, &packet->bounds.w, sizeof(int));
deserialCopy(&buffer, &packet->bounds.h, sizeof(int));
//gameplay components: equipment, items, buffs, debuffs... //gameplay components: equipment, items, buffs, debuffs...
} }
@@ -24,6 +24,7 @@
#include "serial_packet_base.hpp" #include "serial_packet_base.hpp"
#include "bounding_box.hpp"
#include "vector2.hpp" #include "vector2.hpp"
struct CharacterPacket : SerialPacketBase { struct CharacterPacket : SerialPacketBase {
@@ -39,6 +40,7 @@ struct CharacterPacket : SerialPacketBase {
int roomIndex; int roomIndex;
Vector2 origin; Vector2 origin;
Vector2 motion; Vector2 motion;
BoundingBox bounds;
}; };
void serializeCharacter(void* buffer, CharacterPacket* packet); void serializeCharacter(void* buffer, CharacterPacket* packet);
@@ -28,7 +28,7 @@ struct ClientPacket : SerialPacketBase {
int clientIndex; int clientIndex;
int accountIndex; int accountIndex;
char username[PACKET_STRING_SIZE]; char username[PACKET_STRING_SIZE];
//TODO: (9) password, auth token //TODO: (3) password, auth token
}; };
void serializeClient(void* buffer, ClientPacket* packet); void serializeClient(void* buffer, ClientPacket* packet);
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
@@ -24,7 +24,7 @@
#include "serial_packet_type.hpp" #include "serial_packet_type.hpp"
#include "SDL/SDL_net.h" #include "SDL_net.h"
constexpr int PACKET_STRING_SIZE = 100; constexpr int PACKET_STRING_SIZE = 100;
+1 -1
View File
@@ -34,7 +34,7 @@
typedef SerialPacketBase SerialPacket; typedef SerialPacketBase SerialPacket;
//DOCS: NETWORK_VERSION is used to discern compatible servers and clients //DOCS: NETWORK_VERSION is used to discern compatible servers and clients
constexpr int NETWORK_VERSION = 20150214; constexpr int NETWORK_VERSION = 20150304;
union MaxPacket { union MaxPacket {
CharacterPacket a; CharacterPacket a;
+35 -1
View File
@@ -25,6 +25,7 @@
/* DOCS: The headers indicate what packet type is used for each message /* DOCS: The headers indicate what packet type is used for each message
* different messages under the same header will carry different amounts of * different messages under the same header will carry different amounts of
* valid data, but it will still be carried in that packet's format. * valid data, but it will still be carried in that packet's format.
* FORMAT_* is for internal use, deviding the different format bounds.
*/ */
enum class SerialPacketType { enum class SerialPacketType {
@@ -36,6 +37,8 @@ enum class SerialPacketType {
// name, player count, version // name, player count, version
//------------------------- //-------------------------
FORMAT_SERVER,
//heartbeat //heartbeat
PING, PING,
PONG, PONG,
@@ -44,11 +47,15 @@ enum class SerialPacketType {
BROADCAST_REQUEST, BROADCAST_REQUEST,
BROADCAST_RESPONSE, BROADCAST_RESPONSE,
FORMAT_END_SERVER,
//------------------------- //-------------------------
//ClientPacket //ClientPacket
// client index, account index, username // client index, account index, username
//------------------------- //-------------------------
FORMAT_CLIENT,
//Connecting to a server as a client //Connecting to a server as a client
JOIN_REQUEST, JOIN_REQUEST,
JOIN_RESPONSE, JOIN_RESPONSE,
@@ -69,15 +76,21 @@ enum class SerialPacketType {
//shut down the server //shut down the server
ADMIN_SHUTDOWN_REQUEST, ADMIN_SHUTDOWN_REQUEST,
FORMAT_END_CLIENT,
//------------------------- //-------------------------
//RegionPacket //RegionPacket
// room index, x, y, raw data // room index, x, y, raw data
//------------------------- //-------------------------
FORMAT_REGION,
//map data //map data
REGION_REQUEST, REGION_REQUEST,
REGION_CONTENT, REGION_CONTENT,
FORMAT_END_REGION,
//------------------------- //-------------------------
//CharacterPacket //CharacterPacket
// character index, // character index,
@@ -86,6 +99,11 @@ enum class SerialPacketType {
// room index, origin, motion // room index, origin, motion
//------------------------- //-------------------------
FORMAT_CHARACTER,
//full data update
CHARACTER_UPDATE,
//character management //character management
CHARACTER_CREATE, CHARACTER_CREATE,
CHARACTER_DELETE, CHARACTER_DELETE,
@@ -97,7 +115,7 @@ enum class SerialPacketType {
QUERY_CHARACTER_STATS, QUERY_CHARACTER_STATS,
QUERY_CHARACTER_LOCATION, QUERY_CHARACTER_LOCATION,
//set the info in the server //actions taken
CHARACTER_MOVEMENT, CHARACTER_MOVEMENT,
CHARACTER_ATTACK, CHARACTER_ATTACK,
CHARACTER_DAMAGE, CHARACTER_DAMAGE,
@@ -105,6 +123,8 @@ enum class SerialPacketType {
//admin control //admin control
// ADMIN_SET_CHARACTER_ORIGIN, // ADMIN_SET_CHARACTER_ORIGIN,
FORMAT_END_CHARACTER,
//------------------------- //-------------------------
//MonsterPacket //MonsterPacket
// monster index, // monster index,
@@ -113,22 +133,34 @@ enum class SerialPacketType {
// room index, origin, motion // room index, origin, motion
//------------------------- //-------------------------
FORMAT_MONSTER,
//full data update
MONSTER_UPDATE,
//character management
MONSTER_CREATE, MONSTER_CREATE,
MONSTER_DELETE, MONSTER_DELETE,
//find out info from the server
QUERY_MONSTER_EXISTS, QUERY_MONSTER_EXISTS,
QUERY_MONSTER_STATS, QUERY_MONSTER_STATS,
QUERY_MONSTER_LOCATION, QUERY_MONSTER_LOCATION,
//actions taken
MONSTER_MOVEMENT, MONSTER_MOVEMENT,
MONSTER_ATTACK, MONSTER_ATTACK,
MONSTER_DAMAGE, MONSTER_DAMAGE,
FORMAT_END_MONSTER,
//------------------------- //-------------------------
//TextPacket //TextPacket
// name, text // name, text
//------------------------- //-------------------------
FORMAT_TEXT,
//general speech //general speech
TEXT_BROADCAST, TEXT_BROADCAST,
TEXT_SPEECH, TEXT_SPEECH,
@@ -143,6 +175,8 @@ enum class SerialPacketType {
SHUTDOWN_REJECTION, SHUTDOWN_REJECTION,
QUERY_REJECTION, QUERY_REJECTION,
FORMAT_END_TEXT,
//------------------------- //-------------------------
//not used //not used
//------------------------- //-------------------------
+47 -114
View File
@@ -31,6 +31,9 @@
#include <cstring> #include <cstring>
//macros
#define BOUNDS(type, lower, upper) ((type) > (lower) && (type) < (upper))
//raw memory copy //raw memory copy
void serialCopy(void** buffer, void* data, int size) { void serialCopy(void** buffer, void* data, int size) {
memcpy(*buffer, data, size); memcpy(*buffer, data, size);
@@ -46,63 +49,28 @@ void deserialCopy(void** buffer, void* data, int size) {
//main switch functions //main switch functions
void serializePacket(void* buffer, SerialPacketBase* packet) { void serializePacket(void* buffer, SerialPacketBase* packet) {
switch(packet->type) { if (BOUNDS(packet->type, SerialPacketType::FORMAT_SERVER, SerialPacketType::FORMAT_END_SERVER)) {
case SerialPacketType::PING: serializeServer(buffer, static_cast<ServerPacket*>(packet));
case SerialPacketType::PONG: }
case SerialPacketType::BROADCAST_REQUEST:
case SerialPacketType::BROADCAST_RESPONSE: if (BOUNDS(packet->type, SerialPacketType::FORMAT_CLIENT, SerialPacketType::FORMAT_END_CLIENT)) {
serializeServer(buffer, static_cast<ServerPacket*>(packet)); serializeClient(buffer, static_cast<ClientPacket*>(packet));
break; }
case SerialPacketType::JOIN_REQUEST:
case SerialPacketType::JOIN_RESPONSE: if (BOUNDS(packet->type, SerialPacketType::FORMAT_REGION, SerialPacketType::FORMAT_END_REGION)) {
case SerialPacketType::DISCONNECT_REQUEST: serializeRegion(buffer, static_cast<RegionPacket*>(packet));
case SerialPacketType::DISCONNECT_RESPONSE: }
case SerialPacketType::ADMIN_DISCONNECT_FORCED:
case SerialPacketType::LOGIN_REQUEST: if (BOUNDS(packet->type, SerialPacketType::FORMAT_CHARACTER, SerialPacketType::FORMAT_END_CHARACTER)) {
case SerialPacketType::LOGIN_RESPONSE: serializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
case SerialPacketType::LOGOUT_REQUEST: }
case SerialPacketType::LOGOUT_RESPONSE:
case SerialPacketType::ADMIN_SHUTDOWN_REQUEST: if (BOUNDS(packet->type, SerialPacketType::FORMAT_MONSTER, SerialPacketType::FORMAT_END_MONSTER)) {
serializeClient(buffer, static_cast<ClientPacket*>(packet)); serializeMonster(buffer, static_cast<MonsterPacket*>(packet));
break; }
case SerialPacketType::REGION_REQUEST:
case SerialPacketType::REGION_CONTENT: if (BOUNDS(packet->type, SerialPacketType::FORMAT_TEXT, SerialPacketType::FORMAT_END_TEXT)) {
serializeRegion(buffer, static_cast<RegionPacket*>(packet)); serializeText(buffer, static_cast<TextPacket*>(packet));
break;
case SerialPacketType::CHARACTER_CREATE:
case SerialPacketType::CHARACTER_DELETE:
case SerialPacketType::CHARACTER_LOAD:
case SerialPacketType::CHARACTER_UNLOAD:
case SerialPacketType::QUERY_CHARACTER_EXISTS:
case SerialPacketType::QUERY_CHARACTER_STATS:
case SerialPacketType::QUERY_CHARACTER_LOCATION:
case SerialPacketType::CHARACTER_MOVEMENT:
case SerialPacketType::CHARACTER_ATTACK:
case SerialPacketType::CHARACTER_DAMAGE:
serializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
break;
case SerialPacketType::MONSTER_CREATE:
case SerialPacketType::MONSTER_DELETE:
case SerialPacketType::QUERY_MONSTER_EXISTS:
case SerialPacketType::QUERY_MONSTER_STATS:
case SerialPacketType::QUERY_MONSTER_LOCATION:
case SerialPacketType::MONSTER_MOVEMENT:
case SerialPacketType::MONSTER_ATTACK:
case SerialPacketType::MONSTER_DAMAGE:
serializeMonster(buffer, static_cast<MonsterPacket*>(packet));
break;
case SerialPacketType::TEXT_BROADCAST:
case SerialPacketType::TEXT_SPEECH:
case SerialPacketType::TEXT_WHISPER:
case SerialPacketType::JOIN_REJECTION:
case SerialPacketType::LOGIN_REJECTION:
case SerialPacketType::REGION_REJECTION:
case SerialPacketType::CHARACTER_REJECTION:
case SerialPacketType::MONSTER_REJECTION:
case SerialPacketType::SHUTDOWN_REJECTION:
case SerialPacketType::QUERY_REJECTION:
serializeText(buffer, static_cast<TextPacket*>(packet));
break;
} }
} }
@@ -111,62 +79,27 @@ void deserializePacket(void* buffer, SerialPacketBase* packet) {
SerialPacketType type; SerialPacketType type;
memcpy(&type, buffer, sizeof(SerialPacketType)); memcpy(&type, buffer, sizeof(SerialPacketType));
switch(type) { if (BOUNDS(type, SerialPacketType::FORMAT_SERVER, SerialPacketType::FORMAT_END_SERVER)) {
case SerialPacketType::PING: deserializeServer(buffer, static_cast<ServerPacket*>(packet));
case SerialPacketType::PONG: }
case SerialPacketType::BROADCAST_REQUEST:
case SerialPacketType::BROADCAST_RESPONSE: if (BOUNDS(type, SerialPacketType::FORMAT_CLIENT, SerialPacketType::FORMAT_END_CLIENT)) {
deserializeServer(buffer, static_cast<ServerPacket*>(packet)); deserializeClient(buffer, static_cast<ClientPacket*>(packet));
break; }
case SerialPacketType::JOIN_REQUEST:
case SerialPacketType::JOIN_RESPONSE: if (BOUNDS(type, SerialPacketType::FORMAT_REGION, SerialPacketType::FORMAT_END_REGION)) {
case SerialPacketType::DISCONNECT_REQUEST: deserializeRegion(buffer, static_cast<RegionPacket*>(packet));
case SerialPacketType::DISCONNECT_RESPONSE: }
case SerialPacketType::ADMIN_DISCONNECT_FORCED:
case SerialPacketType::LOGIN_REQUEST: if (BOUNDS(type, SerialPacketType::FORMAT_CHARACTER, SerialPacketType::FORMAT_END_CHARACTER)) {
case SerialPacketType::LOGIN_RESPONSE: deserializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
case SerialPacketType::LOGOUT_REQUEST: }
case SerialPacketType::LOGOUT_RESPONSE:
case SerialPacketType::ADMIN_SHUTDOWN_REQUEST: if (BOUNDS(type, SerialPacketType::FORMAT_MONSTER, SerialPacketType::FORMAT_END_MONSTER)) {
deserializeClient(buffer, static_cast<ClientPacket*>(packet)); deserializeMonster(buffer, static_cast<MonsterPacket*>(packet));
break; }
case SerialPacketType::REGION_REQUEST:
case SerialPacketType::REGION_CONTENT: if (BOUNDS(type, SerialPacketType::FORMAT_TEXT, SerialPacketType::FORMAT_END_TEXT)) {
deserializeRegion(buffer, static_cast<RegionPacket*>(packet)); deserializeText(buffer, static_cast<TextPacket*>(packet));
break;
case SerialPacketType::CHARACTER_CREATE:
case SerialPacketType::CHARACTER_DELETE:
case SerialPacketType::CHARACTER_LOAD:
case SerialPacketType::CHARACTER_UNLOAD:
case SerialPacketType::QUERY_CHARACTER_EXISTS:
case SerialPacketType::QUERY_CHARACTER_STATS:
case SerialPacketType::QUERY_CHARACTER_LOCATION:
case SerialPacketType::CHARACTER_MOVEMENT:
case SerialPacketType::CHARACTER_ATTACK:
case SerialPacketType::CHARACTER_DAMAGE:
deserializeCharacter(buffer, static_cast<CharacterPacket*>(packet));
break;
case SerialPacketType::MONSTER_CREATE:
case SerialPacketType::MONSTER_DELETE:
case SerialPacketType::QUERY_MONSTER_EXISTS:
case SerialPacketType::QUERY_MONSTER_STATS:
case SerialPacketType::QUERY_MONSTER_LOCATION:
case SerialPacketType::MONSTER_MOVEMENT:
case SerialPacketType::MONSTER_ATTACK:
case SerialPacketType::MONSTER_DAMAGE:
deserializeMonster(buffer, static_cast<MonsterPacket*>(packet));
break;
case SerialPacketType::TEXT_BROADCAST:
case SerialPacketType::TEXT_SPEECH:
case SerialPacketType::TEXT_WHISPER:
case SerialPacketType::JOIN_REJECTION:
case SerialPacketType::LOGIN_REJECTION:
case SerialPacketType::REGION_REJECTION:
case SerialPacketType::CHARACTER_REJECTION:
case SerialPacketType::MONSTER_REJECTION:
case SerialPacketType::SHUTDOWN_REJECTION:
case SerialPacketType::QUERY_REJECTION:
deserializeText(buffer, static_cast<TextPacket*>(packet));
break;
} }
} }
+1 -1
View File
@@ -27,7 +27,7 @@
#include "singleton.hpp" #include "singleton.hpp"
//APIs //APIs
#include "SDL/SDL_net.h" #include "SDL_net.h"
class UDPNetworkUtility : public Singleton<UDPNetworkUtility> { class UDPNetworkUtility : public Singleton<UDPNetworkUtility> {
public: public:
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
+1 -1
View File
@@ -22,7 +22,7 @@
#ifndef IPOPERATORS_HPP_ #ifndef IPOPERATORS_HPP_
#define IPOPERATORS_HPP_ #define IPOPERATORS_HPP_
#include "SDL/SDL_net.h" #include "SDL_net.h"
//these should've come standard //these should've come standard
bool operator==(IPaddress lhs, IPaddress rhs); bool operator==(IPaddress lhs, IPaddress rhs);
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
View File
+12 -2
View File
@@ -19,13 +19,23 @@ release: clean all package
#For use on my machine ONLY #For use on my machine ONLY
package: package:
rar a -r -ep Tortuga.rar $(OUTDIR)/*.exe $(OUTDIR)/*.dll ifeq ($(OS),Windows_NT)
rar a -r Tortuga.rar rsc/* copyright.txt README.txt rar a -r -ep Tortuga-win.rar $(OUTDIR)/*.exe $(OUTDIR)/*.dll
rar a -r Tortuga-win.rar rsc/* copyright.txt instructions.txt
else ifeq ($(shell uname), Linux)
tar -C $(OUTDIR) -zcvf Tortuga-linux.tar client server ../rsc ../copyright.txt ../instructions.txt
endif
$(OUTDIR): $(OUTDIR):
mkdir $(OUTDIR) mkdir $(OUTDIR)
clean: clean:
ifeq ($(OS),Windows_NT)
$(RM) *.o *.a *.exe $(RM) *.o *.a *.exe
else ifeq ($(shell uname), Linux)
find . -type f -name *.o -exec rm -f -r -v {} \;
find . -type f -name *.a -exec rm -f -r -v {} \;
rm -f -v out/client out/server
endif
rebuild: clean all rebuild: clean all
+89
View File
@@ -0,0 +1,89 @@
--[[
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
--]]
--DOCS: a placeholder door utility
local doorUtility = {}
roomAPI = require("room")
regionPagerAPI = require("region_pager")
triggerAPI = require("trigger")
triggerManagerAPI = require("trigger_manager")
entityAPI = require("entity")
characterAPI = require("character")
networkAPI = require("network")
function doorUtility.createTrigger(handle, room, x, y, script)
local pager = roomAPI.GetPager(room)
--place the indicator tile
regionPagerAPI.SetTile(pager, x / 32, y / 32, 0, mapMaker.dirt)
regionPagerAPI.SetTile(pager, x / 32, y / 32, 1, mapMaker.blank)
regionPagerAPI.SetTile(pager, x / 32, y / 32, 2, mapMaker.blank)
--create the trigger object
triggerManagerAPI.Create(
roomAPI.GetTriggerMgr(room), handle, x, y,
0, 0, 32, 32, --size of the tiles
script
)
end
function doorUtility.createDoorPair(handle, roomOne, Xone, Yone, roomTwo, Xtwo, Ytwo)
--create the scripts
local function scriptOne(entity)
if entityAPI.GetType(entity) ~= "character" then return end
--move the character
characterAPI.SetRoom(entity, roomTwo)
characterAPI.SetOrigin(entity, Xtwo, Ytwo-16)
networkAPI.PumpCharacterUpdate(entity)
--disable the other trigger
local triggerTwo = triggerManagerAPI.GetTrigger(roomAPI.GetTriggerMgr(roomTwo), handle)
triggerAPI.PushExclusionEntity(triggerTwo, entity)
end
local function scriptTwo(entity)
if entityAPI.GetType(entity) ~= "character" then return end
--move the character
characterAPI.SetRoom(entity, roomOne)
characterAPI.SetOrigin(entity, Xone, Yone-16) --NOTE: the 16 pixel margin for presentation
networkAPI.PumpCharacterUpdate(entity)
--disable the other trigger
local triggerOne = triggerManagerAPI.GetTrigger(roomAPI.GetTriggerMgr(roomOne), handle)
triggerAPI.PushExclusionEntity(triggerOne, entity)
end
--create the triggers proper
doorUtility.createTrigger(handle, roomOne, Xone, Yone, scriptOne)
doorUtility.createTrigger(handle, roomTwo, Xtwo, Ytwo, scriptTwo)
end
return doorUtility
+71 -25
View File
@@ -1,4 +1,30 @@
local Region = require("map_system").Region --[[
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
--]]
--DOCS: a placeholder map generator
local regionAPI = require("region")
local mapMaker = {} local mapMaker = {}
@@ -7,6 +33,7 @@ function mapMaker.Sqr(x) return x*x end
function mapMaker.Dist(x, y, i, j) return math.sqrt(mapMaker.Sqr(x - i) + mapMaker.Sqr(y - j)) end function mapMaker.Dist(x, y, i, j) return math.sqrt(mapMaker.Sqr(x - i) + mapMaker.Sqr(y - j)) end
--tile macros, mapped to the tilesheet "overworld.bmp" --tile macros, mapped to the tilesheet "overworld.bmp"
mapMaker.blank = 0
mapMaker.water = 18 + 3 * 0 mapMaker.water = 18 + 3 * 0
mapMaker.sand = 18 + 3 * 1 mapMaker.sand = 18 + 3 * 1
mapMaker.plains = 18 + 3 * 2 mapMaker.plains = 18 + 3 * 2
@@ -20,42 +47,43 @@ mapMaker.edges.south = 16
mapMaker.edges.east = 1 mapMaker.edges.east = 1
mapMaker.edges.west = -1 mapMaker.edges.west = -1
--TODO: (1) path system
--use these macros (mapped to "overworld.bmp" for now) to smooth the region's edges --use these macros (mapped to "overworld.bmp" for now) to smooth the region's edges
function mapMaker.SmoothEdgesSimple(r) function mapMaker.SmoothEdgesSimple(r)
--make and pad an array to use --make and pad an array to use
local shiftArray = {} local shiftArray = {}
for i = 1, Region.GetWidth(r) do for i = 1, regionAPI.GetWidth(r) do
shiftArray[i] = {} shiftArray[i] = {}
for j = 1, Region.GetHeight(r) do for j = 1, regionAPI.GetHeight(r) do
shiftArray[i][j] = 0 shiftArray[i][j] = 0
end end
end end
--build the array --build the array
for i = 1, Region.GetWidth(r) do for i = 1, regionAPI.GetWidth(r) do
for j = 1, Region.GetHeight(r) do for j = 1, regionAPI.GetHeight(r) do
--if (not region edge) and (west tile < this tile), etc. --if (not regionAPI edge) and (west tile < this tile), etc.
if i > 1 and Region.GetTile(r, i - 1, j, 1) < Region.GetTile(r, i, j, 1) then if i > 1 and regionAPI.GetTile(r, i - 1, j, 1) < regionAPI.GetTile(r, i, j, 1) then
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.west shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.west
end end
if j > 1 and Region.GetTile(r, i, j - 1, 1) < Region.GetTile(r, i, j, 1) then if j > 1 and regionAPI.GetTile(r, i, j - 1, 1) < regionAPI.GetTile(r, i, j, 1) then
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.north shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.north
end end
if i < Region.GetWidth(r) and Region.GetTile(r, i + 1, j, 1) < Region.GetTile(r, i, j, 1) then if i < regionAPI.GetWidth(r) and regionAPI.GetTile(r, i + 1, j, 1) < regionAPI.GetTile(r, i, j, 1) then
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.east shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.east
end end
if j < Region.GetHeight(r) and Region.GetTile(r, i, j + 1, 1) < Region.GetTile(r, i, j, 1) then if j < regionAPI.GetHeight(r) and regionAPI.GetTile(r, i, j + 1, 1) < regionAPI.GetTile(r, i, j, 1) then
shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.south shiftArray[i][j] = shiftArray[i][j] + mapMaker.edges.south
end end
end end
end end
--finally apply this --finally apply this
for i = 1, Region.GetWidth(r) do for i = 1, regionAPI.GetWidth(r) do
for j = 1, Region.GetHeight(r) do for j = 1, regionAPI.GetHeight(r) do
if shiftArray[i][j] ~= 0 then if shiftArray[i][j] ~= 0 then
Region.SetTile(r, i, j, 2, Region.GetTile(r, i, j, 1) + shiftArray[i][j]) regionAPI.SetTile(r, i, j, 2, regionAPI.GetTile(r, i, j, 1) + shiftArray[i][j])
Region.SetTile(r, i, j, 1, Region.GetTile(r, i, j, 1) - 3) regionAPI.SetTile(r, i, j, 1, regionAPI.GetTile(r, i, j, 1) - 3)
end end
end end
end end
@@ -63,28 +91,31 @@ end
--custom generation systems here --custom generation systems here
function mapMaker.DebugIsland(r) function mapMaker.DebugIsland(r)
--debug
io.write("map_maker:DebugIsland(", regionAPI.GetX(r), ", ", regionAPI.GetY(r), ")\n")
--basic distance check for each tile, placing an island around the world origin --basic distance check for each tile, placing an island around the world origin
for i = 1, Region.GetWidth(r) do for i = 1, regionAPI.GetWidth(r) do
for j = 1, Region.GetHeight(r) do for j = 1, regionAPI.GetHeight(r) do
local dist = mapMaker.Dist(0, 0, i + Region.GetX(r) -1, j + Region.GetY(r) -1) local dist = mapMaker.Dist(0, 0, i + regionAPI.GetX(r) -1, j + regionAPI.GetY(r) -1)
if dist < 10 then if dist < 10 then
Region.SetTile(r, i, j, 1, mapMaker.plains) regionAPI.SetTile(r, i, j, 1, mapMaker.plains)
elseif dist < 12 then elseif dist < 12 then
Region.SetTile(r, i, j, 1, mapMaker.sand) regionAPI.SetTile(r, i, j, 1, mapMaker.sand)
else else
Region.SetTile(r, i, j, 1, mapMaker.water) regionAPI.SetTile(r, i, j, 1, mapMaker.water)
Region.SetSolid(r, i, j, true) regionAPI.SetSolid(r, i, j, true)
end end
end end
end end
--examples of the smoothing function NOT working correctly --examples of the smoothing function NOT working correctly
--[[ --[[
for j = 1, Region.GetHeight(r) do for j = 1, regionAPI.GetHeight(r) do
Region.SetTile(r, 3, j, 1, mapMaker.dirt) regionAPI.SetTile(r, 3, j, 1, mapMaker.dirt)
Region.SetTile(r, 4, j, 1, mapMaker.dirt) regionAPI.SetTile(r, 4, j, 1, mapMaker.dirt)
Region.SetTile(r, 10, j, 1, mapMaker.dirt) regionAPI.SetTile(r, 10, j, 1, mapMaker.dirt)
end end
--]] --]]
@@ -92,4 +123,19 @@ function mapMaker.DebugIsland(r)
mapMaker.SmoothEdgesSimple(r) mapMaker.SmoothEdgesSimple(r)
end end
function mapMaker.DebugGrassland(r)
--debug
io.write("map_maker:DebugGrassland(", regionAPI.GetX(r), ", ", regionAPI.GetY(r), ")\n")
--all dirt
for i = 1, regionAPI.GetWidth(r) do
for j = 1, regionAPI.GetHeight(r) do
regionAPI.SetTile(r, i, j, 1, mapMaker.grass)
end
end
--A generic edge system
-- mapMaker.SmoothEdgesSimple(r)
end
return mapMaker return mapMaker
+28 -4
View File
@@ -1,15 +1,39 @@
local Region = require("map_system").Region --[[
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
--]]
local region = require("region")
local mapSaver = {} local mapSaver = {}
function mapSaver.Load(r) function mapSaver.Load(r)
--empty --empty
io.write("map_saver:Load(", Region.GetX(r), ", ", Region.GetY(r), ")\n") -- io.write("map_saver:Load(", region.GetX(r), ", ", region.GetY(r), ")\n")
end end
function mapSaver.Save(r) function mapSaver.Save(r)
--empty --empty
io.write("map_saver:Save(", Region.GetX(r), ", ", Region.GetY(r), ")\n") -- io.write("map_saver:Save(", region.GetX(r), ", ", region.GetY(r), ")\n")
end end
--TODO: (9) create a flexible saving & loading system --TODO: (3) create a flexible saving & loading system
return mapSaver return mapSaver
+53 -10
View File
@@ -1,18 +1,61 @@
--[[
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
--]]
--DOCS: This script is run by the server on startup
print("Lua script check") print("Lua script check")
--requirements
roomManagerAPI = require("room_manager")
roomAPI = require("room")
mapMaker = require("map_maker") mapMaker = require("map_maker")
mapSaver = require("map_saver") mapSaver = require("map_saver")
roomSystem = require("room_system")
local function dumpTable(t) doorUtility = require("door_utility")
print(t)
for k, v in pairs(t) do --test the room hooks
print("",k,v) roomManagerAPI.SetOnCreate(function(room, index)
end print("", "Creating room: ", roomAPI.GetName(room), index)
end
roomAPI.SetOnTick(room, function(room)
roomAPI.ForEachCharacter(room, function(character)
--
end)
end)
end)
roomManagerAPI.SetOnUnload(function(room, index)
print("", "Unloading room: ", roomAPI.GetName(room), index)
end)
--NOTE: room 0 is the first that the client asks for, therefore it must exist --NOTE: room 0 is the first that the client asks for, therefore it must exist
local overworld, uid = roomSystem.RoomManager.CreateRoom("overworld", "overworld.bmp") local overworld, uidOne = roomManagerAPI.CreateRoom("overworld", "overworld.bmp")
roomSystem.Room.Initialize(overworld, mapSaver.Load, mapSaver.Save, mapMaker.DebugIsland, mapSaver.Save) roomAPI.Initialize(overworld, mapSaver.Load, mapSaver.Save, mapMaker.DebugIsland, mapSaver.Save)
print("Finished the lua script") local underworld, uidTwo = roomManagerAPI.CreateRoom("underworld", "overworld.bmp")
roomAPI.Initialize(underworld, mapSaver.Load, mapSaver.Save, mapMaker.DebugGrassland, mapSaver.Save)
--call the monstrosity
doorUtility.createDoorPair("pair 1", overworld, -64, -64, underworld, 64, 64)
+65 -12
View File
@@ -1,8 +1,28 @@
--TODO: (9) An archive table of all dead characters /* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
CREATE TABLE IF NOT EXISTS Accounts ( CREATE TABLE IF NOT EXISTS UserAccounts (
uid INTEGER PRIMARY KEY AUTOINCREMENT, uid INTEGER PRIMARY KEY AUTOINCREMENT,
username varchar(100) UNIQUE, --TODO: (9) Swap username for email address username varchar(100) UNIQUE, --TODO: (3) Swap username for email address
--server-client security --server-client security
-- passhash varchar(100), -- passhash varchar(100),
@@ -15,7 +35,7 @@ CREATE TABLE IF NOT EXISTS Accounts (
admin BIT DEFAULT 0 admin BIT DEFAULT 0
); );
CREATE TABLE IF NOT EXISTS Characters ( CREATE TABLE IF NOT EXISTS LiveCharacters (
uid INTEGER PRIMARY KEY AUTOINCREMENT, uid INTEGER PRIMARY KEY AUTOINCREMENT,
--metadata --metadata
@@ -24,19 +44,52 @@ CREATE TABLE IF NOT EXISTS Characters (
avatar varchar(100), avatar varchar(100),
birth timestamp NOT NULL DEFAULT (datetime()), birth timestamp NOT NULL DEFAULT (datetime()),
--position in the world --physically exists in the world
roomIndex INTEGER DEFAULT 0, roomIndex INTEGER DEFAULT 0,
originX INTEGER DEFAULT 0, originX INTEGER DEFAULT 0,
originY INTEGER DEFAULT 0, originY INTEGER DEFAULT 0,
boundsX INTEGER DEFAULT 0,
boundsY INTEGER DEFAULT 0,
boundsW INTEGER DEFAULT 0,
boundsH INTEGER DEFAULT 0
);
--statistics CREATE TABLE IF NOT EXISTS DeadCharacters (
baseStats INTEGER REFERENCES StatisticSets(uid), uid INTEGER PRIMARY KEY,
--equipment --metadata
weapon INTEGER REFERENCES WornEquipment(uid), owner INTEGER REFERENCES Accounts(uid),
helmet INTEGER REFERENCES WornEquipment(uid), handle varchar(100),
armour INTEGER REFERENCES WornEquipment(uid) avatar varchar(100),
--etc. birth timestamp NOT NULL
);
CREATE TABLE IF NOT EXISTS LiveMonsters (
uid INTEGER PRIMARY KEY AUTOINCREMENT,
--metadata
handle varchar(100) UNIQUE,
avatar varchar(100),
--actions
-- script
--physically exists in the world
roomIndex INTEGER DEFAULT 0,
originX INTEGER DEFAULT 0,
originY INTEGER DEFAULT 0,
boundsX INTEGER DEFAULT 0,
boundsY INTEGER DEFAULT 0,
boundsW INTEGER DEFAULT 0,
boundsH INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS DeadMonsters (
uid INTEGER PRIMARY KEY,
--metadata
handle varchar(100) UNIQUE,
avatar varchar(100)
); );
------------------------- -------------------------
+26 -10
View File
@@ -27,16 +27,32 @@
//Define the queries //Define the queries
//------------------------- //-------------------------
static const char* CREATE_USER_ACCOUNT = "INSERT INTO Accounts (username) VALUES (?);"; static const char* CREATE_USER_ACCOUNT = "INSERT INTO UserAccounts (username) VALUES (?);";
static const char* LOAD_USER_ACCOUNT = "SELECT * FROM Accounts WHERE username = ?;";
static const char* SAVE_USER_ACCOUNT = "UPDATE OR FAIL Accounts SET blacklisted = ?2, whitelisted = ?3, mod = ?4, admin = ?5 WHERE uid = ?1;"; static const char* LOAD_USER_ACCOUNT = "SELECT "
static const char* DELETE_USER_ACCOUNT = "DELETE FROM Accounts WHERE uid = ?;"; "uid, "
static const char* COUNT_USER_ACCOUNT_RECORDS = "SELECT COUNT(*) FROM Accounts;"; "blacklisted, "
"whitelisted, "
"mod, "
"admin "
" FROM UserAccounts WHERE username = ?;";
static const char* SAVE_USER_ACCOUNT = "UPDATE OR FAIL UserAccounts SET "
"blacklisted = ?2, "
"whitelisted = ?3, "
"mod = ?4, "
"admin = ?5 "
"WHERE uid = ?1;";
static const char* DELETE_USER_ACCOUNT = "DELETE FROM UserAccounts WHERE uid = ?;";
static const char* COUNT_USER_ACCOUNT_RECORDS = "SELECT COUNT(*) FROM UserAccounts;";
//------------------------- //-------------------------
//Define the public methods //Define the public methods
//------------------------- //-------------------------
//TODO: (1) block blacklisted accounts
int AccountManager::Create(std::string username, int clientIndex) { int AccountManager::Create(std::string username, int clientIndex) {
//create this user account, failing if it exists, leave this account in memory //create this user account, failing if it exists, leave this account in memory
sqlite3_stmt* statement = nullptr; sqlite3_stmt* statement = nullptr;
@@ -94,11 +110,11 @@ int AccountManager::Load(std::string username, int clientIndex) {
//extract the data into memory //extract the data into memory
AccountData& newAccount = elementMap[uid]; AccountData& newAccount = elementMap[uid];
newAccount.username = reinterpret_cast<const char*>(sqlite3_column_text(statement, 1)); newAccount.username = username;
newAccount.blackListed = sqlite3_column_int(statement, 2); newAccount.blackListed = sqlite3_column_int(statement, 1);
newAccount.whiteListed = sqlite3_column_int(statement, 3); newAccount.whiteListed = sqlite3_column_int(statement, 2);
newAccount.mod = sqlite3_column_int(statement, 4); newAccount.mod = sqlite3_column_int(statement, 3);
newAccount.admin = sqlite3_column_int(statement, 5); newAccount.admin = sqlite3_column_int(statement, 4);
newAccount.clientIndex = clientIndex; newAccount.clientIndex = clientIndex;
//finish the routine //finish the routine
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
+96
View File
@@ -22,12 +22,108 @@
#include "character_api.hpp" #include "character_api.hpp"
#include "character_data.hpp" #include "character_data.hpp"
#include "character_manager.hpp"
#include "entity_api.hpp"
#include "room_manager.hpp"
#include "server_utilities.hpp"
#include <stdexcept>
static int setRoom(lua_State* L) {
//reverse engineer the character index
int characterIndex = -1;
CharacterData* character = static_cast<CharacterData*>(lua_touserdata(L, 1));
CharacterManager& characterMgr = CharacterManager::GetSingleton();
for (auto& it : *characterMgr.GetContainer()) {
if (character == &it.second) {
characterIndex = it.first;
break;
}
}
//error checking
if (characterIndex == -1) {
throw(std::runtime_error("Lua Error: Failed to find character index by reference"));
}
//get the room index, depending on the parameter type
int roomIndex = -1;
RoomManager& roomMgr = RoomManager::GetSingleton();
switch(lua_type(L, 2)) {
case LUA_TNUMBER:
roomIndex = lua_tointeger(L, 2);
break;
case LUA_TLIGHTUSERDATA:
//reverse engineer the room index
for (auto& it : *roomMgr.GetContainer()) {
if (lua_touserdata(L, 2) == &it.second) {
roomIndex = it.first;
break;
}
}
break;
}
//error checking
if (roomIndex == -1) {
throw(std::runtime_error("Lua Error: Failed to find room index by reference"));
}
//send the delete & create messages
pumpAndChangeRooms(character, roomIndex, characterIndex);
return 0;
}
static int getOwner(lua_State* L) {
CharacterData* character = static_cast<CharacterData*>(lua_touserdata(L, 1));
lua_pushinteger(L, character->GetOwner());
return 1;
}
static int getHandle(lua_State* L) {
CharacterData* character = static_cast<CharacterData*>(lua_touserdata(L, 1));
lua_pushstring(L, character->GetHandle().c_str());
return 1;
}
static int getAvatar(lua_State* L) {
CharacterData* character = static_cast<CharacterData*>(lua_touserdata(L, 1));
lua_pushstring(L, character->GetAvatar().c_str());
return 1;
}
static const luaL_Reg characterLib[] = { static const luaL_Reg characterLib[] = {
{"SetRoom", setRoom},
// {"GetOwner", getOwner}, //unusable without account API
{"GetHandle", getHandle},
{"GetAvatar", getAvatar},
{nullptr, nullptr} {nullptr, nullptr}
}; };
LUAMOD_API int openCharacterAPI(lua_State* L) { LUAMOD_API int openCharacterAPI(lua_State* L) {
//get the parent table
luaL_requiref(L, TORTUGA_ENTITY_API, openEntityAPI, false);
//the local table
luaL_newlib(L, characterLib); luaL_newlib(L, characterLib);
//merge the local table into the parent table
lua_pushnil(L); //first key
while(lua_next(L, -2)) {
//copy the key-value pair
lua_pushvalue(L, -2);
lua_pushvalue(L, -2);
//push the copy to the parent table
lua_settable(L, -6);
//pop the original value before continuing
lua_pop(L, 1);
}
//remove the local table, leaving the expanded parent table
lua_pop(L, 1);
return 1; return 1;
} }
+4
View File
@@ -21,6 +21,10 @@
*/ */
#include "character_data.hpp" #include "character_data.hpp"
CharacterData::CharacterData(): Entity("character") {
//EMPTY
}
int CharacterData::GetOwner() { int CharacterData::GetOwner() {
return owner; return owner;
} }
+2 -5
View File
@@ -32,12 +32,9 @@
class CharacterData: public Entity { class CharacterData: public Entity {
public: public:
CharacterData() = default; CharacterData();
~CharacterData() = default; ~CharacterData() = default;
//accessors and mutators
//...
//database stuff //database stuff
int GetOwner(); int GetOwner();
std::string GetHandle(); std::string GetHandle();
@@ -46,7 +43,7 @@ public:
private: private:
friend class CharacterManager; friend class CharacterManager;
int owner; int owner = -1;
std::string handle; std::string handle;
std::string avatar; std::string avatar;
}; };
+69 -8
View File
@@ -23,18 +23,56 @@
#include "sqlite3.h" #include "sqlite3.h"
#include "character_defines.hpp"
#include <algorithm> #include <algorithm>
#include <cstring>
#include <stdexcept> #include <stdexcept>
//------------------------- //-------------------------
//Define the queries //Define the queries
//------------------------- //-------------------------
static const char* CREATE_CHARACTER = "INSERT INTO Characters (owner, handle, avatar) VALUES (?, ?, ?);"; //NOTE: Programmer set variables are NOT zero-indexed
static const char* LOAD_CHARACTER = "SELECT * FROM Characters WHERE handle = ?;"; //NOTE: SQLite3 returned variables (i.e. loading) ARE zero-indexed
static const char* SAVE_CHARACTER = "UPDATE OR FAIL Characters SET roomIndex = ?2, originX = ?3, originY = ?4 WHERE uid = ?1;";
static const char* DELETE_CHARACTER = "DELETE FROM Characters WHERE uid = ?;"; static const char* CREATE_CHARACTER = "INSERT INTO LiveCharacters ("
static const char* COUNT_CHARACTER_RECORDS = "SELECT COUNT(*) FROM Characters;"; "owner, "
"handle, "
"avatar, "
"boundsX, "
"boundsY, "
"boundsW, "
"boundsH"
") VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7);";
static const char* LOAD_CHARACTER = "SELECT "
"uid, "
"owner, "
"handle, "
"avatar, "
"roomIndex, "
"originX, "
"originY, "
"boundsX, "
"boundsY, "
"boundsW, "
"boundsH "
"FROM LiveCharacters WHERE handle = ?;";
static const char* SAVE_CHARACTER = "UPDATE OR FAIL LiveCharacters SET "
"roomIndex = ?2, "
"originX = ?3, "
"originY = ?4, "
"boundsX = ?5, "
"boundsY = ?6, "
"boundsW = ?7, "
"boundsH = ?8 "
"WHERE uid = ?1;";
static const char* DELETE_CHARACTER = "DELETE FROM LiveCharacters WHERE uid = ?;";
static const char* COUNT_CHARACTER_RECORDS = "SELECT COUNT(*) FROM LiveCharacters;";
//------------------------- //-------------------------
//Define the methods //Define the methods
@@ -55,6 +93,10 @@ int CharacterManager::Create(int owner, std::string handle, std::string avatar)
ret |= sqlite3_bind_int(statement, 1, owner); ret |= sqlite3_bind_int(statement, 1, owner);
ret |= sqlite3_bind_text(statement, 2, handle.c_str(), handle.size() + 1, SQLITE_STATIC); ret |= sqlite3_bind_text(statement, 2, handle.c_str(), handle.size() + 1, SQLITE_STATIC);
ret |= sqlite3_bind_text(statement, 3, avatar.c_str(), avatar.size() + 1, SQLITE_STATIC); ret |= sqlite3_bind_text(statement, 3, avatar.c_str(), avatar.size() + 1, SQLITE_STATIC);
ret |= sqlite3_bind_int(statement, 4, CHARACTER_BOUNDS_X);
ret |= sqlite3_bind_int(statement, 5, CHARACTER_BOUNDS_Y);
ret |= sqlite3_bind_int(statement, 6, CHARACTER_BOUNDS_WIDTH);
ret |= sqlite3_bind_int(statement, 7, CHARACTER_BOUNDS_HEIGHT);
//check for binding errors //check for binding errors
if (ret) { if (ret) {
@@ -121,9 +163,14 @@ int CharacterManager::Load(int owner, std::string handle, std::string avatar) {
//Don't cache the birth //Don't cache the birth
//world origin //world origin
newChar.roomIndex = sqlite3_column_int(statement, 5); newChar.roomIndex = sqlite3_column_int(statement, 4);
newChar.origin.x = (double)sqlite3_column_int(statement, 6); newChar.origin.x = (double)sqlite3_column_int(statement, 5);
newChar.origin.y = (double)sqlite3_column_int(statement, 7); newChar.origin.y = (double)sqlite3_column_int(statement, 6);
//bounds
newChar.bounds.x = (int)sqlite3_column_int(statement, 7);
newChar.bounds.y = (int)sqlite3_column_int(statement, 8);
newChar.bounds.w = (int)sqlite3_column_int(statement, 9);
newChar.bounds.h = (int)sqlite3_column_int(statement, 10);
//gameplay components: equipment, items, buffs, debuffs... //gameplay components: equipment, items, buffs, debuffs...
@@ -165,6 +212,10 @@ int CharacterManager::Save(int uid) {
ret |= sqlite3_bind_int(statement, 2, character.roomIndex) != SQLITE_OK; ret |= sqlite3_bind_int(statement, 2, character.roomIndex) != SQLITE_OK;
ret |= sqlite3_bind_int(statement, 3, (int)character.origin.x) != SQLITE_OK; ret |= sqlite3_bind_int(statement, 3, (int)character.origin.x) != SQLITE_OK;
ret |= sqlite3_bind_int(statement, 4, (int)character.origin.y) != SQLITE_OK; ret |= sqlite3_bind_int(statement, 4, (int)character.origin.y) != SQLITE_OK;
ret |= sqlite3_bind_int(statement, 5, character.bounds.x) != SQLITE_OK;
ret |= sqlite3_bind_int(statement, 6, character.bounds.y) != SQLITE_OK;
ret |= sqlite3_bind_int(statement, 7, character.bounds.w) != SQLITE_OK;
ret |= sqlite3_bind_int(statement, 8, character.bounds.h) != SQLITE_OK;
//gameplay components: equipment, items, buffs, debuffs... //gameplay components: equipment, items, buffs, debuffs...
@@ -193,6 +244,7 @@ void CharacterManager::Unload(int uid) {
} }
void CharacterManager::Delete(int uid) { void CharacterManager::Delete(int uid) {
//TODO: when deleting a character, move it to an archive table
//delete this character from the database, then remove it from memory //delete this character from the database, then remove it from memory
sqlite3_stmt* statement = nullptr; sqlite3_stmt* statement = nullptr;
@@ -252,6 +304,15 @@ CharacterData* CharacterManager::Get(int uid) {
return &it->second; return &it->second;
} }
CharacterData* CharacterManager::Get(std::string handle) {
for (std::map<int, CharacterData>::iterator it = elementMap.begin(); it != elementMap.end(); ++it) {
if (it->second.GetHandle() == handle) {
return &it->second;
}
}
return nullptr;
}
int CharacterManager::GetLoadedCount() { int CharacterManager::GetLoadedCount() {
return elementMap.size(); return elementMap.size();
} }
+5
View File
@@ -44,13 +44,18 @@ public:
//accessors and mutators //accessors and mutators
CharacterData* Get(int uid); CharacterData* Get(int uid);
CharacterData* Get(std::string handle);
int GetLoadedCount(); int GetLoadedCount();
int GetTotalCount(); int GetTotalCount();
std::map<int, CharacterData>* GetContainer(); std::map<int, CharacterData>* GetContainer();
//API interface
sqlite3* SetDatabase(sqlite3* db); sqlite3* SetDatabase(sqlite3* db);
sqlite3* GetDatabase(); sqlite3* GetDatabase();
//hooks
//TODO: character hooks
private: private:
friend Singleton<CharacterManager>; friend Singleton<CharacterManager>;
@@ -23,7 +23,88 @@
#include "character_manager.hpp" #include "character_manager.hpp"
#include <sstream>
#include <stdexcept>
//TODO: (1) character hooks?
static int setOnCreate(lua_State* L) {
//TODO: (9) setOnCreate()
}
static int setOnLoad(lua_State* L) {
//TODO: (9) setOnLoad()
}
static int setOnSave(lua_State* L) {
//TODO: (9) setOnSave()
}
static int setOnUnload(lua_State* L) {
//TODO: (9) setOnUnload()
}
static int setOnDelete(lua_State* L) {
//TODO: (9) setOnDelete()
}
static int getCharacter(lua_State* L) {
//integer vs name
CharacterManager& characterMgr = CharacterManager::GetSingleton();
CharacterData* characterData = nullptr;
switch(lua_type(L, 1)) {
case LUA_TNUMBER:
characterData = characterMgr.Get(lua_tointeger(L, 1));
break;
case LUA_TSTRING:
//access characters via their handles
characterData = characterMgr.Get(lua_tostring(L, 1));
break;
}
if (characterData) {
lua_pushlightuserdata(L, static_cast<void*>(characterData));
}
else {
lua_pushnil(L);
}
return 1;
}
static int getLoadedCount(lua_State* L) {
CharacterManager& characterMgr = CharacterManager::GetSingleton();
lua_pushinteger(L, characterMgr.GetLoadedCount());
return 1;
}
static int forEach(lua_State* L) {
CharacterManager& characterMgr = CharacterManager::GetSingleton();
//pass each character to the given function
for (auto& it : *characterMgr.GetContainer()) {
lua_pushvalue(L, -1);
lua_pushlightuserdata(L, static_cast<void*>(&it.second));
//call each iteration, throwing an exception if something happened
if (lua_pcall(L, 1, 0, 0) != LUA_OK) {
std::ostringstream os;
os << "Lua error: ";
os << lua_tostring(L, -1);
throw(std::runtime_error(os.str()));
}
}
return 0;
}
static const luaL_Reg characterManagerLib[] = { static const luaL_Reg characterManagerLib[] = {
// {"SetOnCreate", setOnCreate},
// {"SetOnLoad", setOnLoad},
// {"SetOnSave", setOnSave},
// {"SetOnUnload", setOnUnload},
// {"SetOnDelete", setOnDelete},
{"GetCharacter", getCharacter},
{"GetLoadedCount", getLoadedCount},
{"ForEach", forEach},
{nullptr, nullptr} {nullptr, nullptr}
}; };
+1 -6
View File
@@ -1,5 +1,5 @@
#config #config
INCLUDES+=. ../entities ../server_utilities ../../common/gameplay ../../common/utilities INCLUDES+=. ../entities ../monsters ../rooms ../server_utilities ../triggers ../../common/gameplay ../../common/map ../../common/network ../../common/network/packet_types ../../common/utilities
LIBS+= LIBS+=
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
+1 -1
View File
@@ -22,7 +22,7 @@
#ifndef CLIENTDATA_HPP_ #ifndef CLIENTDATA_HPP_
#define CLIENTDATA_HPP_ #define CLIENTDATA_HPP_
#include "SDL/SDL_net.h" #include "SDL_net.h"
#include <chrono> #include <chrono>
+8 -8
View File
@@ -21,11 +21,15 @@
*/ */
#include "client_manager.hpp" #include "client_manager.hpp"
#include "ip_operators.hpp"
#include "udp_network_utility.hpp" #include "udp_network_utility.hpp"
#include <chrono> #include <chrono>
int ClientManager::CheckConnections() { std::list<int> ClientManager::CheckConnections() {
//list of clients to disconnect
std::list<int> returnList;
for (auto& it : elementMap) { for (auto& it : elementMap) {
//3 seconds between beats //3 seconds between beats
if (ClientData::Clock::now() - it.second.GetLastBeat() > std::chrono::seconds(3)) { if (ClientData::Clock::now() - it.second.GetLastBeat() > std::chrono::seconds(3)) {
@@ -38,21 +42,17 @@ int ClientManager::CheckConnections() {
for (auto& it : elementMap) { for (auto& it : elementMap) {
if (it.second.GetAttempts() > 2) { if (it.second.GetAttempts() > 2) {
int ret = it.first; returnList.push_back(it.first);
// elementMap.erase(it.first);
return ret;
} }
} }
return -1; return returnList;
} }
void ClientManager::HandlePong(ServerPacket* const argPacket) { void ClientManager::HandlePong(ServerPacket* const argPacket) {
//find and update the specified client //find and update the specified client
for (auto& it : elementMap) { for (auto& it : elementMap) {
if (it.second.GetAddress().host == argPacket->srcAddress.host && if (it.second.GetAddress() == argPacket->srcAddress) {
it.second.GetAddress().port == argPacket->srcAddress.port
) {
it.second.ResetAttempts(); it.second.ResetAttempts();
return; return;
} }
+3 -2
View File
@@ -26,15 +26,16 @@
#include "server_packet.hpp" #include "server_packet.hpp"
#include "singleton.hpp" #include "singleton.hpp"
#include "SDL/SDL_net.h" #include "SDL_net.h"
#include <functional> #include <functional>
#include <list>
#include <map> #include <map>
class ClientManager: public Singleton<ClientManager> { class ClientManager: public Singleton<ClientManager> {
public: public:
//methods //methods
int CheckConnections(); std::list<int> CheckConnections();
void HandlePong(ServerPacket* const argPacket); void HandlePong(ServerPacket* const argPacket);
//common public methods //common public methods
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
+20
View File
@@ -21,6 +21,14 @@
*/ */
#include "entity.hpp" #include "entity.hpp"
Entity::Entity(const char* _type): type(_type) {
//EMPTY
}
void Entity::Update() {
origin += motion;
}
int Entity::SetRoomIndex(int i) { int Entity::SetRoomIndex(int i) {
return roomIndex = i; return roomIndex = i;
} }
@@ -33,6 +41,10 @@ Vector2 Entity::SetMotion(Vector2 v) {
return motion = v; return motion = v;
} }
BoundingBox Entity::SetBounds(BoundingBox b) {
return bounds = b;
}
int Entity::GetRoomIndex() const { int Entity::GetRoomIndex() const {
return roomIndex; return roomIndex;
} }
@@ -43,4 +55,12 @@ Vector2 Entity::GetOrigin() const {
Vector2 Entity::GetMotion() const { Vector2 Entity::GetMotion() const {
return motion; return motion;
}
BoundingBox Entity::GetBounds() const {
return bounds;
}
const char* Entity::GetType() const {
return type;
} }
+14 -3
View File
@@ -22,27 +22,38 @@
#ifndef ENTITY_HPP_ #ifndef ENTITY_HPP_
#define ENTITY_HPP_ #define ENTITY_HPP_
#include "bounding_box.hpp"
#include "vector2.hpp" #include "vector2.hpp"
#include <string>
//The base class for all objects in the world //The base class for all objects in the world
class Entity { class Entity {
public: public:
virtual void Update();
//accessors & mutators //accessors & mutators
int SetRoomIndex(int i); int SetRoomIndex(int i);
Vector2 SetOrigin(Vector2 v); Vector2 SetOrigin(Vector2 v);
Vector2 SetMotion(Vector2 v); Vector2 SetMotion(Vector2 v);
BoundingBox SetBounds(BoundingBox b);
int GetRoomIndex() const; int GetRoomIndex() const;
Vector2 GetOrigin() const; Vector2 GetOrigin() const;
Vector2 GetMotion() const; Vector2 GetMotion() const;
BoundingBox GetBounds() const;
const char* GetType() const;
protected: protected:
Entity() = default; Entity(const char* type);
virtual ~Entity() = default; virtual ~Entity() = default;
int roomIndex = -1; int roomIndex = -1;
Vector2 origin; Vector2 origin = {0, 0};
Vector2 motion; Vector2 motion = {0, 0};
BoundingBox bounds = {0, 0, 0, 0};
const char* type;
}; };
#endif #endif
+31 -2
View File
@@ -41,6 +41,17 @@ static int setMotion(lua_State* L) {
return 0; return 0;
} }
static int setBounds(lua_State* L) {
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
entity->SetBounds({
lua_tointeger(L, 2),
lua_tointeger(L, 3),
lua_tointeger(L, 4),
lua_tointeger(L, 5)
});
return 0;
}
static int getRoomIndex(lua_State* L) { static int getRoomIndex(lua_State* L) {
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1)); Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
lua_pushinteger(L, entity->GetRoomIndex()); lua_pushinteger(L, entity->GetRoomIndex());
@@ -56,18 +67,36 @@ static int getOrigin(lua_State* L) {
static int getMotion(lua_State* L) { static int getMotion(lua_State* L) {
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1)); Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
lua_pushnumber(L, entity->GetOrigin().x); lua_pushnumber(L, entity->GetMotion().x);
lua_pushnumber(L, entity->GetOrigin().y); lua_pushnumber(L, entity->GetMotion().y);
return 2; return 2;
} }
static int getBounds(lua_State* L) {
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
lua_pushinteger(L, entity->GetBounds().x);
lua_pushinteger(L, entity->GetBounds().y);
lua_pushinteger(L, entity->GetBounds().w);
lua_pushinteger(L, entity->GetBounds().h);
return 4;
}
static int getType(lua_State* L) {
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 1));
lua_pushstring(L, entity->GetType());
return 1;
}
static const luaL_Reg entityLib[] = { static const luaL_Reg entityLib[] = {
{"SetRoomIndex", setRoomIndex}, {"SetRoomIndex", setRoomIndex},
{"SetOrigin", setOrigin}, {"SetOrigin", setOrigin},
{"SetMotion", setMotion}, {"SetMotion", setMotion},
{"SetBounds", setBounds},
{"GetRoomIndex", getRoomIndex}, {"GetRoomIndex", getRoomIndex},
{"GetOrigin", getOrigin}, {"GetOrigin", getOrigin},
{"GetMotion", getMotion}, {"GetMotion", getMotion},
{"GetBounds", getBounds},
{"GetType", getType},
{nullptr, nullptr} {nullptr, nullptr}
}; };
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
+23 -10
View File
@@ -37,10 +37,17 @@
#include "lua.hpp" #include "lua.hpp"
#include "entity_api.hpp" #include "entity_api.hpp"
#include "map_system_api.hpp" #include "character_api.hpp"
#include "monster_system_api.hpp" #include "character_manager_api.hpp"
#include "room_system_api.hpp" #include "region_api.hpp"
#include "waypoint_system_api.hpp" #include "region_pager_api.hpp"
//#include "monster_api.hpp"
//#include "monster_manager_api.hpp"
#include "network_api.hpp"
#include "room_api.hpp"
#include "room_manager_api.hpp"
#include "trigger_api.hpp"
#include "trigger_manager_api.hpp"
//these libs are loaded by lua.c and are readily available to any Lua program //these libs are loaded by lua.c and are readily available to any Lua program
static const luaL_Reg loadedlibs[] = { static const luaL_Reg loadedlibs[] = {
@@ -58,14 +65,20 @@ static const luaL_Reg loadedlibs[] = {
{NULL, NULL} {NULL, NULL}
}; };
//these libs are preloaded and must be required before used //these libs are preloaded and must be required before used
static const luaL_Reg preloadedlibs[] = { static const luaL_Reg preloadedlibs[] = {
{TORTUGA_ENTITY_API, openEntityAPI}, {TORTUGA_ENTITY_API, openEntityAPI}, //required by derived classes
{TORTUGA_MAP_SYSTEM_API, openMapSystemAPI}, {TORTUGA_CHARACTER_API, openCharacterAPI},
{TORTUGA_MONSTER_SYSTEM_API, openMonsterSystemAPI}, {TORTUGA_CHARACTER_MANAGER_API, openCharacterManagerAPI},
{TORTUGA_ROOM_SYSTEM_API, openRoomSystemAPI}, // {TORTUGA_MONSTER_API, openMonsterAPI},
{TORTUGA_WAYPOINT_SYSTEM_API, openWaypointSystemAPI}, // {TORTUGA_MONSTER_MANAGER_API, openMonsterManagerAPI},
{TORTUGA_NETWORK_API, openNetworkAPI},
{TORTUGA_REGION_API, openRegionAPI},
{TORTUGA_REGION_PAGER_API, openRegionPagerAPI},
{TORTUGA_ROOM_API, openRoomAPI},
{TORTUGA_ROOM_MANAGER_API, openRoomManagerAPI},
{TORTUGA_TRIGGER_API, openTriggerAPI},
{TORTUGA_TRIGGER_MANAGER_API, openTriggerManagerAPI},
{NULL, NULL} {NULL, NULL}
}; };
-1
View File
@@ -28,7 +28,6 @@
#include "config_utility.hpp" #include "config_utility.hpp"
#include "room_manager.hpp" #include "room_manager.hpp"
#include "udp_network_utility.hpp" #include "udp_network_utility.hpp"
#include "waypoint_manager.hpp"
#include <stdexcept> #include <stdexcept>
#include <iostream> #include <iostream>
+13 -3
View File
@@ -1,5 +1,5 @@
#include directories #include directories
INCLUDES+=. accounts characters clients entities monsters rooms server_utilities waypoints ../common/debugging ../common/gameplay ../common/map ../common/network ../common/network/packet_types ../common/utilities INCLUDES+=SDL . accounts characters clients entities rooms server_utilities triggers ../common/debugging ../common/gameplay ../common/map ../common/network ../common/network/packet_types ../common/utilities
#libraries #libraries
#the order of the $(LIBS) is important, at least for MinGW #the order of the $(LIBS) is important, at least for MinGW
@@ -8,6 +8,10 @@ ifeq ($(OS),Windows_NT)
LIBS+=-lwsock32 -liphlpapi -lmingw32 LIBS+=-lwsock32 -liphlpapi -lmingw32
endif endif
LIBS+=-lSDLmain -lSDL -llua -lsqlite3 LIBS+=-lSDLmain -lSDL -llua -lsqlite3
ifeq ($(shell uname), Linux)
#I don't know what this does, but Ubuntu needs it
LIBS+=-ldl
endif
#flags #flags
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
@@ -29,10 +33,10 @@ all: $(OBJ) $(OUT)
$(MAKE) -C characters $(MAKE) -C characters
$(MAKE) -C clients $(MAKE) -C clients
$(MAKE) -C entities $(MAKE) -C entities
$(MAKE) -C monsters # $(MAKE) -C monsters
$(MAKE) -C rooms $(MAKE) -C rooms
$(MAKE) -C server_utilities $(MAKE) -C server_utilities
$(MAKE) -C waypoints $(MAKE) -C triggers
$(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS) $(CXX) $(CXXFLAGS) -o $(OUT) $(OBJ) $(LIBS)
$(OBJ): | $(OBJDIR) $(OBJ): | $(OBJDIR)
@@ -49,6 +53,12 @@ $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean: clean:
ifeq ($(OS),Windows_NT)
$(RM) *.o *.a *.exe $(RM) *.o *.a *.exe
else ifeq ($(shell uname), Linux)
find . -type f -name *.o -exec rm -f -r -v {} \;
find . -type f -name *.a -exec rm -f -r -v {} \;
rm -f -v out/client out/server
endif
rebuild: clean all rebuild: clean all
-5
View File
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
+7 -7
View File
@@ -28,7 +28,7 @@
static int setAvatar(lua_State* L) { static int setAvatar(lua_State* L) {
MonsterData* monster = static_cast<MonsterData*>(lua_touserdata(L, 1)); MonsterData* monster = static_cast<MonsterData*>(lua_touserdata(L, 1));
monster->SetAvatar(lua_tostring(L, 2)); monster->SetAvatar(lua_tostring(L, 2));
//TODO: send an update to the clients? //TODO: (1) send an update to the clients?
return 0; return 0;
} }
@@ -61,27 +61,27 @@ static const luaL_Reg monsterLib[] = {
}; };
LUAMOD_API int openMonsterAPI(lua_State* L) { LUAMOD_API int openMonsterAPI(lua_State* L) {
//the local table
luaL_newlib(L, monsterLib);
//get the parent table //get the parent table
luaL_requiref(L, TORTUGA_ENTITY_API, openEntityAPI, false); luaL_requiref(L, TORTUGA_ENTITY_API, openEntityAPI, false);
//clone the parent table into the local table //the local table
luaL_newlib(L, monsterLib);
//merge the local table into the parent table
lua_pushnil(L); //first key lua_pushnil(L); //first key
while(lua_next(L, -2)) { while(lua_next(L, -2)) {
//copy the key-value pair //copy the key-value pair
lua_pushvalue(L, -2); lua_pushvalue(L, -2);
lua_pushvalue(L, -2); lua_pushvalue(L, -2);
//push the copy to the local table //push the copy to the parent table
lua_settable(L, -6); lua_settable(L, -6);
//pop the original value before continuing //pop the original value before continuing
lua_pop(L, 1); lua_pop(L, 1);
} }
//remove the parent table, leaving the expanded child table //remove the local table, leaving the expanded parent table
lua_pop(L, 1); lua_pop(L, 1);
return 1; return 1;
+17
View File
@@ -21,6 +21,23 @@
*/ */
#include "monster_data.hpp" #include "monster_data.hpp"
MonsterData::MonsterData(std::string _avatar, int _scriptRef):
Entity("monster"),
avatar(_avatar),
scriptRef(_scriptRef)
{
//EMPTY
}
void MonsterData::Update() {
Entity::Update();
//TODO: (0) call the script reference
}
//-------------------------
//accessors & mutators
//-------------------------
std::string MonsterData::SetAvatar(std::string s) { std::string MonsterData::SetAvatar(std::string s) {
return avatar = s; return avatar = s;
} }
+15 -2
View File
@@ -24,13 +24,26 @@
#include "entity.hpp" #include "entity.hpp"
#include "lua.hpp"
#include <string> #include <string>
/* DOCS: Monster attributes, read more
* species (avatar, script)
* level
* health/mana
* permadeath/respawn
*/
class MonsterData: public Entity { class MonsterData: public Entity {
public: public:
MonsterData() = default; MonsterData(std::string avatar, int scriptRef);
~MonsterData() = default; ~MonsterData() = default;
virtual void Update();
//accessors & mutators
std::string SetAvatar(std::string); std::string SetAvatar(std::string);
std::string GetAvatar(); std::string GetAvatar();
@@ -41,7 +54,7 @@ private:
friend class MonsterManager; friend class MonsterManager;
std::string avatar; std::string avatar;
int scriptRef; int scriptRef = LUA_NOREF;
}; };
#endif #endif
+32 -12
View File
@@ -29,46 +29,66 @@ MonsterManager::~MonsterManager() {
UnloadAll(); UnloadAll();
} }
int MonsterManager::Create(std::string) { int MonsterManager::Create(std::string avatar, int scriptRef) {
//Create //implicitly create the new
elementMap.emplace(counter, MonsterData(avatar, scriptRef));
//TODO: do various things like saving to the database
return counter++;
} }
//TODO: (1) monster load, save
void MonsterManager::Unload(int uid) { void MonsterManager::Unload(int uid) {
//Unload elementMap.erase(uid);
} }
void MonsterManager::UnloadAll() { void MonsterManager::UnloadAll() {
//UnloadAll elementMap.clear();
} }
void MonsterManager::UnloadIf(std::function<bool(std::pair<const int, MonsterData const&>)> fn) { void MonsterManager::UnloadIf(std::function<bool(std::pair<const int, MonsterData const&>)> fn) {
//UnloadIf std::map<int, MonsterData>::iterator it = elementMap.begin();
while (it != elementMap.end()) {
if (fn(*it)) {
it = elementMap.erase(it);
}
else {
++it;
}
}
} }
MonsterData* MonsterManager::Get(int uid) { MonsterData* MonsterManager::Get(int uid) {
//Get std::map<int, MonsterData>::iterator it = elementMap.find(uid);
if (it == elementMap.end()) {
return nullptr;
}
return &it->second;
} }
int MonsterManager::GetLoadedCount() { int MonsterManager::GetLoadedCount() {
//GetLoadedCount return elementMap.size();
} }
std::map<int, MonsterData>* MonsterManager::GetContainer() { std::map<int, MonsterData>* MonsterManager::GetContainer() {
//GetContainer return &elementMap;
} }
lua_State* MonsterManager::SetLuaState(lua_State* L) { lua_State* MonsterManager::SetLuaState(lua_State* L) {
//SetLuaState return lua = L;
} }
lua_State* MonsterManager::GetLuaState() { lua_State* MonsterManager::GetLuaState() {
//GetLuaState return lua;
} }
sqlite3* MonsterManager::SetDatabase(sqlite3* db) { sqlite3* MonsterManager::SetDatabase(sqlite3* db) {
//SetDatabase return database = db;
} }
sqlite3* MonsterManager::GetDatabase() { sqlite3* MonsterManager::GetDatabase() {
//GetDatabase return database;
} }
+2 -1
View File
@@ -37,7 +37,7 @@ public:
~MonsterManager(); ~MonsterManager();
//common public methods //common public methods
int Create(std::string); int Create(std::string avatar, int scriptRef);
void Unload(int uid); void Unload(int uid);
void UnloadAll(); void UnloadAll();
@@ -57,6 +57,7 @@ public:
private: private:
//members //members
std::map<int, MonsterData> elementMap; std::map<int, MonsterData> elementMap;
int counter = 0;
lua_State* lua = nullptr; lua_State* lua = nullptr;
sqlite3* database = nullptr; sqlite3* database = nullptr;
}; };
+47
View File
@@ -23,7 +23,54 @@
#include "monster_manager.hpp" #include "monster_manager.hpp"
static int create(lua_State* L) {
MonsterManager* mgr = static_cast<MonsterManager* const>(lua_touserdata(L, 1));
int index = mgr->Create(lua_tostring(L, 2), lua_tointeger(L, 3));
MonsterData* monster = mgr->Get(index);
lua_pushlightuserdata(L, static_cast<void*>(monster));
lua_pushinteger(L, index);
return 2;
}
//TOOD: this needs to take the userdata as a parameter too
static int unload(lua_State* L) {
MonsterManager* mgr = static_cast<MonsterManager* const>(lua_touserdata(L, 1));
mgr->Unload(lua_tointeger(L, 2));
return 0;
}
static int unloadAll(lua_State* L) {
MonsterManager* mgr = static_cast<MonsterManager* const>(lua_touserdata(L, 1));
mgr->UnloadAll();
return 0;
}
static int unloadIf(lua_State* L) {
MonsterManager* mgr = static_cast<MonsterManager* const>(lua_touserdata(L, 1));
//TODO: unloadIf
return 0;
}
static int get(lua_State* L) {
MonsterManager* mgr = static_cast<MonsterManager* const>(lua_touserdata(L, 1));
MonsterData* monster = mgr->Get(lua_tointeger(L, 2));
lua_pushlightuserdata(L, static_cast<void*>(monster));
return 1;
}
static int getLoadedCount(lua_State* L) {
MonsterManager* mgr = static_cast<MonsterManager* const>(lua_touserdata(L, 1));
lua_pushinteger(L, mgr->GetLoadedCount());
return 1;
}
static const luaL_Reg monsterManagerLib[] = { static const luaL_Reg monsterManagerLib[] = {
{"Create", create},
{"Unload", unload},
{"UnloadAll", unloadAll},
// {"UnloadIf", unloadIf},
{"Get", get},
{"GetLoadedCount", getLoadedCount},
{nullptr, nullptr} {nullptr, nullptr}
}; };
-55
View File
@@ -1,55 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "monster_system_api.hpp"
//all monster API headers
#include "monster_api.hpp"
#include "monster_manager_api.hpp"
//useful "globals"
//...
//This mimics linit.c to create a nested collection of all monster modules.
static const luaL_Reg funcs[] = {
{nullptr, nullptr}
};
static const luaL_Reg libs[] = {
{"Monster", openMonsterAPI},
{"MonsterManager", openMonsterManagerAPI},
{nullptr, nullptr}
};
int openMonsterSystemAPI(lua_State* L) {
//create the table
luaL_newlibtable(L, libs);
//push the "global" functions
luaL_setfuncs(L, funcs, 0);
//push the substable
for (const luaL_Reg* lib = libs; lib->func; lib++) {
lib->func(L);
lua_setfield(L, -2, lib->name);
}
return 1;
}
+1 -6
View File
@@ -1,5 +1,5 @@
#config #config
INCLUDES+=. ../characters ../entities ../monsters ../server_utilities ../waypoints ../../common/gameplay ../../common/map ../../common/utilities INCLUDES+=. ../characters ../entities ../monsters ../server_utilities ../triggers ../../common/gameplay ../../common/map ../../common/utilities
LIBS+= LIBS+=
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
+65 -4
View File
@@ -23,6 +23,9 @@
#include "room_data.hpp" #include "room_data.hpp"
#include <sstream>
#include <stdexcept>
static int setRoomName(lua_State* L) { static int setRoomName(lua_State* L) {
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1)); RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
room->SetName(lua_tostring(L, 2)); room->SetName(lua_tostring(L, 2));
@@ -53,15 +56,67 @@ static int getPager(lua_State* L) {
return 1; return 1;
} }
/*
static int getMonsterMgr(lua_State* L) { static int getMonsterMgr(lua_State* L) {
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1)); RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
lua_pushlightuserdata(L, reinterpret_cast<void*>(room->GetMonsterMgr()) ); lua_pushlightuserdata(L, reinterpret_cast<void*>(room->GetMonsterMgr()) );
return 1; return 1;
} }
*/
static int getWaypointMgr(lua_State* L) { static int getTriggerMgr(lua_State* L) {
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1)); RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
lua_pushlightuserdata(L, reinterpret_cast<void*>(room->GetWaypointMgr()) ); lua_pushlightuserdata(L, reinterpret_cast<void*>(room->GetTriggerMgr()) );
return 1;
}
static int forEachCharacter(lua_State* L) {
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
//pass each character to the given function
for (auto& it : *room->GetCharacterList()) {
lua_pushvalue(L, -1);
lua_pushlightuserdata(L, static_cast<void*>(it));
//call each iteration, throwing an exception if something happened
if (lua_pcall(L, 1, 0, 0) != LUA_OK) {
std::ostringstream os;
os << "Lua error: ";
os << lua_tostring(L, -1);
throw(std::runtime_error(os.str()));
}
}
return 0;
}
/*
static int forEachMonster(lua_State* L) {
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
MonsterManager* monsterMgr = room->GetMonsterMgr();
//pass each monster to the given function
for (auto& it : *monsterMgr->GetContainer()) {
lua_pushvalue(L, -1);
lua_pushlightuserdata(L, static_cast<void*>(&it.second));
//call each iteration, throwing an exception if something happened
if (lua_pcall(L, 1, 0, 0) != LUA_OK) {
std::ostringstream os;
os << "Lua error: ";
os << lua_tostring(L, -1);
throw(std::runtime_error(os.str()));
}
}
return 0;
}
*/
static int setOnTick(lua_State* L) {
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
luaL_unref(L, LUA_REGISTRYINDEX, room->GetTickReference());
room->SetTickReference(luaL_ref(L, LUA_REGISTRYINDEX));
return 0;
}
static int getOnTick(lua_State* L) {
RoomData* room = reinterpret_cast<RoomData*>(lua_touserdata(L, 1));
lua_rawgeti(L, LUA_REGISTRYINDEX, room->GetTickReference());
return 1; return 1;
} }
@@ -85,8 +140,14 @@ static const luaL_Reg roomLib[] = {
{"GetTileset", getTilesetName}, {"GetTileset", getTilesetName},
{"GetPager",getPager}, {"GetPager",getPager},
{"GetMonsterMgr",getMonsterMgr}, // {"GetMonsterMgr",getMonsterMgr},
{"GetWaypointMgr",getWaypointMgr}, {"GetTriggerMgr",getTriggerMgr},
{"ForEachCharacter", forEachCharacter},
// {"ForEachMonster", forEachMonster},
{"SetOnTick", setOnTick},
{"GetOnTick", getOnTick},
{"Initialize", initialize}, {"Initialize", initialize},
{nullptr, nullptr} {nullptr, nullptr}
+111 -6
View File
@@ -21,6 +21,87 @@
*/ */
#include "room_data.hpp" #include "room_data.hpp"
#include <algorithm>
#include <iostream>
#include <stack>
#include <stdexcept>
//TODO: (9) character collisions should be preformed client-side
void RoomData::RunFrame() {
//get the hook
lua_rawgeti(lua, LUA_REGISTRYINDEX, tickRef);
if (!lua_isnil(lua, -1)) {
//call the tick function, with this as a parameter
lua_pushlightuserdata(lua, this);
if (lua_pcall(lua, 1, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) ));
}
}
else {
lua_pop(lua, 1);
}
//update the entities in the room
for (auto& it : characterList) {
it->Update();
}
//TODO: (3) iterate through the monster map
//TODO: (3) trigger script for monsters
//build a list of game entities
std::stack<Entity*> entityStack;
for (auto& it : characterList) {
entityStack.push(it);
}
//TODO: (3) push the monster entities
//compare the triggers to the entities, using their real hitboxes
//NOTE: this stack solution should prevent problems when modifying the various lists
while(entityStack.size()) {
//get the entity & hitbox
Entity* entity = entityStack.top();
BoundingBox entityBox = entity->GetBounds() + entity->GetOrigin();
//get the trigger pair & hitbox
for (auto& triggerPair : *triggerMgr.GetContainer()) {
BoundingBox triggerBox = triggerPair.second.GetBoundingBox() + triggerPair.second.GetOrigin();
//find all collisions
if (entityBox.CheckOverlap(triggerBox)) {
//skip members of the exclusion list
if (std::any_of(triggerPair.second.GetExclusionList()->begin(), triggerPair.second.GetExclusionList()->end(), [entity](Entity* ptr) -> bool {
return entity == ptr;
})) {
continue;
}
//run the trigger script
lua_rawgeti(lua, LUA_REGISTRYINDEX, triggerPair.second.GetScriptReference());
lua_pushlightuserdata(lua, entity);
if (lua_pcall(lua, 1, 0, 0) != LUA_OK) {
//error
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) ));
}
//push to the exclusion list
triggerPair.second.GetExclusionList()->push_back(entity);
}
else {
//remove members of the exclusion list
//NOTE: characters in different rooms won't be removed, but that shouldn't be a problem
triggerPair.second.GetExclusionList()->remove_if([entity](Entity* ptr) -> bool {
return entity == ptr;
});
}
}
//next
entityStack.pop();
}
}
std::string RoomData::SetName(std::string s) { std::string RoomData::SetName(std::string s) {
return roomName = s; return roomName = s;
} }
@@ -41,14 +122,38 @@ RegionPagerLua* RoomData::GetPager() {
return &pager; return &pager;
} }
MonsterManager* RoomData::GetMonsterMgr() { TriggerManager* RoomData::GetTriggerMgr() {
return &monsterMgr; return &triggerMgr;
}
WaypointManager* RoomData::GetWaypointMgr() {
return &waypointMgr;
} }
std::list<CharacterData*>* RoomData::GetCharacterList() { std::list<CharacterData*>* RoomData::GetCharacterList() {
return &characterList; return &characterList;
} }
lua_State* RoomData::SetLuaState(lua_State* L) {
lua = L;
pager.SetLuaState(lua);
triggerMgr.SetLuaState(lua);
return lua;
}
lua_State* RoomData::GetLuaState() {
return lua;
}
sqlite3* RoomData::SetDatabase(sqlite3* db) {
database = db;
return database;
}
sqlite3* RoomData::GetDatabase() {
return database;
}
int RoomData::SetTickReference(int i) {
return tickRef = i;
}
int RoomData::GetTickReference() {
return tickRef;
}
+25 -10
View File
@@ -23,11 +23,11 @@
#define ROOMDATA_HPP_ #define ROOMDATA_HPP_
#include "character_data.hpp" #include "character_data.hpp"
#include "monster_manager.hpp"
#include "region_pager_lua.hpp" #include "region_pager_lua.hpp"
#include "waypoint_manager.hpp" #include "trigger_manager.hpp"
#include "lua.hpp" #include "lua.hpp"
#include "sqlite3.h"
#include <list> #include <list>
#include <string> #include <string>
@@ -37,6 +37,8 @@ public:
RoomData() = default; RoomData() = default;
~RoomData() = default; ~RoomData() = default;
void RunFrame();
//accessors and mutators //accessors and mutators
std::string SetName(std::string); std::string SetName(std::string);
std::string GetName(); std::string GetName();
@@ -45,23 +47,36 @@ public:
std::string GetTileset(); std::string GetTileset();
RegionPagerLua* GetPager(); RegionPagerLua* GetPager();
MonsterManager* GetMonsterMgr(); TriggerManager* GetTriggerMgr();
WaypointManager* GetWaypointMgr();
std::list<CharacterData*>* GetCharacterList(); std::list<CharacterData*>* GetCharacterList();
//TODO: triggers for unload, save, per-second, player enter, player exit, etc. //API interfaces
lua_State* SetLuaState(lua_State* L);
lua_State* GetLuaState();
sqlite3* SetDatabase(sqlite3* db);
sqlite3* GetDatabase();
//hooks
int SetTickReference(int i);
int GetTickReference();
//TODO: other triggers like player entry & exit, etc.
private: private:
friend class RoomManager; //metadata
//members
std::string roomName; std::string roomName;
std::string tilesetName; std::string tilesetName;
//members
RegionPagerLua pager; RegionPagerLua pager;
MonsterManager monsterMgr; TriggerManager triggerMgr;
WaypointManager waypointMgr;
std::list<CharacterData*> characterList; std::list<CharacterData*> characterList;
//API
lua_State* lua = nullptr;
sqlite3* database = nullptr;
//hooks
int tickRef = LUA_NOREF;
}; };
#endif #endif
+82 -8
View File
@@ -35,29 +35,79 @@ int RoomManager::Create(std::string roomName, std::string tileset) {
newRoom->SetName(roomName); newRoom->SetName(roomName);
newRoom->SetTileset(tileset); newRoom->SetTileset(tileset);
newRoom->pager.SetLuaState(lua); newRoom->SetLuaState(lua);
newRoom->monsterMgr.SetLuaState(lua); newRoom->SetDatabase(database);
newRoom->monsterMgr.SetDatabase(database);
newRoom->waypointMgr.SetLuaState(lua); //get the hook
lua_rawgeti(lua, LUA_REGISTRYINDEX, createRef);
if(!lua_isnil(lua, -1)) {
lua_pushlightuserdata(lua, newRoom);
lua_pushinteger(lua, counter);
//call the function, 2 arg, 0 return
if (lua_pcall(lua, 2, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) ));
}
}
//finish the routine //finish the routine
return counter++; return counter++;
} }
void RoomManager::UnloadAll() { void RoomManager::UnloadAll() {
//get the hook
lua_rawgeti(lua, LUA_REGISTRYINDEX, unloadRef);
if(!lua_isnil(lua, -1)) {
//pass each room to the hook
for (auto& it : elementMap) {
lua_pushvalue(lua, -1); //copy the hook
lua_pushlightuserdata(lua, &it.second);
lua_pushinteger(lua, it.first);
//call the function, 2 arg, 0 return
if (lua_pcall(lua, 2, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) ));
}
}
}
//pop the hook or nil
lua_pop(lua, 1);
elementMap.clear(); elementMap.clear();
} }
void RoomManager::UnloadIf(std::function<bool(std::pair<const int, RoomData const&>)> fn) { void RoomManager::UnloadIf(std::function<bool(std::pair<const int, RoomData const&>)> fn) {
//get the hook
lua_rawgeti(lua, LUA_REGISTRYINDEX, unloadRef);
//get the element
std::map<int, RoomData>::iterator it = elementMap.begin(); std::map<int, RoomData>::iterator it = elementMap.begin();
//jenky pattern
while (it != elementMap.end()) { while (it != elementMap.end()) {
if (fn(*it)) { if (fn(*it)) {
if(!lua_isnil(lua, -1)) {
lua_pushvalue(lua, -1); //copy the hook
lua_pushlightuserdata(lua, &it->second);
lua_pushinteger(lua, it->first);
//call the function, 2 arg, 0 return
if (lua_pcall(lua, 2, 0, 0) != LUA_OK) {
throw(std::runtime_error(std::string() + "Lua error: " + lua_tostring(lua, -1) ));
}
}
it = elementMap.erase(it); it = elementMap.erase(it);
} }
else { else {
++it; ++it;
} }
} }
//pop the hook or nil
lua_pop(lua, 1);
} }
void RoomManager::PushCharacter(CharacterData* character) { void RoomManager::PushCharacter(CharacterData* character) {
@@ -71,7 +121,7 @@ void RoomManager::PushCharacter(CharacterData* character) {
throw(std::runtime_error("Failed to push an character to a non-existant room")); throw(std::runtime_error("Failed to push an character to a non-existant room"));
} }
room->characterList.push_back(character); room->GetCharacterList()->push_back(character);
} }
void RoomManager::PopCharacter(CharacterData const* character) { void RoomManager::PopCharacter(CharacterData const* character) {
@@ -86,7 +136,7 @@ void RoomManager::PopCharacter(CharacterData const* character) {
throw(std::runtime_error("Failed to pop an character to a non-existant room")); throw(std::runtime_error("Failed to pop an character to a non-existant room"));
} }
room->characterList.remove_if([character](CharacterData* ptr) { room->GetCharacterList()->remove_if([character](CharacterData* ptr) {
return character == ptr; return character == ptr;
}); });
} }
@@ -119,7 +169,11 @@ std::map<int, RoomData>* RoomManager::GetContainer() {
} }
lua_State* RoomManager::SetLuaState(lua_State* L) { lua_State* RoomManager::SetLuaState(lua_State* L) {
return lua = L; lua = L;
for (auto& it : elementMap) {
it.second.SetLuaState(lua);
}
return lua;
} }
lua_State* RoomManager::GetLuaState() { lua_State* RoomManager::GetLuaState() {
@@ -127,9 +181,29 @@ lua_State* RoomManager::GetLuaState() {
} }
sqlite3* RoomManager::SetDatabase(sqlite3* db) { sqlite3* RoomManager::SetDatabase(sqlite3* db) {
return database = db; database = db;
for (auto& it : elementMap) {
it.second.SetDatabase(database);
}
return database;
} }
sqlite3* RoomManager::GetDatabase() { sqlite3* RoomManager::GetDatabase() {
return database; return database;
} }
int RoomManager::SetCreateReference(int i) {
return createRef = i;
}
int RoomManager::SetUnloadReference(int i) {
return unloadRef = i;
}
int RoomManager::GetCreateReference() {
return createRef;
}
int RoomManager::GetUnloadReference() {
return unloadRef;
}
+15 -2
View File
@@ -49,12 +49,19 @@ public:
int GetLoadedCount(); int GetLoadedCount();
std::map<int, RoomData>* GetContainer(); std::map<int, RoomData>* GetContainer();
//hooks //API interfaces
lua_State* SetLuaState(lua_State* L); lua_State* SetLuaState(lua_State* L);
lua_State* GetLuaState(); lua_State* GetLuaState();
sqlite3* SetDatabase(sqlite3* db); sqlite3* SetDatabase(sqlite3* db);
sqlite3* GetDatabase(); sqlite3* GetDatabase();
//hooks
int SetCreateReference(int i);
int SetUnloadReference(int i);
int GetCreateReference();
int GetUnloadReference();
private: private:
friend Singleton<RoomManager>; friend Singleton<RoomManager>;
@@ -63,9 +70,15 @@ private:
//members //members
std::map<int, RoomData> elementMap; std::map<int, RoomData> elementMap;
int counter = 0;
//API
lua_State* lua = nullptr; lua_State* lua = nullptr;
sqlite3* database = nullptr; sqlite3* database = nullptr;
int counter = 0;
//hooks
int createRef = LUA_NOREF;
int unloadRef = LUA_NOREF;
}; };
#endif #endif
+16
View File
@@ -96,10 +96,26 @@ int getRoom(lua_State* L) {
return 1; return 1;
} }
static int setOnCreate(lua_State* L) {
RoomManager& roomMgr = RoomManager::GetSingleton();
luaL_unref(L, LUA_REGISTRYINDEX, roomMgr.GetCreateReference());
roomMgr.SetCreateReference(luaL_ref(L, LUA_REGISTRYINDEX));
return 0;
}
static int setOnUnload(lua_State* L) {
RoomManager& roomMgr = RoomManager::GetSingleton();
luaL_unref(L, LUA_REGISTRYINDEX, roomMgr.GetUnloadReference());
roomMgr.SetUnloadReference(luaL_ref(L, LUA_REGISTRYINDEX));
return 0;
}
static const luaL_Reg roomManagerLib[] = { static const luaL_Reg roomManagerLib[] = {
{"CreateRoom", createRoom}, {"CreateRoom", createRoom},
{"UnloadRoom", unloadRoom}, {"UnloadRoom", unloadRoom},
{"GetRoom", getRoom}, {"GetRoom", getRoom},
{"SetOnCreate", setOnCreate},
{"SetOnUnload", setOnUnload},
{nullptr, nullptr} {nullptr, nullptr}
}; };
-55
View File
@@ -1,55 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "room_system_api.hpp"
//all room API headers
#include "room_api.hpp"
#include "room_manager_api.hpp"
//useful "globals"
//...
//This mimics linit.c to create a nested collection of all room modules.
static const luaL_Reg funcs[] = {
{nullptr, nullptr}
};
static const luaL_Reg libs[] = {
{"Room", openRoomAPI},
{"RoomManager", openRoomManagerAPI},
{nullptr, nullptr}
};
int openRoomSystemAPI(lua_State* L) {
//create the table
luaL_newlibtable(L, libs);
//push the "global" functions
luaL_setfuncs(L, funcs, 0);
//push the substable
for (const luaL_Reg* lib = libs; lib->func; lib++) {
lib->func(L);
lua_setfield(L, -2, lib->name);
}
return 1;
}
+3 -10
View File
@@ -26,7 +26,6 @@
#include "account_manager.hpp" #include "account_manager.hpp"
#include "character_manager.hpp" #include "character_manager.hpp"
#include "client_manager.hpp" #include "client_manager.hpp"
#include "monster_manager.hpp"
#include "room_manager.hpp" #include "room_manager.hpp"
//utilities //utilities
@@ -38,6 +37,9 @@
#include "serial_packet.hpp" #include "serial_packet.hpp"
#include "singleton.hpp" #include "singleton.hpp"
//server utilities
#include "server_utilities.hpp"
//APIs //APIs
#include "lua.hpp" #include "lua.hpp"
#include "sqlite3.h" #include "sqlite3.h"
@@ -102,22 +104,13 @@ private:
void hCharacterAttack(CharacterPacket* const); void hCharacterAttack(CharacterPacket* const);
void hCharacterDamage(CharacterPacket* const); void hCharacterDamage(CharacterPacket* const);
//character management
void hMonsterDamage(MonsterPacket* const);
//chat //chat
void hTextBroadcast(TextPacket* const); void hTextBroadcast(TextPacket* const);
void hTextSpeech(TextPacket* const); void hTextSpeech(TextPacket* const);
void hTextWhisper(TextPacket* const); void hTextWhisper(TextPacket* const);
//utility methods //utility methods
void PumpPacket(SerialPacket* const);
void PumpPacketProximity(SerialPacket* const argPacket, int roomIndex, Vector2 position, int distance);
void CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex);
void SaveServerState(); void SaveServerState();
void FullClientUnload(int index);
void FullAccountUnload(int index);
void FullCharacterUnload(int index);
//APIs and utilities //APIs and utilities
sqlite3* database = nullptr; sqlite3* database = nullptr;
+36 -36
View File
@@ -21,6 +21,7 @@
*/ */
#include "server_application.hpp" #include "server_application.hpp"
#include <cstring>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@@ -46,13 +47,14 @@ void ServerApplication::hCharacterCreate(CharacterPacket* const argPacket) {
} }
//push to the rooms //push to the rooms
roomMgr.PushCharacter(characterMgr.Get(characterIndex)); CharacterData* characterData = characterMgr.Get(characterIndex);
roomMgr.PushCharacter(characterData);
//pump this character to all clients //pump this character to all clients
CharacterPacket newPacket; CharacterPacket newPacket;
CopyCharacterToPacket(&newPacket, characterIndex); copyCharacterToPacket(&newPacket, characterIndex);
newPacket.type = SerialPacketType::CHARACTER_CREATE; newPacket.type = SerialPacketType::CHARACTER_CREATE;
PumpPacket(&newPacket); pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
} }
void ServerApplication::hCharacterDelete(CharacterPacket* const argPacket) { void ServerApplication::hCharacterDelete(CharacterPacket* const argPacket) {
@@ -90,16 +92,17 @@ void ServerApplication::hCharacterDelete(CharacterPacket* const argPacket) {
} }
//pop from the rooms //pop from the rooms
roomMgr.PopCharacter(characterMgr.Get(characterIndex)); CharacterData* characterData = characterMgr.Get(characterIndex);
roomMgr.PopCharacter(characterData);
//delete the character
characterMgr.Delete(characterIndex);
//pump character delete //pump character delete
CharacterPacket newPacket; CharacterPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_DELETE; newPacket.type = SerialPacketType::CHARACTER_DELETE;
newPacket.characterIndex = characterIndex; newPacket.characterIndex = characterIndex;
PumpPacket(static_cast<SerialPacket*>(&newPacket)); pumpPacketProximity(static_cast<SerialPacket*>(&newPacket), characterData->GetRoomIndex());
//delete the character
characterMgr.Delete(characterIndex);
} }
void ServerApplication::hCharacterLoad(CharacterPacket* const argPacket) { void ServerApplication::hCharacterLoad(CharacterPacket* const argPacket) {
@@ -126,13 +129,14 @@ void ServerApplication::hCharacterLoad(CharacterPacket* const argPacket) {
} }
//push to the rooms //push to the rooms
roomMgr.PushCharacter(characterMgr.Get(characterIndex)); CharacterData* characterData = characterMgr.Get(characterIndex);
roomMgr.PushCharacter(characterData);
//pump this character to all clients //pump this character to all clients
CharacterPacket newPacket; CharacterPacket newPacket;
CopyCharacterToPacket(&newPacket, characterIndex); copyCharacterToPacket(&newPacket, characterIndex);
newPacket.type = SerialPacketType::CHARACTER_CREATE; newPacket.type = SerialPacketType::CHARACTER_CREATE;
PumpPacket(&newPacket); pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
} }
void ServerApplication::hCharacterUnload(CharacterPacket* const argPacket) { void ServerApplication::hCharacterUnload(CharacterPacket* const argPacket) {
@@ -161,14 +165,14 @@ void ServerApplication::hCharacterUnload(CharacterPacket* const argPacket) {
//pop from the rooms //pop from the rooms
roomMgr.PopCharacter(characterData); roomMgr.PopCharacter(characterData);
//unload the character
characterMgr.Unload(argPacket->characterIndex);
//pump character delete //pump character delete
CharacterPacket newPacket; CharacterPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_DELETE; newPacket.type = SerialPacketType::CHARACTER_DELETE;
newPacket.characterIndex = argPacket->characterIndex; newPacket.characterIndex = argPacket->characterIndex;
PumpPacket(static_cast<SerialPacket*>(&newPacket)); pumpPacketProximity(static_cast<SerialPacket*>(&newPacket), characterData->GetRoomIndex());
//unload the character
characterMgr.Unload(argPacket->characterIndex);
} }
//------------------------- //-------------------------
@@ -180,10 +184,15 @@ void ServerApplication::hCharacterUnload(CharacterPacket* const argPacket) {
void ServerApplication::hCharacterMovement(CharacterPacket* const argPacket) { void ServerApplication::hCharacterMovement(CharacterPacket* const argPacket) {
//get the specified objects //get the specified objects
AccountData* accountData = accountMgr.Get(argPacket->accountIndex); AccountData* accountData = accountMgr.Get(argPacket->accountIndex);
if (!accountData) {
throw(std::runtime_error("Failed to move a character, missing account"));
}
CharacterData* characterData = characterMgr.Get(argPacket->characterIndex); CharacterData* characterData = characterMgr.Get(argPacket->characterIndex);
if (!accountData || !characterData) { if (!characterData) {
throw(std::runtime_error("Failed to move a character, missing data")); throw(std::runtime_error("Failed to move a character, missing character"));
} }
//get this account's client //get this account's client
@@ -197,28 +206,19 @@ void ServerApplication::hCharacterMovement(CharacterPacket* const argPacket) {
//check if allowed //check if allowed
if (characterData->GetOwner() != argPacket->accountIndex && !accountData->GetModerator() && !accountData->GetAdministrator()) { if (characterData->GetOwner() != argPacket->accountIndex && !accountData->GetModerator() && !accountData->GetAdministrator()) {
//TODO: (2) send to the client? //TODO: (3) send to the client?
std::cerr << "Failed to set character motion due to lack of permissions targeting uid(" << argPacket->characterIndex << ")" << std::endl; std::cerr << "Failed to set character motion due to lack of permissions targeting uid(" << argPacket->characterIndex << ")" << std::endl;
return; return;
} }
//check if moving rooms //check if moving rooms
if (characterData->GetRoomIndex() != argPacket->roomIndex) { if (characterData->GetRoomIndex() != argPacket->roomIndex) {
//delete from the old room //set the character's origin and motion
CharacterPacket newPacket; characterData->SetOrigin(argPacket->origin);
CopyCharacterToPacket(&newPacket, argPacket->characterIndex); characterData->SetMotion(argPacket->motion);
newPacket.type = SerialPacketType::CHARACTER_DELETE;
PumpPacketProximity(&newPacket, characterData->GetRoomIndex(), characterData->GetOrigin(), -1);
//move the character between rooms //send the delete & create messages
roomMgr.PopCharacter(characterData); pumpAndChangeRooms(characterData, argPacket->roomIndex, argPacket->characterIndex);
characterData->SetRoomIndex(argPacket->roomIndex);
roomMgr.PushCharacter(characterData);
//create in the new room
CopyCharacterToPacket(&newPacket, argPacket->characterIndex);
newPacket.type = SerialPacketType::CHARACTER_CREATE;
PumpPacketProximity(&newPacket, characterData->GetRoomIndex(), characterData->GetOrigin(), -1);
} }
//if not moving between rooms //if not moving between rooms
else { else {
@@ -228,16 +228,16 @@ void ServerApplication::hCharacterMovement(CharacterPacket* const argPacket) {
//update the clients //update the clients
CharacterPacket newPacket; CharacterPacket newPacket;
CopyCharacterToPacket(&newPacket, argPacket->characterIndex); copyCharacterToPacket(&newPacket, argPacket->characterIndex);
newPacket.type = SerialPacketType::CHARACTER_MOVEMENT; newPacket.type = SerialPacketType::CHARACTER_MOVEMENT;
PumpPacketProximity(&newPacket, characterData->GetRoomIndex(), characterData->GetOrigin(), -1); pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
} }
} }
void ServerApplication::hCharacterAttack(CharacterPacket* const argPacket) { void ServerApplication::hCharacterAttack(CharacterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) ServerApplication::hCharacterAttack()
} }
void ServerApplication::hCharacterDamage(CharacterPacket* const argPacket) { void ServerApplication::hCharacterDamage(CharacterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) ServerApplication::hCharacterDamage()
} }
+3 -3
View File
@@ -22,13 +22,13 @@
#include "server_application.hpp" #include "server_application.hpp"
void ServerApplication::hTextBroadcast(TextPacket* const argPacket) { void ServerApplication::hTextBroadcast(TextPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) ServerApplication::hTextBroadcast()
} }
void ServerApplication::hTextSpeech(TextPacket* const argPacket) { void ServerApplication::hTextSpeech(TextPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) ServerApplication::hTextSpeech()
} }
void ServerApplication::hTextWhisper(TextPacket* const argPacket) { void ServerApplication::hTextWhisper(TextPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) ServerApplication::hTextWhisper()
} }
+3 -2
View File
@@ -21,6 +21,7 @@
*/ */
#include "server_application.hpp" #include "server_application.hpp"
#include <cstring>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@@ -138,7 +139,7 @@ void ServerApplication::hLogoutRequest(ClientPacket* const argPacket) {
network.SendTo(clientData->GetAddress(), static_cast<SerialPacket*>(&newPacket)); network.SendTo(clientData->GetAddress(), static_cast<SerialPacket*>(&newPacket));
//save and unload this account and it's characters //save and unload this account and it's characters
FullAccountUnload(argPacket->accountIndex); fullAccountUnload(argPacket->accountIndex);
//finished this routine //finished this routine
std::cout << "New logout, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl; std::cout << "New logout, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
@@ -165,7 +166,7 @@ void ServerApplication::hDisconnectRequest(ClientPacket* const argPacket) {
network.SendTo(clientData->GetAddress(), static_cast<SerialPacket*>(&newPacket)); network.SendTo(clientData->GetAddress(), static_cast<SerialPacket*>(&newPacket));
//unload the client, it's accounts, and their characters //unload the client, it's accounts, and their characters
FullClientUnload(argPacket->clientIndex); fullClientUnload(argPacket->clientIndex);
//finished this routine //finished this routine
std::cout << "New disconnection, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl; std::cout << "New disconnection, " << clientMgr.GetLoadedCount() << " clients and " << accountMgr.GetLoadedCount() << " accounts total" << std::endl;
+7 -6
View File
@@ -21,6 +21,7 @@
*/ */
#include "server_application.hpp" #include "server_application.hpp"
#include <cstring>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@@ -69,28 +70,28 @@ void ServerApplication::hQueryCharacterExists(CharacterPacket* const argPacket)
if (argPacket->roomIndex != -1 && it.second.GetRoomIndex() != argPacket->roomIndex) { if (argPacket->roomIndex != -1 && it.second.GetRoomIndex() != argPacket->roomIndex) {
continue; continue;
} }
CopyCharacterToPacket(&newPacket, it.first); copyCharacterToPacket(&newPacket, it.first);
newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS; newPacket.type = SerialPacketType::QUERY_CHARACTER_EXISTS;
network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket)); network.SendTo(argPacket->srcAddress, static_cast<SerialPacket*>(&newPacket));
} }
} }
void ServerApplication::hQueryCharacterStats(CharacterPacket* const argPacket) { void ServerApplication::hQueryCharacterStats(CharacterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) ServerApplication::hQueryCharacterStats()
} }
void ServerApplication::hQueryCharacterLocation(CharacterPacket* const argPacket) { void ServerApplication::hQueryCharacterLocation(CharacterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) ServerApplication::hQueryCharacterLocation()
} }
void ServerApplication::hQueryMonsterExists(MonsterPacket* const argPacket) { void ServerApplication::hQueryMonsterExists(MonsterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) ServerApplication::hQueryMonsterExists()
} }
void ServerApplication::hQueryMonsterStats(MonsterPacket* const argPacket) { void ServerApplication::hQueryMonsterStats(MonsterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) ServerApplication::hQueryMonsterStats()
} }
void ServerApplication::hQueryMonsterLocation(MonsterPacket* const argPacket) { void ServerApplication::hQueryMonsterLocation(MonsterPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) ServerApplication::hQueryMonsterLocation()
} }
+37 -18
View File
@@ -27,7 +27,9 @@
//std & STL //std & STL
#include <stdexcept> #include <stdexcept>
#include <chrono> #include <chrono>
#include <cstring>
#include <iostream> #include <iostream>
#include <list>
#include <sstream> #include <sstream>
#include <string> #include <string>
@@ -50,7 +52,9 @@ void ServerApplication::Init(int argc, char* argv[]) {
//Init SDL //Init SDL
if (SDL_Init(0)) { if (SDL_Init(0)) {
throw(std::runtime_error("Failed to initialize SDL")); std::ostringstream os;
os << "Failed to initialize SDL: " << SDL_GetError();
throw(std::runtime_error(os.str()));
} }
std::cout << "Initialized SDL" << std::endl; std::cout << "Initialized SDL" << std::endl;
@@ -161,9 +165,16 @@ void ServerApplication::Init(int argc, char* argv[]) {
} }
void ServerApplication::Proc() { void ServerApplication::Proc() {
//network buffer
SerialPacket* packetBuffer = reinterpret_cast<SerialPacket*>(new char[MAX_PACKET_SIZE]); SerialPacket* packetBuffer = reinterpret_cast<SerialPacket*>(new char[MAX_PACKET_SIZE]);
memset(packetBuffer, 0, MAX_PACKET_SIZE); //zero the buffer memset(packetBuffer, 0, MAX_PACKET_SIZE); //zero the buffer
//time system
typedef std::chrono::steady_clock Clock;
Clock::time_point simTime = Clock::now();
Clock::time_point realTime;
while(running) { while(running) {
//suck in the waiting packets & process them //suck in the waiting packets & process them
while(network.Receive(packetBuffer)) { while(network.Receive(packetBuffer)) {
@@ -173,20 +184,33 @@ void ServerApplication::Proc() {
catch(std::exception& e) { catch(std::exception& e) {
std::cerr << "HandlePacket Error: " << e.what() << std::endl; std::cerr << "HandlePacket Error: " << e.what() << std::endl;
} }
memset(packetBuffer, 0, MAX_PACKET_SIZE); //reset the buffer //reset the buffer
} memset(packetBuffer, 0, MAX_PACKET_SIZE);
//update the internals
//...
//Check connections
int disconnected = clientMgr.CheckConnections();
if (disconnected != -1) {
FullClientUnload(disconnected);
std::cerr << "Client dropped: " << disconnected << std::endl;
} }
//give the machine a break //Check client connections
SDL_Delay(10); std::list<int> disconnections = clientMgr.CheckConnections();
for(auto const& it : disconnections) {
fullClientUnload(it);
std::cerr << "Client dropped: " << it << std::endl;
}
//"tick" the internals
realTime = Clock::now();
if (simTime < realTime) {
while(simTime < realTime) {
for (auto& it : *roomMgr.GetContainer()) {
it.second.RunFrame();
}
//~60 FPS
simTime += std::chrono::duration<int, std::milli>(16);
}
}
else {
//give the machine a break
SDL_Delay(10);
}
} }
delete reinterpret_cast<char*>(packetBuffer); delete reinterpret_cast<char*>(packetBuffer);
} }
@@ -303,11 +327,6 @@ void ServerApplication::HandlePacket(SerialPacket* const argPacket) {
hCharacterDamage(static_cast<CharacterPacket*>(argPacket)); hCharacterDamage(static_cast<CharacterPacket*>(argPacket));
break; break;
//monster management
case SerialPacketType::MONSTER_DAMAGE:
hMonsterDamage(static_cast<MonsterPacket*>(argPacket));
break;
//chat //chat
case SerialPacketType::TEXT_BROADCAST: case SerialPacketType::TEXT_BROADCAST:
hTextBroadcast(static_cast<TextPacket*>(argPacket)); hTextBroadcast(static_cast<TextPacket*>(argPacket));
+4 -118
View File
@@ -22,6 +22,7 @@
#include "server_application.hpp" #include "server_application.hpp"
#include <chrono> #include <chrono>
#include <cstring>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@@ -30,7 +31,7 @@
//------------------------- //-------------------------
void ServerApplication::hAdminDisconnectForced(ClientPacket* const argPacket) { void ServerApplication::hAdminDisconnectForced(ClientPacket* const argPacket) {
//TODO: (9) empty //TODO: (9) ServerApplication::hAdminDisconnectForced()
} }
void ServerApplication::hAdminShutdownRequest(ClientPacket* const argPacket) { void ServerApplication::hAdminShutdownRequest(ClientPacket* const argPacket) {
@@ -78,127 +79,12 @@ void ServerApplication::hAdminShutdownRequest(ClientPacket* const argPacket) {
TextPacket newPacket; TextPacket newPacket;
newPacket.type = SerialPacketType::ADMIN_DISCONNECT_FORCED; newPacket.type = SerialPacketType::ADMIN_DISCONNECT_FORCED;
strncpy(newPacket.text, "Server shutdown", PACKET_STRING_SIZE); strncpy(newPacket.text, "Server shutdown", PACKET_STRING_SIZE);
PumpPacket(&newPacket); pumpPacket(&newPacket);
//finished this routine //finished this routine
std::cout << "Shutdown signal accepted" << std::endl; std::cout << "Shutdown signal accepted" << std::endl;
} }
void ServerApplication::SaveServerState() { void ServerApplication::SaveServerState() {
//TODO: (9) empty //TODO: (3) Periodic mass server saves
}
//-------------------------
//full unload methods
//-------------------------
void ServerApplication::FullClientUnload(int index) {
clientMgr.UnloadIf([&](std::pair<const int, ClientData const&> client) -> bool {
//skip the wrong clients
if (client.first != index) {
return false;
}
//unload associated accounts
for (std::map<int, AccountData>::iterator it = accountMgr.GetContainer()->begin(); it != accountMgr.GetContainer()->end(); /* EMPTY */) {
if (it->second.GetClientIndex() == index) {
FullAccountUnload(it->first);
it = accountMgr.GetContainer()->begin();
}
else {
++it;
}
}
//unload this client
return true;
});
}
void ServerApplication::FullAccountUnload(int index) {
accountMgr.UnloadIf([&](std::pair<const int, AccountData const&> account) -> bool {
//skip the wrong accounts
if (account.first != index) {
return false;
}
//unload associated characters
for (std::map<int, CharacterData>::iterator it = characterMgr.GetContainer()->begin(); it != characterMgr.GetContainer()->end(); /* EMPTY */) {
if (it->second.GetOwner() == index) {
FullCharacterUnload(it->first);
it = characterMgr.GetContainer()->begin();
}
else {
++it;
}
}
//unload this account
return true;
});
}
void ServerApplication::FullCharacterUnload(int index) {
characterMgr.UnloadIf([&](std::pair<const int, CharacterData const&> character) -> bool {
//skip the wrong characters
if (character.first != index) {
return false;
}
//pop from the rooms
roomMgr.PopCharacter(&character.second);
//pump character unload
CharacterPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_DELETE;
newPacket.characterIndex = character.first;
//NOTE: more character info as needed
PumpPacket(&newPacket);
//unload this character
return true;
});
}
//-------------------------
//utility methods
//-------------------------
void ServerApplication::PumpPacket(SerialPacket* const argPacket) {
for (auto& it : *clientMgr.GetContainer()) {
network.SendTo(it.second.GetAddress(), argPacket);
}
}
void ServerApplication::PumpPacketProximity(SerialPacket* const argPacket, int roomIndex, Vector2 position, int distance) {
RoomData* room = roomMgr.Get(roomIndex);
if (!room) {
throw(std::runtime_error("Failed to pump to a non-existant room"));
}
for (auto& character : *room->GetCharacterList()) {
if (distance == -1 || (character->GetOrigin() - position).Length() <= distance) {
AccountData* account = accountMgr.Get(character->GetOwner());
ClientData* client = clientMgr.Get(account->GetClientIndex());
network.SendTo(client->GetAddress(), argPacket);
}
}
}
void ServerApplication::CopyCharacterToPacket(CharacterPacket* const packet, int characterIndex) {
CharacterData* character = characterMgr.Get(characterIndex);
if (!character) {
throw(std::runtime_error("Failed to copy a character to a packet"));
}
//NOTE: keep this up to date when the character changes
packet->characterIndex = characterIndex;
strncpy(packet->handle, character->GetHandle().c_str(), PACKET_STRING_SIZE);
strncpy(packet->avatar, character->GetAvatar().c_str(), PACKET_STRING_SIZE);
packet->accountIndex = character->GetOwner();
packet->roomIndex = character->GetRoomIndex();
packet->origin = character->GetOrigin();
packet->motion = character->GetMotion();
} }
-26
View File
@@ -1,26 +0,0 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "server_application.hpp"
void ServerApplication::hMonsterDamage(MonsterPacket* const argPacket) {
//TODO: (9) empty
}
+1 -6
View File
@@ -1,5 +1,5 @@
#config #config
INCLUDES+=. INCLUDES+=. ../accounts ../characters ../clients ../entities ../monsters ../rooms ../triggers ../../common/gameplay ../../common/map ../../common/network ../../common/network/packet_types ../../common/utilities
LIBS+= LIBS+=
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES)) CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
+80
View File
@@ -0,0 +1,80 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "network_api.hpp"
#include "character_data.hpp"
#include "character_manager.hpp"
#include "server_utilities.hpp"
#include <cstring>
static int pumpCharacterUpdate(lua_State* L) {
CharacterData* characterData = static_cast<CharacterData*>(lua_touserdata(L, 1));
//determine the character's index
int index = -1;
for (auto const& it : *CharacterManager::GetSingleton().GetContainer()) {
if(characterData == &it.second) {
index = it.first;
break;
}
}
//signal an error
if (index == -1) {
lua_pushboolean(L, false);
return 1;
}
//fill the packet with all of this character's data
CharacterPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_UPDATE;
newPacket.characterIndex = index;
strncpy(newPacket.handle, characterData->GetHandle().c_str(), PACKET_STRING_SIZE);
strncpy(newPacket.avatar, characterData->GetAvatar().c_str(), PACKET_STRING_SIZE);
newPacket.accountIndex = characterData->GetOwner();
newPacket.roomIndex = characterData->GetRoomIndex();
newPacket.origin = characterData->GetOrigin();
newPacket.motion = characterData->GetMotion();
//pump to the room
pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
//signal success
lua_pushboolean(L, true);
return 1;
}
static int pumpMonsterUpdate(lua_State* L) {
//TODO: (0) send the info about a specific monster instance
}
static const luaL_Reg networkLib[] = {
{"PumpCharacterUpdate", pumpCharacterUpdate},
{"PumpMonsterUpdate", pumpMonsterUpdate},
{nullptr, nullptr}
};
LUAMOD_API int openNetworkAPI(lua_State* L) {
luaL_newlib(L, networkLib);
return 1;
}
@@ -19,12 +19,12 @@
* 3. This notice may not be removed or altered from any source * 3. This notice may not be removed or altered from any source
* distribution. * distribution.
*/ */
#ifndef WAYPOINTAPI_HPP_ #ifndef NETWORKAPI_HPP_
#define WAYPOINTAPI_HPP_ #define NETWORKAPI_HPP_
#include "lua.hpp" #include "lua.hpp"
#define TORTUGA_WAYPOINT_API "waypoint" #define TORTUGA_NETWORK_API "network"
LUAMOD_API int openWaypointAPI(lua_State* L); LUAMOD_API int openNetworkAPI(lua_State* L);
#endif #endif
@@ -0,0 +1,184 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "server_utilities.hpp"
#include "account_manager.hpp"
#include "character_manager.hpp"
#include "client_manager.hpp"
#include "room_manager.hpp"
#include "udp_network_utility.hpp"
#include <cstring>
//-------------------------
//manager unload functions
//-------------------------
void fullClientUnload(int index) {
ClientManager::GetSingleton().UnloadIf([index](std::pair<const int, ClientData const&> clientPair) -> bool {
//skip the wrong clients
if (clientPair.first != index) {
return false;
}
AccountManager& accountMgr = AccountManager::GetSingleton();
//unload associated accounts
for (std::map<int, AccountData>::iterator it = accountMgr.GetContainer()->begin(); it != accountMgr.GetContainer()->end(); /* EMPTY */) {
if (it->second.GetClientIndex() == index) {
fullAccountUnload(it->first);
it = accountMgr.GetContainer()->begin();
}
else {
++it;
}
}
//unload this client
return true;
});
}
void fullAccountUnload(int index) {
AccountManager::GetSingleton().UnloadIf([index](std::pair<const int, AccountData const&> accountPair) -> bool {
//skip the wrong accounts
if (accountPair.first != index) {
return false;
}
CharacterManager& characterMgr = CharacterManager::GetSingleton();
//unload associated characters
for (std::map<int, CharacterData>::iterator it = characterMgr.GetContainer()->begin(); it != characterMgr.GetContainer()->end(); /* EMPTY */) {
if (it->second.GetOwner() == index) {
fullCharacterUnload(it->first);
it = characterMgr.GetContainer()->begin();
}
else {
++it;
}
}
//unload this account
return true;
});
}
void fullCharacterUnload(int index) {
CharacterManager::GetSingleton().UnloadIf([index](std::pair<const int, CharacterData const&> characterPair) -> bool {
//skip the wrong characters
if (characterPair.first != index) {
return false;
}
//pop from the rooms
RoomManager::GetSingleton().PopCharacter(&characterPair.second);
//pump character unload
CharacterPacket newPacket;
newPacket.type = SerialPacketType::CHARACTER_DELETE;
newPacket.characterIndex = characterPair.first;
//NOTE: more character info as needed
//TODO: proximity?
pumpPacketProximity(&newPacket, characterPair.second.GetRoomIndex());
//unload this character
return true;
});
}
//-------------------------
//utility functions
//-------------------------
void pumpPacket(SerialPacket* const argPacket) {
for (auto& it : *ClientManager::GetSingleton().GetContainer()) {
UDPNetworkUtility::GetSingleton().SendTo(it.second.GetAddress(), argPacket);
}
}
void pumpPacketProximity(SerialPacket* const argPacket, int roomIndex, Vector2 position, int distance) {
RoomData* roomData = RoomManager::GetSingleton().Get(roomIndex);
if (!roomData) {
throw(std::runtime_error("Failed to pump to a non-existant room"));
}
AccountData* accountData = nullptr;
ClientData* clientData = nullptr;
for (auto& characterIt : *roomData->GetCharacterList()) {
if (distance == -1 || (characterIt->GetOrigin() - position).Length() <= distance) {
accountData = AccountManager::GetSingleton().Get(characterIt->GetOwner());
clientData = ClientManager::GetSingleton().Get(accountData->GetClientIndex());
UDPNetworkUtility::GetSingleton().SendTo(clientData->GetAddress(), argPacket);
}
}
}
void copyCharacterToPacket(CharacterPacket* const packet, int characterIndex) {
CharacterData* characterData = CharacterManager::GetSingleton().Get(characterIndex);
if (!characterData) {
throw(std::runtime_error("Failed to copy a character to a packet"));
}
copyCharacterToPacket(packet, characterData, characterIndex);
}
void copyCharacterToPacket(CharacterPacket* const packet, CharacterData* const characterData, int characterIndex) {
//NOTE: keep this up to date when the character changes
packet->characterIndex = characterIndex;
strncpy(packet->handle, characterData->GetHandle().c_str(), PACKET_STRING_SIZE);
strncpy(packet->avatar, characterData->GetAvatar().c_str(), PACKET_STRING_SIZE);
packet->accountIndex = characterData->GetOwner();
packet->roomIndex = characterData->GetRoomIndex();
packet->origin = characterData->GetOrigin();
packet->motion = characterData->GetMotion();
packet->bounds = characterData->GetBounds();
}
void pumpAndChangeRooms(int characterIndex, int newRoomIndex) {
//get the character object
CharacterData* character = CharacterManager::GetSingleton().Get(characterIndex);
//pass ownwards
pumpAndChangeRooms(character, newRoomIndex, characterIndex);
}
void pumpAndChangeRooms(CharacterData* const characterData, int newRoomIndex, int characterIndex) {
//delete from the old room
CharacterPacket newPacket;
copyCharacterToPacket(&newPacket, characterData, characterIndex);
newPacket.type = SerialPacketType::CHARACTER_DELETE;
pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
//move the character between rooms
RoomManager::GetSingleton().PopCharacter(characterData);
characterData->SetRoomIndex(newRoomIndex);
RoomManager::GetSingleton().PushCharacter(characterData);
//create in the new room
copyCharacterToPacket(&newPacket, characterData, characterIndex);
newPacket.type = SerialPacketType::CHARACTER_CREATE;
pumpPacketProximity(&newPacket, characterData->GetRoomIndex());
}
@@ -19,12 +19,23 @@
* 3. This notice may not be removed or altered from any source * 3. This notice may not be removed or altered from any source
* distribution. * distribution.
*/ */
#ifndef MONSTERSYSTEMAPI_HPP_ #ifndef SERVERUTILITIES_HPP_
#define MONSTERSYSTEMAPI_HPP_ #define SERVERUTILITIES_HPP_
#include "lua.hpp" #include "character_data.hpp"
#include "serial_packet.hpp"
#include "vector2.hpp"
#define TORTUGA_MONSTER_SYSTEM_API "monster_system" void fullClientUnload(int index);
LUAMOD_API int openMonsterSystemAPI(lua_State* L); void fullAccountUnload(int index);
void fullCharacterUnload(int index);
void pumpPacket(SerialPacket* const argPacket);
void pumpPacketProximity(SerialPacket* const argPacket, int roomIndex, Vector2 position = {0, 0}, int distance = -1);
void copyCharacterToPacket(CharacterPacket* const packet, int characterIndex);
void copyCharacterToPacket(CharacterPacket* const packet, CharacterData* const characterData, int characterIndex);
void pumpAndChangeRooms(int characterIndex, int newRoomIndex);
void pumpAndChangeRooms(CharacterData* const characterData, int newRoomIndex, int characterIndex);
#endif #endif
@@ -30,8 +30,3 @@ $(OUTDIR):
$(OBJDIR)/%.o: %.cpp $(OBJDIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $< $(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
$(RM) *.o *.a *.exe
rebuild: clean all
+126
View File
@@ -0,0 +1,126 @@
/* Copyright: (c) Kayne Ruse 2013-2015
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#include "trigger_api.hpp"
#include "trigger_data.hpp"
//hamdle
static int setHandle(lua_State* L) {
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
trigger->SetHandle(lua_tostring(L, 2));
return 0;
}
static int getHandle(lua_State* L) {
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
lua_pushstring(L, trigger->GetHandle().c_str());
return 1;
}
//origin
static int setOrigin(lua_State* L) {
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
trigger->SetOrigin(Vector2(lua_tonumber(L, 2), lua_tonumber(L, 3)));
return 0;
}
static int getOrigin(lua_State* L) {
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
lua_pushnumber(L, trigger->GetOrigin().x);
lua_pushnumber(L, trigger->GetOrigin().y);
return 2;
}
//bounds
static int setBoundingBox(lua_State* L) {
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
trigger->SetBoundingBox(BoundingBox(
lua_tonumber(L, 2),
lua_tonumber(L, 3),
lua_tonumber(L, 4),
lua_tonumber(L, 5)
));
return 0;
}
static int getBoundingBox(lua_State* L) {
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
lua_pushinteger(L, trigger->GetBoundingBox().x);
lua_pushinteger(L, trigger->GetBoundingBox().y);
lua_pushinteger(L, trigger->GetBoundingBox().w);
lua_pushinteger(L, trigger->GetBoundingBox().h);
return 4;
}
//triggers
static int setReference(lua_State* L) {
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
luaL_unref(L, LUA_REGISTRYINDEX, trigger->GetScriptReference());
trigger->SetScriptReference(luaL_ref(L, LUA_REGISTRYINDEX));
return 0;
}
static int getReference(lua_State* L) {
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
lua_pushinteger(L, trigger->GetScriptReference());
lua_gettable(L, LUA_REGISTRYINDEX);
return 1;
}
static int pushExclusionEntity(lua_State* L) {
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
trigger->GetExclusionList()->push_back(static_cast<Entity*>(lua_touserdata(L, 2)));
return 0;
}
static int removeExclusionEntity(lua_State* L) {
TriggerData* trigger = static_cast<TriggerData*>(lua_touserdata(L, 1));
Entity* entity = static_cast<Entity*>(lua_touserdata(L, 2));
trigger->GetExclusionList()->remove_if([entity](Entity* ptr){
return entity == ptr;
});
return 0;
}
static const luaL_Reg triggerLib[] = {
{"SetHandle", setHandle},
{"GetHandle", getHandle},
{"SetOrigin",setOrigin},
{"GetOrigin",getOrigin},
{"SetBounds",setBoundingBox},
{"GetBounds",getBoundingBox},
{"SetScript",setReference},
{"GetScript",getReference},
{"PushExclusionEntity", pushExclusionEntity},
{"RemoveExclusionEntity", removeExclusionEntity},
{nullptr, nullptr}
};
LUAMOD_API int openTriggerAPI(lua_State* L) {
luaL_newlib(L, triggerLib);
return 1;
}
@@ -19,12 +19,12 @@
* 3. This notice may not be removed or altered from any source * 3. This notice may not be removed or altered from any source
* distribution. * distribution.
*/ */
#ifndef MAPSYSTEMAPI_HPP_ #ifndef TRIGGERAPI_HPP_
#define MAPSYSTEMAPI_APP_ #define TRIGGERAPI_HPP_
#include "lua.hpp" #include "lua.hpp"
#define TORTUGA_MAP_SYSTEM_API "map_system" #define TORTUGA_TRIGGER_API "trigger"
LUAMOD_API int openMapSystemAPI(lua_State* L); LUAMOD_API int openTriggerAPI(lua_State* L);
#endif #endif
@@ -19,28 +19,40 @@
* 3. This notice may not be removed or altered from any source * 3. This notice may not be removed or altered from any source
* distribution. * distribution.
*/ */
#include "waypoint_data.hpp" #include "trigger_data.hpp"
int WaypointData::SetTriggerReference(int i) { std::string TriggerData::SetHandle(std::string s) {
return triggerRef = i; return handle = s;
} }
int WaypointData::GetTriggerReference() { std::string TriggerData::GetHandle() const {
return triggerRef; return handle;
} }
BoundingBox WaypointData::SetBoundingBox(BoundingBox b) { Vector2 TriggerData::SetOrigin(Vector2 v) {
return bounds = b;
}
BoundingBox WaypointData::GetBoundingBox() {
return bounds;
}
Vector2 WaypointData::SetOrigin(Vector2 v) {
return origin = v; return origin = v;
} }
Vector2 WaypointData::GetOrigin() { Vector2 TriggerData::GetOrigin() {
return origin; return origin;
} }
BoundingBox TriggerData::SetBoundingBox(BoundingBox b) {
return bounds = b;
}
BoundingBox TriggerData::GetBoundingBox() {
return bounds;
}
int TriggerData::SetScriptReference(int i) {
return scriptRef = i;
}
int TriggerData::GetScriptReference() {
return scriptRef;
}
std::list<Entity*>* TriggerData::GetExclusionList() {
return &exclusionList;
}

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