Multiple changes, read more

* Implemented HeartbeatUtility
* simplified the SQL files
* Added a dummy inventory button
This commit is contained in:
2016-04-25 22:10:11 +10:00
parent 5285397101
commit 7c6468c1dd
10 changed files with 259 additions and 145 deletions
+58
View File
@@ -0,0 +1,58 @@
/* Copyright: (c) Kayne Ruse 2013-2016
*
* 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 "heartbeat_utility.hpp"
#include "channels.hpp"
#include "ip_operators.hpp"
//heartbeat system
void HeartbeatUtility::hPing(ServerPacket* const argPacket) {
ServerPacket newPacket;
newPacket.type = SerialPacketType::PONG;
network.SendTo(argPacket->srcAddress, &newPacket);
}
void HeartbeatUtility::hPong(ServerPacket* const argPacket) {
if (*network.GetIPAddress(Channels::SERVER) != argPacket->srcAddress) {
throw(std::runtime_error("Heartbeat message received from an unknown source"));
}
attemptedBeats = 0;
lastBeat = Clock::now();
}
int HeartbeatUtility::CheckHeartBeat() {
//check the connection (heartbeat)
if (Clock::now() - lastBeat > std::chrono::seconds(3)) {
if (attemptedBeats > 2) {
return 1;
}
else {
ServerPacket newPacket;
newPacket.type = SerialPacketType::PING;
network.SendTo(Channels::SERVER, &newPacket);
attemptedBeats++;
lastBeat = Clock::now();
}
}
return 0;
}
@@ -19,27 +19,24 @@
* 3. This notice may not be removed or altered from any source
* distribution.
*/
#pragma once
-------------------------
--fill the global tables with gameplay data
-------------------------
#include "server_packet.hpp"
#include "udp_network_utility.hpp"
INSERT OR IGNORE INTO InventoryItems (name, type, durability) VALUES
("sword", "weapon", 100),
("dagger", "weapon", 100),
("staff", "weapon", 100),
("shield", "armour", 100),
("potion", "consumable", 100)
;
#include <chrono>
--DEBUG: Test cases
INSERT INTO LiveCharacters
class HeartbeatUtility {
public:
//heartbeat system
void hPing(ServerPacket* const);
void hPong(ServerPacket* const);
--DEBUG: this is supposed to archive the dead characters
--Insert into DeadCharacters From LiveCharacters all characters who's HP has reached zero or below
INSERT INTO DeadCharacters (uid, owner, handle, avatar, birth)
SELECT uid, owner, handle, avatar, birth FROM LiveCharacters WHERE
SELECT character FROM CharacterStatistics WHERE
SELECT uid FROM CombatStatistics WHERE health <= 0;
int CheckHeartBeat();
DELETE FROM LiveCharacters WHERE uid IN (SELECT uid FROM DeadCharacters);
private:
UDPNetworkUtility& network = UDPNetworkUtility::GetSingleton();
typedef std::chrono::steady_clock Clock;
Clock::time_point lastBeat = Clock::now();
int attemptedBeats = 0;
};
+18 -41
View File
@@ -77,12 +77,16 @@ World::World(int* const argClientIndex, int* const argAccountIndex):
disconnectButton.SetText(GetRenderer(), font, WHITE, "Disconnect");
shutdownButton.SetBackgroundTexture(GetRenderer(), buttonImage.GetTexture());
shutdownButton.SetText(GetRenderer(), font, WHITE, "Shutdown");
inventoryButton.SetBackgroundTexture(GetRenderer(), buttonImage.GetTexture());
inventoryButton.SetText(GetRenderer(), font, WHITE, "Inventory");
//set the button positions
disconnectButton.SetX(50);
disconnectButton.SetY(50);
shutdownButton.SetX(50);
shutdownButton.SetY(70);
inventoryButton.SetX(50);
inventoryButton.SetY(90);
//load the tilesheet
//TODO: (2) Tile size and tile sheet should be loaded elsewhere
@@ -161,7 +165,12 @@ void World::Update() {
delete reinterpret_cast<char*>(packetBuffer);
//heartbeat system
CheckHeartBeat();
if (heartbeatUtility.CheckHeartBeat()) {
//escape to the disconnect screen
SendDisconnectRequest();
SetSceneSignal(SceneSignal::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "Error: Lost connection to the server";
}
//update all entities
for (auto& it : characterMap) {
@@ -261,6 +270,7 @@ void World::RenderFrame(SDL_Renderer* renderer) {
//draw UI
disconnectButton.DrawTo(renderer);
shutdownButton.DrawTo(renderer);
inventoryButton.DrawTo(renderer);
//FPS
fpsTextLine.DrawTo(renderer);
@@ -285,11 +295,13 @@ void World::QuitEvent() {
void World::MouseMotion(SDL_MouseMotionEvent const& event) {
disconnectButton.MouseMotion(event);
shutdownButton.MouseMotion(event);
inventoryButton.MouseMotion(event);
}
void World::MouseButtonDown(SDL_MouseButtonEvent const& event) {
disconnectButton.MouseButtonDown(event);
shutdownButton.MouseButtonDown(event);
inventoryButton.MouseButtonDown(event);
}
void World::MouseButtonUp(SDL_MouseButtonEvent const& event) {
@@ -299,6 +311,9 @@ void World::MouseButtonUp(SDL_MouseButtonEvent const& event) {
if (shutdownButton.MouseButtonUp(event) == Button::State::RELEASED) {
SendAdminShutdownRequest();
}
if (inventoryButton.MouseButtonUp(event) == Button::State::RELEASED) {
//TODO: show the inventory screen
}
}
void World::MouseWheel(SDL_MouseWheelEvent const& event) {
@@ -411,10 +426,10 @@ void World::HandlePacket(SerialPacket* const argPacket) {
switch(argPacket->type) {
//heartbeat system
case SerialPacketType::PING:
hPing(static_cast<ServerPacket*>(argPacket));
heartbeatUtility.hPing(static_cast<ServerPacket*>(argPacket));
break;
case SerialPacketType::PONG:
hPong(static_cast<ServerPacket*>(argPacket));
heartbeatUtility.hPong(static_cast<ServerPacket*>(argPacket));
break;
//game server connections
@@ -520,44 +535,6 @@ void World::HandlePacket(SerialPacket* const argPacket) {
}
}
//-------------------------
//heartbeat system
//-------------------------
void World::hPing(ServerPacket* const argPacket) {
ServerPacket newPacket;
newPacket.type = SerialPacketType::PONG;
network.SendTo(argPacket->srcAddress, &newPacket);
}
void World::hPong(ServerPacket* const argPacket) {
if (*network.GetIPAddress(Channels::SERVER) != argPacket->srcAddress) {
throw(std::runtime_error("Heartbeat message received from an unknown source"));
}
attemptedBeats = 0;
lastBeat = Clock::now();
}
void World::CheckHeartBeat() {
//check the connection (heartbeat)
if (Clock::now() - lastBeat > std::chrono::seconds(3)) {
if (attemptedBeats > 2) {
//escape to the disconnect screen
SendDisconnectRequest();
SetSceneSignal(SceneSignal::DISCONNECTEDSCREEN);
ConfigUtility::GetSingleton()["client.disconnectMessage"] = "Error: Lost connection to the server";
}
else {
ServerPacket newPacket;
newPacket.type = SerialPacketType::PING;
network.SendTo(Channels::SERVER, &newPacket);
attemptedBeats++;
lastBeat = Clock::now();
}
}
}
//-------------------------
//Connection control
//-------------------------
+3 -9
View File
@@ -43,6 +43,7 @@
#include "base_scene.hpp"
#include "base_barrier.hpp"
#include "base_creature.hpp"
#include "heartbeat_utility.hpp"
#include "local_character.hpp"
#include "SDL2/SDL.h"
@@ -80,12 +81,6 @@ private:
//handle incoming traffic
void HandlePacket(SerialPacket* const);
//heartbeat system
void hPing(ServerPacket* const);
void hPong(ServerPacket* const);
void CheckHeartBeat();
//basic connections
void SendLogoutRequest();
void SendDisconnectRequest();
@@ -148,6 +143,7 @@ private:
TTF_Font* font = nullptr;
Button disconnectButton;
Button shutdownButton;
Button inventoryButton;
FrameRate fps;
TextLine fpsTextLine;
@@ -165,11 +161,9 @@ private:
LocalCharacter* localCharacter = nullptr;
//heartbeat
//TODO: (2) Heartbeat needs it's own utility
HeartbeatUtility heartbeatUtility;
typedef std::chrono::steady_clock Clock;
Clock::time_point lastBeat = Clock::now();
Clock::time_point queryTime = Clock::now() - std::chrono::seconds(4); //back 4 seconds to trigger automatically
int attemptedBeats = 0;
//ugly references; I hate this
ConfigUtility& config = ConfigUtility::GetSingleton();
+125
View File
@@ -0,0 +1,125 @@
/* Copyright: (c) Kayne Ruse 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.
*/
#pragma once
//DOCS: this is a generic CSV reading tool
//DOCS: empty lines and comment lines begining with '#' are ignored
//DOCS: whitespace characters are valid field values
//DOCS: if the file is invalid, then the behavior is undefined
#include <array>
#include <cstring>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
//define the container types
template<int N>
using CSVElement = std::array<std::string, N>;
template<int N>
using CSVObject = std::vector<CSVElement<N>>;
//read a file into an object
template<int N>
CSVObject<N> readCSV(std::string fname, char delim = ',') {
//open the file
std::ifstream is(fname);
if (!is.is_open()) {
std::ostringstream msg;
msg << "Failed to open file: " << fname;
throw(std::runtime_error(msg.str()));
}
//build the scanf format
std::ostringstream format;
format << "%[^\0" << delim << "]";
//read and store each record (one per line)
CSVObject<N> object;
while(!is.eof()) {
//get a line
std::string tmpLine;
getline(is, tmpLine);
//skip blank and comment lines
if (tmpLine.size() == 0 || tmpLine[0] == '#') {
continue;
}
//read and store each field
CSVElement<N> record;
for (int i = 0; i < N; ++i) {
//get a field
char tmpField[256];
memset(tmpField, 0, 256);
sscanf(tmpLine.c_str(), format.str().c_str(), tmpField);
//prune the input
int len = std::min(strlen(tmpField)+1, tmpLine.size());
tmpLine = tmpLine.substr(len);
//store the field
record[i] = tmpField;
}
object.push_back(record);
}
//finally, close the file
is.close();
return object;
}
template<int N>
void writeCSV(std::string fname, CSVObject<N> const& object, char delim = ',') {
//open the file
std::ofstream os(fname);
if (!os.is_open()) {
std::ostringstream msg;
msg << "Failed to open file: " << fname;
throw(std::runtime_error(msg.str()));
}
//write each record, one at a time
for(auto& record : object) {
//write each field, one at a time
for (int i = 0; i < N; i++) {
os << record[i];
//print delimiter
if (i != N -1) {
os << delim;
}
}
os << std::endl;
}
//finish
os.close();
}
+5
View File
@@ -0,0 +1,5 @@
#Format (4 columns): "name", type, "sprite.png", stackable
"Sword",weapon,"sword.png",false
"Staff",weapon,"staff.png",false
"Dagger",weapon,"dagger.png",false
"Potion",consumable,"potion.png",true
Can't render this file because it contains an unexpected character in line 1 and column 22.
+32 -63
View File
@@ -57,7 +57,23 @@ CREATE TABLE IF NOT EXISTS LiveCharacters (
--physically exists in the world
roomIndex INTEGER DEFAULT 0,
originX INTEGER DEFAULT 0,
originY INTEGER DEFAULT 0
originY INTEGER DEFAULT 0,
--combat stats
level INTEGER DEFAULT 0,
exp INTEGER DEFAULT 0,
maxHP INTEGER DEFAULT 0,
health INTEGER DEFAULT 0,
maxMP INTEGER DEFAULT 0,
mana INTEGER DEFAULT 0,
attack INTEGER DEFAULT 0,
defence INTEGER DEFAULT 0,
intelligence INTEGER DEFAULT 0,
resistance INTEGER DEFAULT 0,
accuracy INTEGER DEFAULT 0,
evasion INTEGER DEFAULT 0,
speed INTEGER DEFAULT 0,
luck INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS DeadCharacters (
@@ -68,23 +84,21 @@ CREATE TABLE IF NOT EXISTS DeadCharacters (
handle varchar(100),
avatar varchar(100),
birth timestamp NOT NULL,
death timestamp NOT NULL DEFAULT (datetime())
);
death timestamp NOT NULL DEFAULT (datetime()),
CREATE TABLE IF NOT EXISTS LiveCreatures (
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
--combat stats
level INTEGER DEFAULT 0,
exp INTEGER DEFAULT 0,
maxHP INTEGER DEFAULT 0,
maxMP INTEGER DEFAULT 0,
attack INTEGER DEFAULT 0,
defence INTEGER DEFAULT 0,
intelligence INTEGER DEFAULT 0,
resistance INTEGER DEFAULT 0,
accuracy INTEGER DEFAULT 0,
evasion INTEGER DEFAULT 0,
speed INTEGER DEFAULT 0,
luck INTEGER DEFAULT 0
);
-------------------------
@@ -105,49 +119,4 @@ CREATE TABLE IF NOT EXISTS InventoryItems (
--member tables
-------------------------
CREATE TABLE IF NOT EXISTS CombatStatistics (
--metadata
uid INTEGER PRIMARY KEY AUTOINCREMENT,
--general use statistics
level INTEGER DEFAULT 0,
exp INTEGER DEFAULT 0,
maxHP INTEGER DEFAULT 0,
health INTEGER DEFAULT 0,
maxMP INTEGER DEFAULT 0,
mana INTEGER DEFAULT 0,
attack INTEGER DEFAULT 0,
defence INTEGER DEFAULT 0,
intelligence INTEGER DEFAULT 0,
resistance INTEGER DEFAULT 0,
accuracy REAL DEFAULT 0.0,
evasion REAL DEFAULT 0.0,
speed INTEGER DEFAULT 0,
luck REAL DEFAULT 0.0
);
-------------------------
--cross reference tables
-------------------------
CREATE TABLE IF NOT EXISTS CharacterStatistics (
character INTEGER,
statistic INTEGER,
FOREIGN KEY (character) REFERENCES LiveCharacters(uid),
FOREIGN KEY (statistic) REFERENCES CombatStatistics(uid)
);
CREATE TABLE IF NOT EXISTS CharacterItems (
character INTEGER,
item INTEGER,
FOREIGN KEY (character) REFERENCES LiveCharacters(uid),
FOREIGN KEY (item) REFERENCES InventoryItem(uid)
);
CREATE TABLE IF NOT EXISTS CharacterEquipment (
character INTEGER,
item INTEGER,
FOREIGN KEY (character) REFERENCES LiveCharacters(uid),
FOREIGN KEY (item) REFERENCES InventoryItem(uid)
);
--TODO
-11
View File
@@ -21,14 +21,3 @@
*/
#include "inventory_manager.hpp"
static const char* CREATE_CHARACTER_ITEMS = "INSERT INTO CharacterItems (character, item) VALUES (?1, ?2);";
static const char* DELETE_CHARACTER_ITEMS = "DELETE FROM CharacterItems WHERE (character=?1, item=?2);";
static const char* CREATE_CHARACTER_EQUIPMENT = "INSERT INTO CharacterEquipment (character, item) VALUES (?1, ?2);";
static const char* DELETE_CHARACTER_EQUIPMENT = "DELETE FROM CharacterEquipment WHERE (character=?1, item=?2);";
int InventoryManager::CreateItem(int owner, ItemType itemType) {
sqlite3_stmt* statement = nullptr;
}
+1 -1
View File
@@ -1,5 +1,5 @@
#config
INCLUDES+=. .. ../characters ../creatures ../entities ../../common/gameplay ../../common/utilities
INCLUDES+=. .. ../characters ../creatures ../entities ../inventory ../../common/gameplay ../../common/utilities
LIBS+=
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))
+1 -1
View File
@@ -1,5 +1,5 @@
#config
INCLUDES+=. .. ../characters ../combat ../creatures ../entities ../monsters ../triggers ../../common/gameplay ../../common/map ../../common/network ../../common/network/packet_types ../../common/utilities
INCLUDES+=. .. ../characters ../combat ../creatures ../entities ../inventory ../monsters ../triggers ../../common/gameplay ../../common/map ../../common/network ../../common/network/packet_types ../../common/utilities
LIBS+=
CXXFLAGS+=-std=c++11 $(addprefix -I,$(INCLUDES))