There are several forms of the name for this.
NVI is the abbreviation.
NetVarInterface is the short-hand term.
Networked Variable Interface is the full name.
The name says it all. It's a platform-independent interface to store variables (strings, integers, float values, and even Vector3 values). What's the difference? It keeps track of what has changed, and gives them GUIDs (globally unique identifiers) so they can be used with your clients.
Too bad I'm not entirely done. There's a separate version for servers and clients. I finished the server part, but have yet to start with the client (just a modified form of the server version).
Basically, you get an NVI and you can store values by name in the interface. Then you can loop through the vector of NetVars and send them if their HasChanged() method returns true. If not, why send them and waste bandwidth?
Enough explanation, have at it.
NVI.h (53 lines)
#ifndef NetVar_h
#define NetVar_h
#include <string>
#include <sstream>
#include <vector>
#include "util/Vector3.h"
#include <iostream>
using namespace std;
class NetVarInterface
{
public:
class NetVar
{
private:
string Var;
bool changed;
public:
NetVar(string Value);
string GetNetVar();
void SetNetVar(string NewVal);
void UpdateNetVar(string NewVal);
bool HasChanged();
int GUID;
string Name;
};
vector<NetVar> NetVars;
void CreateValue(string NVName, string NewVal);
void CreateValue(string NVName, float NewVal);
void CreateValue(string NVName, int NewVal);
void CreateValue(string NVName, Vector3 NewVal);
void SetValue(string NVName, string NewVal);
void SetValue(string NVName, float NewVal);
void SetValue(string NVName, int NewVal);
void SetValue(string NVName, Vector3 NewVal);
int GetInt(string NVName);
float GetFloat(string NVName);
Vector3 GetVec3(string NVName);
string GetString(string NVName);
int RegisterGUID();
};
#endif
NVI.cpp (248 lines, yes, it's not quite so small!)
#include "NetVar.h"
int NetVarInterface::RegisterGUID()
{
static int last_guid = -1;
last_guid++;
return last_guid;
}
NetVarInterface::NetVar::NetVar(string Value)
{
Var = Value;
changed = true;
}
void NetVarInterface::NetVar::UpdateNetVar(string NewVal)
{
Var = NewVal;
}
void NetVarInterface::NetVar::SetNetVar(string NewVal)
{
UpdateNetVar(NewVal);
changed = true;
}
string NetVarInterface::NetVar::GetNetVar()
{
return Var;
}
bool NetVarInterface::NetVar::HasChanged()
{
if (changed)
{
changed = false;
return true;
}
return false;
}
Vector3 NetVarInterface::GetVec3(string NVName)
{
for (unsigned i = 0; i < NetVars.size(); i++)
{
if (NetVars.at(i).Name == NVName)
{
string val = NetVars.at(i).GetNetVar();
Vector3 tmp(0.0f, 0.0f, 0.0f);
string valtmp;
float valtmp2;
stringstream sstr;
int sep = val.find(",");
valtmp = val.substr(0, sep);
sstr << valtmp; sstr >> valtmp2;
tmp.x(valtmp2);
val = val.substr(sep + 1);
sep = val.find(",");
valtmp = val.substr(0, sep);
sstr << valtmp; sstr >> valtmp2;
tmp.y(valtmp2);
val = val.substr(sep + 1);
sep = val.find(",");
valtmp = val.substr(0, sep);
sstr << valtmp; sstr >> valtmp2;
tmp.z(valtmp2);
return tmp;
}
}
return Vector3();
}
int NetVarInterface::GetInt(string NVName)
{
for (unsigned i = 0; i < NetVars.size(); i++)
{
if (NetVars.at(i).Name == NVName)
{
int val;
stringstream sstr;
sstr<<NetVars.at(i).GetNetVar();
sstr>>val;
}
}
return 0;
}
float NetVarInterface::GetFloat(string NVName)
{
for (unsigned i = 0; i < NetVars.size(); i++)
{
if (NetVars.at(i).Name == NVName)
{
float val;
stringstream sstr;
sstr<<NetVars.at(i).GetNetVar();
sstr>>val;
}
}
return 0;
}
string NetVarInterface::GetString(string NVName)
{
for (unsigned i = 0; i < NetVars.size(); i++)
{
if (NetVars.at(i).Name == NVName)
{
return NetVars.at(i).GetNetVar();
}
}
return "";
}
void NetVarInterface::CreateValue(string NVName, string NewVal)
{
NetVar nv(NewVal);
nv.Name = NVName;
nv.GUID = RegisterGUID();
NetVars.push_back(nv);
}
void NetVarInterface::CreateValue(string NVName, float NewVal)
{
stringstream ss;
ss << NewVal;
string tmp;
ss >> tmp;
NetVar nv(tmp);
nv.Name = NVName;
nv.GUID = RegisterGUID();
NetVars.push_back(nv);
}
void NetVarInterface::CreateValue(string NVName, int NewVal)
{
stringstream ss;
ss << NewVal;
string tmp;
ss >> tmp;
NetVar nv(tmp);
nv.Name = NVName;
nv.GUID = RegisterGUID();
NetVars.push_back(nv);
}
void NetVarInterface::CreateValue(string NVName, Vector3 NewVal)
{
string tmp;
string tmp2;
stringstream ss;
ss << NewVal.x();
ss >> tmp2;
tmp += tmp2;
ss.clear();
tmp += ",";
ss << NewVal.y();
ss >> tmp2;
tmp += tmp2;
ss.clear();
tmp += ",";
ss << NewVal.z();
ss >> tmp2;
tmp += tmp2;
ss.clear();
NetVar nv(tmp);
nv.Name = NVName;
nv.GUID = RegisterGUID();
NetVars.push_back(nv);
}
void NetVarInterface::SetValue(string NVName, string NewVal)
{
for (unsigned i = 0; i < NetVars.size(); i++)
{
if (NetVars.at(i).Name == NVName)
{
NetVars.at(i).SetNetVar(NewVal);
}
}
}
void NetVarInterface::SetValue(string NVName, float NewVal)
{
for (unsigned i = 0; i < NetVars.size(); i++)
{
if (NetVars.at(i).Name == NVName)
{
stringstream ss;
ss << NewVal;
string tmp;
ss >> tmp;
NetVars.at(i).SetNetVar(tmp);
}
}
}
void NetVarInterface::SetValue(string NVName, int NewVal)
{
for (unsigned i = 0; i < NetVars.size(); i++)
{
if (NetVars.at(i).Name == NVName)
{
stringstream ss;
ss << NewVal;
string tmp;
ss >> tmp;
NetVars.at(i).SetNetVar(tmp);
}
}
}
void NetVarInterface::SetValue(string NVName, Vector3 NewVal)
{
for (unsigned i = 0; i < NetVars.size(); i++)
{
if (NetVars.at(i).Name == NVName)
{
string tmp;
string tmp2;
stringstream ss;
ss << NewVal.x();
ss >> tmp2;
tmp += tmp2;
ss.clear();
tmp += ",";
ss << NewVal.y();
ss >> tmp2;
tmp += tmp2;
ss.clear();
tmp += ",";
ss << NewVal.z();
ss >> tmp2;
tmp += tmp2;
ss.clear();
NetVars.at(i).SetNetVar(tmp);
}
}
}
It also requires my Vector3 class. It's very easy to use, don't worry.
Vector3.h (71 lines)
#ifndef Vector3_h
#define Vector3_h
class Vector3
{
private:
float tx, ty, tz;
public:
///Constructor
Vector3(float fx = 0.0f, float fy = 0.0f, float fz = 0.0f);
///Add two vectors together
Vector3 & operator+(Vector3 & item);
///Subtract the right vector from the left.
Vector3 & operator-(Vector3 & item);
///Increment left vector by the right.
Vector3 & operator+=(Vector3 & item);
///Decrement left vector by the right.
Vector3 & operator-=(Vector3 & item);
///Scale the left vector by the right float.
Vector3 & operator*=(float & scalar);
///Scale the left vector by the right float.
Vector3 & operator*(float & scalar);
///Scale the left vector by the right vector.
Vector3 & operator*=(Vector3 & scalar);
///Scale the left vector by the right vector.
Vector3 & operator*(Vector3 & scalar);
///Divide the left vector by the right vector.
Vector3 & operator/=(Vector3 & scalar);
///Divide the left vector by the right vector.
Vector3 & operator/(Vector3 & scalar);
///Divide the left vector by the right float.
Vector3 & operator/=(float & scalar);
///Divide the left vector by the right float.
Vector3 & operator/(float & scalar);
///Get the length of the current vector.
float length();
///Get the distance between vectors ((Vector3_1 - Vector3_2).length()).
float distance(Vector3 item);
///Get the unit vector of the current vector.
Vector3 unit();
///Get the direction between two vectors.
Vector3 direction(Vector3 item);
///Returns the dot product of the two vectors.
float dot(Vector3 item);
///Returns the cross product of the two vectors.
Vector3 cross(Vector3 item);
///Get the current x value.
float x() { return tx; }
///Get the current y value.
float y() { return ty; }
///Get the current z value.
float z() { return tz; }
///Set the current x value.
void x(float newx) { tx = newx; }
///Set the current y value.
void y(float newy) { ty = newy; }
///Set the current z value.
void z(float newz) { tz = newz; }
Vector3 Lerp(Vector3 Item, float Alpha);
};
#ifdef Vector3_DEBUG
void OutputVector3(Vector3 vec)
{
std::cout<<"Vector3; x: "<<vec.x()<<"; y: "<<vec.y()<<"; z: "<<vec.z();
}
#endif
#endif//Vector3_h
Vector3.cpp (130 lines)
#include "Vector3.h"
#include <cmath>
Vector3::Vector3(float fx, float fy, float fz)
{
this->tx = fx;
this->ty = fy;
this->tz = fz;
}
Vector3 & Vector3::operator+=(Vector3 & item)
{
this->tx = this->tx + item.x();
this->ty = this->ty + item.y();
this->tz = this->tz + item.z();
return *this;
}
Vector3 & Vector3::operator-=(Vector3 & item)
{
this->tx = this->tx - item.x();
this->ty = this->ty - item.y();
this->tz = this->tz - item.z();
return *this;
}
Vector3 & Vector3::operator*=(Vector3 & scalar)
{
tx = tx * scalar.x();
ty = ty * scalar.y();
tz = tz * scalar.z();
return *this;
}
Vector3 & Vector3::operator*=(float & scalar)
{
tx = tx * scalar;
ty = ty * scalar;
tz = tz * scalar;
return *this;
}
Vector3 & Vector3::operator/=(Vector3 & scalar)
{
tx = tx / scalar.x();
ty = ty / scalar.y();
tz = tz / scalar.z();
return *this;
}
Vector3 & Vector3::operator/=(float & scalar)
{
tx = tx / scalar;
ty = ty / scalar;
tz = tz / scalar;
return *this;
}
Vector3 & Vector3::operator*(Vector3 & scalar)
{
return Vector3(*this) *= scalar;
}
Vector3 & Vector3::operator*(float & scalar)
{
return Vector3(*this) *= scalar;
}
Vector3 & Vector3::operator/(Vector3 & scalar)
{
return Vector3(*this) /= scalar;
}
Vector3 & Vector3::operator/(float & scalar)
{
return Vector3(*this) /= scalar;
}
Vector3 & Vector3::operator+(Vector3 & item)
{
return Vector3(*this) += item;
}
Vector3 & Vector3::operator-(Vector3 & item)
{
return Vector3(*this) += item;
}
float Vector3::length()
{
return std::abs(std::sqrt(tx * tx + ty * ty + tz * tz));
}
float Vector3::distance(Vector3 item)
{
return Vector3(*this - item).length();
}
Vector3 Vector3::unit()
{
Vector3 result = *this;
float length = result.length();
result = result / length;
return result;
}
Vector3 Vector3::direction(Vector3 item)
{
return Vector3(*this - item).unit();
}
float Vector3::dot(Vector3 item)
{
return (tx * item.x() + ty * item.y() + tz * item.z());
}
Vector3 Vector3::cross(Vector3 item)
{
return Vector3(ty * item.z() - tz * item.y(), tz * item.x() - tx * item.z(), tx * item.y() - ty * item.x());
}
Vector3 Vector3::Lerp(Vector3 Item, float Alpha)
{
Vector3 Return = Vector3(0.0f, 0.0f, 0.0f);
Return.x(this->x()*(1 - Alpha) + Item.x() * Alpha);
Return.y(this->y()*(1 - Alpha) + Item.y() * Alpha);
Return.z(this->z()*(1 - Alpha) + Item.z() * Alpha);
return Return;
}
Yep, Vector3 has it's own Intellisense interface via triple-slash comments!
If you read through the source, you would know this, but yeah, you don't have to read it all.
NVI casts anything. If you store a Vector3 and try to get it as a string, you'll get "x,y,z". You can add in exceptions if you want, but I like the looseness of it myself. It's a lot like KaosScript in how it stores things.