diff options
| author | Alexander Pickering <alexandermpickering@gmail.com> | 2017-10-18 21:34:55 -0400 |
|---|---|---|
| committer | Alexander Pickering <alexandermpickering@gmail.com> | 2017-10-18 21:34:55 -0400 |
| commit | 33e6b9627e6a46d388d46f2c5b4d15ba7e9f9904 (patch) | |
| tree | 18d24b74e48d8b7e9cb656272df7a48b28d3b6c8 /src | |
| parent | 76b4fddee6106b60dbc6da6d7bcef61b42a3c310 (diff) | |
| download | brokengine-33e6b9627e6a46d388d46f2c5b4d15ba7e9f9904.tar.gz brokengine-33e6b9627e6a46d388d46f2c5b4d15ba7e9f9904.tar.bz2 brokengine-33e6b9627e6a46d388d46f2c5b4d15ba7e9f9904.zip | |
Started refactoring
* Finished a basic server
* Changed from ZMQ to nanomsg (basically the same though)
* Moved some repeated code from the client/server directories into
"shared"
* Edited makefile to reflect new dependencies
Diffstat (limited to 'src')
| -rw-r--r-- | src/client/lua_api/load_scene.cpp (renamed from src/client/lua_api/load_core.cpp) | 2 | ||||
| -rw-r--r-- | src/client/lua_api/load_scene.hpp (renamed from src/client/lua_api/load_core.hpp) | 6 | ||||
| -rw-r--r-- | src/client/lua_api/phys/bphysbox.cpp | 3 | ||||
| -rw-r--r-- | src/client/lua_api/phys/bphysmodel.cpp | 3 | ||||
| -rw-r--r-- | src/client/main.cpp | 222 | ||||
| -rw-r--r-- | src/client/menuhandeler.cpp | 3 | ||||
| -rw-r--r-- | src/server/main.cpp | 57 | ||||
| -rw-r--r-- | src/server/testclient.cpp | 110 | ||||
| -rw-r--r-- | src/shared/lua_api/common.c | 38 | ||||
| -rw-r--r-- | src/shared/lua_api/common.h | 13 | ||||
| -rw-r--r-- | src/shared/lua_api/load_net.cpp | 224 | ||||
| -rw-r--r-- | src/shared/lua_api/load_net.hpp | 8 | ||||
| -rw-r--r-- | src/shared/phys/physcommon.cpp | 84 | ||||
| -rw-r--r-- | src/shared/phys/physcommon.hpp | 4 | ||||
| -rw-r--r-- | src/shared/util/hashmap.c | 397 | ||||
| -rw-r--r-- | src/shared/util/hashmap.h | 81 |
16 files changed, 1091 insertions, 164 deletions
diff --git a/src/client/lua_api/load_core.cpp b/src/client/lua_api/load_scene.cpp index 4a74d39..285cba0 100644 --- a/src/client/lua_api/load_core.cpp +++ b/src/client/lua_api/load_scene.cpp @@ -18,7 +18,7 @@ using namespace irr; extern IrrlichtDevice* device; -void load_corefuncs(lua_State* L){ +void load_scenefuncs(lua_State* L){ icamera_register(L,device); imesh_register(L,device); ilight_register(L,device); diff --git a/src/client/lua_api/load_core.hpp b/src/client/lua_api/load_scene.hpp index b3b42ff..7602d08 100644 --- a/src/client/lua_api/load_core.hpp +++ b/src/client/lua_api/load_scene.hpp @@ -1,5 +1,5 @@ -#ifndef __H_loadcore -#define __H_loadcore +#ifndef __H_loadscene +#define __H_loadscene #include <stdio.h> #include <stdlib.h> #include <vector> @@ -10,5 +10,5 @@ extern "C" { } #include <irrlicht.h> -void load_corefuncs(lua_State* L); +void load_scenefuncs(lua_State* L); #endif diff --git a/src/client/lua_api/phys/bphysbox.cpp b/src/client/lua_api/phys/bphysbox.cpp index 80cd2eb..a03b488 100644 --- a/src/client/lua_api/phys/bphysbox.cpp +++ b/src/client/lua_api/phys/bphysbox.cpp @@ -5,6 +5,7 @@ #include <memory> #include <map> #include <functional> +#include <list> extern "C" { #include <lua.h> #include <lauxlib.h> @@ -24,7 +25,7 @@ using namespace video; extern IrrlichtDevice* device; extern btDiscreteDynamicsWorld* World; -extern core::list<btRigidBody*> Objects; +extern std::list<btRigidBody*> Objects; static LBPhysNode* checkisbphysbox(lua_State* L, int index){ void* ud = luaL_checkudata(L,index,"phys.physbox"); diff --git a/src/client/lua_api/phys/bphysmodel.cpp b/src/client/lua_api/phys/bphysmodel.cpp index 7bdc483..b76b336 100644 --- a/src/client/lua_api/phys/bphysmodel.cpp +++ b/src/client/lua_api/phys/bphysmodel.cpp @@ -5,6 +5,7 @@ #include <memory> #include <map> #include <functional> +#include <list> extern "C" { #include <lua.h> #include <lauxlib.h> @@ -25,7 +26,7 @@ using namespace video; extern IrrlichtDevice* device; extern btDiscreteDynamicsWorld* World; -extern core::list<btRigidBody*> Objects; +extern std::list<btRigidBody*> Objects; static LBPhysNode* checkisbphysmodel(lua_State* L, int index){ void* ud = luaL_checkudata(L,index,"phys.physmodel"); diff --git a/src/client/main.cpp b/src/client/main.cpp index 52de76f..763c9f3 100644 --- a/src/client/main.cpp +++ b/src/client/main.cpp @@ -7,6 +7,8 @@ extern "C" { } #include <irrlicht.h> +#include <chrono> + #include <btBulletDynamicsCommon.h> #include <cstdlib> @@ -14,139 +16,65 @@ extern "C" { #include "menuhandeler.hpp" #include "lua_api/load_gui.hpp" #include "lua_api/load_game.hpp" -#include "lua_api/load_core.hpp" +#include "lua_api/load_scene.hpp" #include "lua_api/load_phys.hpp" #include "callbackhandeler.hpp" +#include "../shared/lua_api/common.h" +#include "../shared/lua_api/load_net.hpp" +#include "../shared/phys/physcommon.hpp" + using namespace irr; using namespace core; using namespace scene; using namespace video; using namespace io; using namespace gui; +using namespace std::chrono; -btDiscreteDynamicsWorld* World; -core::list<btRigidBody*> Objects; - -void loadLLibs(lua_State* L){ - luaopen_base(L); - luaopen_table(L); - luaopen_io(L); - luaopen_string(L); - luaopen_math(L); -} +//btDiscreteDynamicsWorld* World; +//irr::core::list<btRigidBody*> Objects; lua_State* L; IrrlichtDevice* device; void loadIrrLibs(lua_State* L, IrrlichtDevice* device){ - printf("Loading guifuncs...\n"); - load_guifuncs(L); - load_gamefuncs(L); - load_corefuncs(L); - load_physfuncs(L); + printf("Loading guifuncs...\n"); + load_guifuncs(L); + load_gamefuncs(L); + load_scenefuncs(L); + load_physfuncs(L); } static int GetRandInt(int TMax) { return rand() % TMax; } +void RemoveISceneNode(btRigidBody* rb){ + ISceneNode *Node = static_cast<ISceneNode*>(rb->getUserPointer()); + Node->remove(); +} +/* // Removes all objects from the world -void ClearObjects() { +void ClearObjects(btDiscreteDynamicsWorld* wr, core::list<btRigidBody*> objs, void(*f)(btRigidBody*)) { - for(list<btRigidBody *>::Iterator Iterator = Objects.begin(); Iterator != Objects.end(); ++Iterator) { + for(list<btRigidBody *>::Iterator Iterator = objs.begin(); Iterator != objs.end(); ++Iterator) { btRigidBody *Object = *Iterator; - printf("Found an object to clean:%p\n",Object); - + if(f){ + (*f)(Object); + } // Delete irrlicht node ISceneNode *Node = static_cast<ISceneNode *>(Object->getUserPointer()); - printf("got node\n"); Node->remove(); - printf("removed node\n"); + // Remove the object from the world - World->removeRigidBody(Object); - printf("removed rigidbody\n"); - printf("right before delete, object is %p\n",Object); + wr->removeRigidBody(Object); delete Object; - printf("deleted object\n"); } - - Objects.clear(); + objs.clear(); } +*/ -// Create a box rigid body -// void CreateBox(ISceneManager* irrScene, const btVector3 &TPosition, const core::vector3df &TScale, btScalar TMass) { -// -// // Create an Irrlicht cube -// scene::ISceneNode *Node = irrScene->addCubeSceneNode(1.0f); -// Node->setScale(TScale); -// -// Node->setMaterialFlag(video::EMF_LIGHTING, 1); -// Node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); -// //Node->setMaterialTexture(0, irrDriver->getTexture("rust0.jpg")); -// -// // Set the initial position of the object -// btTransform Transform; -// Transform.setIdentity(); -// Transform.setOrigin(TPosition); -// -// // Give it a default MotionState -// btDefaultMotionState *MotionState = new btDefaultMotionState(Transform); -// -// // Create the shape -// btVector3 HalfExtents(TScale.X * 0.5f, TScale.Y * 0.5f, TScale.Z * 0.5f); -// btCollisionShape *Shape = new btBoxShape(HalfExtents); -// -// // Add mass -// btVector3 LocalInertia; -// Shape->calculateLocalInertia(TMass, LocalInertia); -// -// // Create the rigid body object -// btRigidBody *RigidBody = new btRigidBody(TMass, MotionState, Shape, LocalInertia); -// -// // Store a pointer to the irrlicht node so we can update it later -// RigidBody->setUserPointer((void *)(Node)); -// -// // Add it to the world -// World->addRigidBody(RigidBody); -// Objects.push_back(RigidBody); -// } -// -// // Create a sphere rigid body -// void CreateSphere(ISceneManager* irrScene, const btVector3 &TPosition, btScalar TRadius, btScalar TMass) { -// -// // Create an Irrlicht sphere -// scene::ISceneNode *Node = irrScene->addSphereSceneNode(TRadius, 32); -// Node->setMaterialFlag(video::EMF_LIGHTING, 1); -// Node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true); -// //Node->setMaterialTexture(0, irrDriver->getTexture("ice0.jpg")); -// -// // Set the initial position of the object -// btTransform Transform; -// Transform.setIdentity(); -// Transform.setOrigin(TPosition); -// -// // Give it a default MotionState -// btDefaultMotionState *MotionState = new btDefaultMotionState(Transform); -// -// // Create the shape -// btCollisionShape *Shape = new btSphereShape(TRadius); -// -// // Add mass -// btVector3 LocalInertia; -// Shape->calculateLocalInertia(TMass, LocalInertia); -// -// // Create the rigid body object -// btRigidBody *RigidBody = new btRigidBody(TMass, MotionState, Shape, LocalInertia); -// -// // Store a pointer to the irrlicht node so we can update it later -// RigidBody->setUserPointer((void *)(Node)); -// -// // Add it to the world -// World->addRigidBody(RigidBody); -// Objects.push_back(RigidBody); -// } -// -// // Converts a quaternion to an euler angle +// Converts a quaternion to an euler angle void QuaternionToEuler(const btQuaternion &TQuat, btVector3 &TEuler) { btScalar W = TQuat.getW(); btScalar X = TQuat.getX(); @@ -163,19 +91,9 @@ void QuaternionToEuler(const btQuaternion &TQuat, btVector3 &TEuler) { TEuler *= core::RADTODEG; } -// Runs the physics simulation. -// - TDeltaTime tells the simulation how much time has passed since the last frame so the simulation can run independently of the frame rate. -void UpdatePhysics(u32 TDeltaTime) { - - World->stepSimulation(TDeltaTime * 0.002f, 60); - - btRigidBody *TObject; - // Relay the object's orientation to irrlicht - for(core::list<btRigidBody *>::Iterator it = Objects.begin(); it != Objects.end(); ++it) { - +void UpdateElement(btRigidBody* TObject){ //UpdateRender(*Iterator); - scene::ISceneNode *Node = static_cast<scene::ISceneNode *>((*it)->getUserPointer()); - TObject = *it; + scene::ISceneNode *Node = static_cast<scene::ISceneNode *>((TObject)->getUserPointer()); // Set position btVector3 Point = TObject->getCenterOfMassPosition(); @@ -185,20 +103,25 @@ void UpdatePhysics(u32 TDeltaTime) { btVector3 EulerRotation; QuaternionToEuler(TObject->getOrientation(), EulerRotation); Node->setRotation(core::vector3df(EulerRotation[0], EulerRotation[1], EulerRotation[2])); - - } } +/* +// Runs the physics simulation. +// - TDeltaTime tells the simulation how much time has passed since the last frame so the simulation can run independently of the frame rate. Optionally pass in an argument that will be called on every rigidbody in the world +void UpdatePhysics(double TDeltaTime, void(*f)(btRigidBody*)) { -// Creates a base box -void CreateStartScene(ISceneManager* smgr) { + World->stepSimulation(TDeltaTime * 0.02f, 60); - ClearObjects(); - //CreateBox(smgr,btVector3(0.0f, 0.0f, 0.0f), core::vector3df(10.0f, 0.5f, 10.0f), 0.0f); + // Relay the object's orientation to irrlicht + for(core::list<btRigidBody *>::Iterator it = Objects.begin(); it != Objects.end(); ++it) { + (*f)(*it); + } } +*/ int main(int argc, char *argv[]){ - printf("Brok[en]gine"); + printf("Brok[en]gine Client"); // Initialize bullet + /* btBroadphaseInterface *BroadPhase = new btAxisSweep3(btVector3(-1000, -1000, -1000), btVector3(1000, 1000, 1000)); printf("Broadphase\n"); btDefaultCollisionConfiguration *CollisionConfiguration = new btDefaultCollisionConfiguration(); @@ -209,6 +132,9 @@ int main(int argc, char *argv[]){ printf("Solver\n"); World = new btDiscreteDynamicsWorld(Dispatcher, BroadPhase, Solver, CollisionConfiguration); printf("Physics world init ok.\n"); + */ + phys_genesis(); + //Create a new lua state, this gets shared everywhere lua_State *state = luaL_newstate(); L = state; @@ -220,6 +146,7 @@ int main(int argc, char *argv[]){ return 1; //Loads libraries for interfaceing with irrlicht loadIrrLibs(state,device); + loadNetLibs(state); printf("Loadded irr libs...\n"); //Sets the global event handeler GlobalEventReceiver ger = GlobalEventReceiver(device); @@ -240,44 +167,22 @@ int main(int argc, char *argv[]){ IGUIEnvironment* guienv = device->getGUIEnvironment(); ITimer* irrTimer = device->getTimer(); - device->setWindowCaption(L"Bork[en]gine Demo"); - - /* - CreateBox(smgr, - btVector3( - GetRandInt(10) - 5.0f, 7.0f, - GetRandInt(10) - 5.0f), - core::vector3df( - GetRandInt(3) + 0.5f, - GetRandInt(3) + 0.5f, - GetRandInt(3) + 0.5f), - 1.0f); - CreateBox(smgr, - btVector3(0,0,0), - core::vector3df(10,10,10), - 0.0f); - CreateSphere(smgr, - btVector3( - GetRandInt(10) - 5.0f, 7.0f, - GetRandInt(10) - 5.0f), - GetRandInt(5) / 5.0f + 0.2f, 1.0f); - */ - - //guienv->addStaticText(L"Hello World! This is the Irrlicht Software renderer!", - // rect<s32>(10,10,260,22), true); - printf("Abbout to add camera\n"); - //smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0)); - //smgr->addCameraSceneNodeMaya(); + device->setWindowCaption(L"Bork[en]gine Client"); printf("Everything registered, about to start running device!\n"); - u32 TimeStamp = irrTimer->getTime(), DeltaTime = 0; + //u32 TimeStamp = irrTimer->getTime(), DeltaTime = 0; + //high_resolution_clock::time_point t1 = high_resolution_clock::now(); while(device->run()){ - if(device->isWindowActive()){ - DeltaTime = irrTimer->getTime() - TimeStamp; - TimeStamp = irrTimer->getTime(); - UpdatePhysics(DeltaTime); + gameloop_net(L); + gameloop_phys(UpdateElement); + if(device->isWindowActive()){ + //high_resolution_clock::time_point now = high_resolution_clock::now(); + //duration<double> delta = now-t1; + //double steps = delta.count() * 100; + //UpdatePhysics(steps,UpdateElement); + //t1 = now; driver->beginScene(true, true, SColor(255,100,101,140)); @@ -294,10 +199,12 @@ int main(int argc, char *argv[]){ lua_call(state,0,0); lua_pop(state,2); } - printf("Claoseing lua state...\n"); + printf("Closeing lua state...\n"); //lua_close(state); - printf("clearing objects...\n"); - ClearObjects(); //Clearing objects must be done after we droped the device. + //printf("clearing objects...\n"); + //ClearObjects(World,Objects,RemoveISceneNode); //Clearing objects must be done after we droped the device. + phys_shutdown(RemoveISceneNode); + /* printf("cleared objects\n"); delete BroadPhase; printf("deleted broadphase\n"); @@ -310,6 +217,7 @@ int main(int argc, char *argv[]){ delete World; //Muah ha ha printf("deleted world\n"); + */ device->drop(); printf("droped device\n"); diff --git a/src/client/menuhandeler.cpp b/src/client/menuhandeler.cpp index 830c695..53d38cc 100644 --- a/src/client/menuhandeler.cpp +++ b/src/client/menuhandeler.cpp @@ -15,7 +15,8 @@ using namespace io; using namespace gui; void loadMenu(const char* name, IrrlichtDevice* device){ - + IGUIEnvironment* env = device->getGUIEnvironment(); + IGUIWindow* window = env->addWindow(rect<s32>(0,0,200,200),true,L"Menu",0,-1); } void showMenu(const char* name, IrrlichtDevice* device){ diff --git a/src/server/main.cpp b/src/server/main.cpp new file mode 100644 index 0000000..846ec2b --- /dev/null +++ b/src/server/main.cpp @@ -0,0 +1,57 @@ + +#include <stdio.h> +#include <stdlib.h> +#include "../shared/util/hashmap.h" +extern "C" { + #include <lua.h> + #include <lauxlib.h> + #include <lualib.h> +} + +//C++ things +#include <vector> +#include <thread> +#include <list> + +#include <string.h> // for strstr() +#include <nn.h> +#include <tcp.h> +#include <pair.h> + +#include <btBulletDynamicsCommon.h> +#include <cstdlib> + +#include "../shared/lua_api/common.h" +#include "../shared/lua_api/load_net.hpp" +#include "../shared/phys/physcommon.hpp" + +using namespace std; +using namespace chrono; + +lua_State* L; +void gameloop(){ + gameloop_phys(NULL); + gameloop_net(L); +} + +int main (){ + printf("Brok[en]gine Server\n"); + L = luaL_newstate(); + + phys_genesis(); + loadLLibs(L); + loadNetLibs(L); + int iErr = luaL_dofile(L,"../data/init.lua"); + if(iErr != 0){ + lua_error(L); + printf("Failed to open lua file:../data/init.lua\n"); + } + do{ + + gameloop(); + std::this_thread::yield(); + }while(true); + phys_shutdown(NULL); + + return 0; +} diff --git a/src/server/testclient.cpp b/src/server/testclient.cpp new file mode 100644 index 0000000..0aab8a2 --- /dev/null +++ b/src/server/testclient.cpp @@ -0,0 +1,110 @@ +// +// // Minimal C ZMQ Client example +// +// // Properties -> Linker -> Input -> Additional dependencies "libzmq.lib" +// // Properties -> Linker -> Input -> Additional dependencies "ws2_32.lib" +// +// #include <stdio.h> +// #include "zmq.h" +// +// +// #define WS_VER 0x0202 +// #define DEFAULT_PORT "5001" +// +// +// int main () +// { +// int retval; +// void *ctx, *s; +// zmq_msg_t query, reply; +// const char *query_string = "SELECT * FROM sometable, END SERVER", *reply_string; +// +// +// printf( "Initialise ZMQ context: \n" ); +// +// // Initialise ZMQ context, requesting a single application thread and a single I/O thread +// ctx = zmq_init(1); +// if( ctx == 0 ) { +// printf( "Error zmq_init: '%s'\n", zmq_strerror(errno) ); +// return 0; +// } +// +// while(1) { +// printf( "Create a ZMQ_REP socket: \n" ); +// // Create a ZMQ_REP socket to receive requests and send replies +// s = zmq_socket( ctx, ZMQ_REQ ); +// if( s == 0 ) { +// printf( "Error zmq_socket: '%s'\n", zmq_strerror(errno) ); +// break; +// } +// +// retval = zmq_connect( s, "tcp://localhost:5555" ); +// if( retval != 0 ) { +// printf( "Error zmq_connect: '%s'\n", zmq_strerror(errno) ); +// break; +// } +// +// +// // Allocate a message and fill it +// retval = zmq_msg_init_size( &query, strlen(query_string)+1 ); +// if( retval != 0 ) { +// printf( "Error zmq_msg_init_size: '%s'\n", zmq_strerror(errno) ); +// break; +// } +// +// memcpy( zmq_msg_data (&query), query_string, strlen (query_string)+1 ); +// +// printf( "Send Query: '%s'\n", query_string ); +// // Send Query +// retval = zmq_send( s, &query, 0 , 0); +// if( retval != 0 ) { +// printf( "Error zmq_send: '%s'\n", zmq_strerror(errno) ); +// break; +// } +// +// +// +// // Recover response +// zmq_msg_init(&reply); +// if( retval != 0 ) { +// printf( "Error zmq_msg_init: '%s'\n", zmq_strerror(errno) ); +// break; +// } +// +// printf( "Waiting for reply: \n"); +// +// // Receive reply, blocks until one is available +// retval = zmq_recv( s, &reply, 0 , 0); +// if( retval != 0 ) { +// printf( "Error zmq_recv: '%s'\n", zmq_strerror(errno) ); +// break; +// } +// +// // Process the reply +// reply_string = (const char *)zmq_msg_data(&reply); +// printf("Server reply: '%s'\n", reply_string); +// +// +// // Free message memory +// zmq_msg_close(&reply); +// +// break; +// } +// +// +// // Close connection +// if( s != 0) { +// printf( "Close connection \n"); +// retval = zmq_close(s); +// if( retval != 0 ) { +// printf( "Error zmq_close: '%s'\n", zmq_strerror(errno) ); +// } +// } +// +// // Release library resources +// retval = zmq_term(ctx); +// +// printf( "All Done \n" ); +// +// return 0; +// } diff --git a/src/shared/lua_api/common.c b/src/shared/lua_api/common.c new file mode 100644 index 0000000..1e0c971 --- /dev/null +++ b/src/shared/lua_api/common.c @@ -0,0 +1,38 @@ + +extern "C" { + #include <lua.h> + #include <lauxlib.h> + #include <lualib.h> +} + +#include "common.h" + +//Expose things to the lua state +void loadLLibs(lua_State* L){ + + lua_pushcfunction(L,luaopen_base); + lua_pushliteral(L,""); + lua_call(L,1,0); + + lua_pushcfunction(L,luaopen_table); + lua_pushliteral(L,LUA_TABLIBNAME); + lua_call(L,1,0); + + lua_pushcfunction(L,luaopen_string); + lua_pushliteral(L,LUA_STRLIBNAME); + lua_call(L,1,0); + + lua_pushcfunction(L,luaopen_math); + lua_pushliteral(L,LUA_MATHLIBNAME); + lua_call(L,1,0); + + lua_pushcfunction(L,luaopen_string); + lua_pushliteral(L,LUA_STRLIBNAME); + lua_call(L,1,0); + + /* + lua_pushcfunction(L,luaopen_string); + lua_pushliteral(L,LUA_STRLIBNAME); + lua_call(L,1,0); + */ +} diff --git a/src/shared/lua_api/common.h b/src/shared/lua_api/common.h new file mode 100644 index 0000000..81dc3a4 --- /dev/null +++ b/src/shared/lua_api/common.h @@ -0,0 +1,13 @@ + +extern "C" { + #include <lua.h> + #include <lauxlib.h> + #include <lualib.h> +} + +void loadLLibs(lua_State*); + +int pushvector3i(lua_State*,long,long,long); +int pushvector3d(lua_State*,double,double,double); +int popvector3i(lua_State*,long*,long*,long*); +int popvector3d(lua_State*,double*,double*,double*); diff --git a/src/shared/lua_api/load_net.cpp b/src/shared/lua_api/load_net.cpp new file mode 100644 index 0000000..cd155fb --- /dev/null +++ b/src/shared/lua_api/load_net.cpp @@ -0,0 +1,224 @@ +extern "C" { + #include <lua.h> + #include <lauxlib.h> + #include <lualib.h> +} +#include <string.h> + +#include <string> +#include <map> + +//nanomsg things +#include <nn.h> +#include <tcp.h> +#include <pair.h> +#include <ipc.h> +#include <pipeline.h> +#include <pubsub.h> +#include <survey.h> +#include <bus.h> + +#include "load_net.hpp" + +//#include <zmq.h> +#include "../util/hashmap.h" + +std::map<int,std::map<std::string,int>> netfuncs; + +void gameloop_net(lua_State* L){ + //printf("Doing net of gameloop\n"); + for(std::map<int,std::map<std::string,int>>::iterator it = netfuncs.begin(); it != netfuncs.end(); ++it){ + //printf("Looking for new data for socket %d\n",it->first); + char* buf = NULL; + int bytes = nn_recv(it->first, &buf, NN_MSG,NN_DONTWAIT); + //printf("After recv\n"); + if(bytes < 0 && nn_errno() != EAGAIN){ + lua_pushstring(L,"Failed to receive"); + lua_error(L); + }else if( bytes < 0 && nn_errno() == EAGAIN){ + //do nothing + }else{ + //find how long until the first null character + int msglen = strlen(buf); + char msg[msglen]; + msg[msglen] = '\0'; + sprintf(msg,"%s",buf); + std::map<std::string,int> themap = it->second; + std::string s = std::string(msg); + std::map<std::string,int>::iterator in = themap.find(s); + if(in != themap.end()){ + lua_rawgeti(L,LUA_REGISTRYINDEX,(*in).second); + lua_newtable(L); + lua_call(L,1,0); + } + nn_freemsg(buf); + } + } + //hashmap_iterate(netfuncs,check_socket,0); +} + +int bindsocket(lua_State*L){ + const char* s = lua_tostring(L,-1); + lua_pushstring(L,"fd"); + lua_gettable(L,-2); + lua_pop(L,2); + int fd = lua_tonumber(L,-1); + int id = nn_bind(fd,s); + if(id < 0){ + const char* errstr = nn_strerror(nn_errno()); + char* failmsg = "Failed to bind socket: "; + int faillen = strlen(failmsg + 2); + char buf[faillen + strlen(errstr)]; + sprintf(buf,"%s%s\n",failmsg,errstr); + lua_pushstring(L,buf); + lua_error(L); + } + + lua_pushstring(L,"endpoint"); + lua_pushinteger(L,id); + lua_settable(L,-3); + netfuncs[fd] = std::map<std::string,int>(); + + return 0; +} + +int connectsocket(lua_State* L){ + const char* s = lua_tostring(L,-1); + lua_pushstring(L,"fd"); + lua_gettable(L,-2); + int fd = lua_tonumber(L,-1); + lua_pop(L,2); + int id = nn_connect(fd,s); + + lua_pushstring(L,"endpoint"); + lua_pushinteger(L,id); + lua_settable(L,-3); + + netfuncs[fd] = std::map<std::string,int>(); + + return 0; +} + +int send(lua_State* L){ + const char* data = lua_tostring(L,-1); + lua_pushstring(L,"fd"); + lua_gettable(L,-2); + int fd = lua_tonumber(L,-1); + int dlen = strlen(data); + int err = nn_send(fd,(void*)data,dlen,0); + if(err < 0){ + const char* errstr = nn_strerror(nn_errno()); + char* failmsg = "Failed to bind socket: "; + int faillen = strlen(failmsg + 2); + char buf[faillen + strlen(errstr)]; + sprintf(buf,"%s%s\n",failmsg,errstr); + lua_pushstring(L,buf); + lua_error(L); + } + return 0; +} + +//LUA: +//socket:receive(s_name,function(socket)) +int netreceive(lua_State* L){ + const char* name = lua_tostring(L,-2); + int slen = strlen(name); + std::string s = std::string(name); + int func = luaL_ref(L,LUA_REGISTRYINDEX); + lua_pushstring(L,"fd"); + lua_gettable(L,-2); + int fd = lua_tonumber(L,-1); + lua_pop(L,1); + netfuncs[fd].insert(std::pair<std::string, int>(s,func)); + return 0; +} + +int socketFactory(lua_State*L){ + int domain = luaL_optint(L,-1,0); + int type = luaL_optint(L,-2,0); + + int c = nn_socket(AF_SP,NN_PAIR); + if(c < 0){ + lua_pushstring(L,"Failed to create socket"); + lua_error(L); + } + + luaL_getmetatable(L,"net.socket"); + lua_setmetatable(L,-2); + + lua_newtable(L); + + lua_pushstring(L,"fd"); + lua_pushinteger(L,c); + lua_settable(L,-3); + + lua_pushstring(L,"bind"); + lua_pushcfunction(L,bindsocket); + lua_settable(L,-3); + + lua_pushstring(L,"connect"); + lua_pushcfunction(L,connectsocket); + lua_settable(L,-3); + + lua_pushstring(L,"send"); + lua_pushcfunction(L,send); + lua_settable(L,-3); + + lua_pushstring(L,"receive"); + lua_pushcfunction(L,netreceive); + lua_settable(L,-3); + + return 1; +} + +static const struct luaL_Reg socket_m[] = { + {"bind", bindsocket}, + {NULL,NULL} +}; + +#define set_const(l,x) lua_pushstring(l,#x);lua_pushinteger(l,x);lua_settable(l,-3); + +void loadNetLibs(lua_State* L){ + //A table to hold all our net funcs + lua_newtable(L); + + //Push some enums + set_const(L,AF_SP); + set_const(L,AF_SP_RAW); + + set_const(L,NN_PROTO_PAIR); + set_const(L,NN_PAIR); + set_const(L,NN_SUB); + set_const(L,NN_SUB_SUBSCRIBE); + set_const(L,NN_PUB); + set_const(L,NN_SUB_UNSUBSCRIBE); + + set_const(L,NN_PUSH); + set_const(L,NN_PULL); + set_const(L,NN_PROTO_PIPELINE); + set_const(L,NN_PROTO_SURVEY); + set_const(L,NN_SURVEYOR); + set_const(L,NN_RESPONDENT); + set_const(L,NN_SURVEYOR_DEADLINE); + set_const(L,NN_TCP_NODELAY); + set_const(L,NN_TCP); + set_const(L,NN_PROTO_BUS); + set_const(L,NN_BUS); + + set_const(L,NN_DONTWAIT); + set_const(L,PROTO_SP); + set_const(L,SP_HDR); + + lua_pushstring(L,"create_socket"); + lua_pushcfunction(L,socketFactory); + lua_settable(L,-3); + + //Set the table to gobal "net" + lua_setglobal(L,"net"); + + //Create the metatable for sockets + luaL_newmetatable(L,"net.socket"); + lua_pushvalue(L,-1); + lua_setfield(L,-2,"__index"); + luaL_register(L,NULL,socket_m); +} diff --git a/src/shared/lua_api/load_net.hpp b/src/shared/lua_api/load_net.hpp new file mode 100644 index 0000000..ecfadb9 --- /dev/null +++ b/src/shared/lua_api/load_net.hpp @@ -0,0 +1,8 @@ +extern "C" { + #include <lua.h> + #include <lauxlib.h> + #include <lualib.h> +} + +void loadNetLibs(lua_State* L); +void gameloop_net(lua_State* L); diff --git a/src/shared/phys/physcommon.cpp b/src/shared/phys/physcommon.cpp new file mode 100644 index 0000000..c15274d --- /dev/null +++ b/src/shared/phys/physcommon.cpp @@ -0,0 +1,84 @@ +#include <chrono> +#include <list> +#include <btBulletDynamicsCommon.h> + +#include "physcommon.hpp" + +using namespace std::chrono; + +btDiscreteDynamicsWorld* World; +std::list<btRigidBody*> Objects; + +// Removes all objects from the world +void ClearObjects(btDiscreteDynamicsWorld* wr, std::list<btRigidBody*> objs, void(*f)(btRigidBody*)) { + + for(std::list<btRigidBody *>::iterator Iterator = objs.begin(); Iterator != objs.end(); ++Iterator) { + btRigidBody *Object = *Iterator; + + if(f){ + (*f)(Object); + } + + // Remove the object from the world + wr->removeRigidBody(Object); + delete Object; + } + objs.clear(); +} + +btBroadphaseInterface* BroadPhase; +btDefaultCollisionConfiguration* CollisionConfiguration; +btCollisionDispatcher* Dispatcher; +btSequentialImpulseConstraintSolver* Solver; + +void phys_genesis(){ + BroadPhase = new btAxisSweep3(btVector3(-1000, -1000, -1000), btVector3(1000, 1000, 1000)); + printf("Broadphase\n"); + CollisionConfiguration = new btDefaultCollisionConfiguration(); + printf("Collision config\n"); + Dispatcher = new btCollisionDispatcher(CollisionConfiguration); + printf("Dispatcher\n"); + Solver = new btSequentialImpulseConstraintSolver(); + printf("Solver\n"); + World = new btDiscreteDynamicsWorld(Dispatcher, BroadPhase, Solver, CollisionConfiguration); + printf("Physics world init ok.\n"); +} + +void phys_shutdown(void(*f)(btRigidBody*)){ + ClearObjects(World,Objects,f); + printf("cleared objects\n"); + delete BroadPhase; + printf("deleted broadphase\n"); + delete CollisionConfiguration; + printf("deleted collision config\n"); + delete Dispatcher; + printf("Deleted dispatcher\n"); + delete Solver; + printf("deleted solver\n"); + + delete World; //Muah ha ha + printf("deleted world\n"); + +} + + +// Runs the physics simulation. +// - TDeltaTime tells the simulation how much time has passed since the last frame so the simulation can run independently of the frame rate. Optionally pass in an argument that will be called on every rigidbody in the world +void UpdatePhysics(double TDeltaTime, void(*f)(btRigidBody*)) { + World->stepSimulation(TDeltaTime * 0.02f, 60); + if(f){ + // Relay the object's orientation to irrlicht + for(std::list<btRigidBody *>::iterator it = Objects.begin(); it != Objects.end(); ++it) { + (*f)(*it); + } + } +} + +high_resolution_clock::time_point t1 = high_resolution_clock::now(); +void gameloop_phys(void(*f)(btRigidBody*)){ + high_resolution_clock::time_point now = high_resolution_clock::now(); + duration<double> delta = now-t1; + double steps = delta.count() * 100; + UpdatePhysics(steps,f); + t1 = now; +} diff --git a/src/shared/phys/physcommon.hpp b/src/shared/phys/physcommon.hpp new file mode 100644 index 0000000..e4660ab --- /dev/null +++ b/src/shared/phys/physcommon.hpp @@ -0,0 +1,4 @@ + +void gameloop_phys(void(*f)(btRigidBody*)); +void phys_genesis(); +void phys_shutdown(void(*f)(btRigidBody*)); diff --git a/src/shared/util/hashmap.c b/src/shared/util/hashmap.c new file mode 100644 index 0000000..f91e743 --- /dev/null +++ b/src/shared/util/hashmap.c @@ -0,0 +1,397 @@ +/* + * Generic map implementation. + */ +#include "hashmap.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#define INITIAL_SIZE (256) +#define MAX_CHAIN_LENGTH (8) + +/* We need to keep keys and values */ +typedef struct _hashmap_element{ + char* key; + int in_use; + any_t data; +} hashmap_element; + +/* A hashmap has some maximum size and current size, + * as well as the data to hold. */ +typedef struct _hashmap_map{ + int table_size; + int size; + hashmap_element *data; +} hashmap_map; + +/* + * Return an empty hashmap, or NULL on failure. + */ +map_t hashmap_new() { + hashmap_map* m = (hashmap_map*) malloc(sizeof(hashmap_map)); + if(!m) goto err; + + m->data = (hashmap_element*) calloc(INITIAL_SIZE, sizeof(hashmap_element)); + if(!m->data) goto err; + + m->table_size = INITIAL_SIZE; + m->size = 0; + + return m; + err: + if (m) + hashmap_free(m); + return NULL; +} + +/* The implementation here was originally done by Gary S. Brown. I have + borrowed the tables directly, and made some minor changes to the + crc32-function (including changing the interface). //ylo */ + + /* ============================================================= */ + /* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ + /* code or tables extracted from it, as desired without restriction. */ + /* */ + /* First, the polynomial itself and its table of feedback terms. The */ + /* polynomial is */ + /* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ + /* */ + /* Note that we take it "backwards" and put the highest-order term in */ + /* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ + /* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ + /* the MSB being 1. */ + /* */ + /* Note that the usual hardware shift register implementation, which */ + /* is what we're using (we're merely optimizing it by doing eight-bit */ + /* chunks at a time) shifts bits into the lowest-order term. In our */ + /* implementation, that means shifting towards the right. Why do we */ + /* do it this way? Because the calculated CRC must be transmitted in */ + /* order from highest-order term to lowest-order term. UARTs transmit */ + /* characters in order from LSB to MSB. By storing the CRC this way, */ + /* we hand it to the UART in the order low-byte to high-byte; the UART */ + /* sends each low-bit to hight-bit; and the result is transmission bit */ + /* by bit from highest- to lowest-order term without requiring any bit */ + /* shuffling on our part. Reception works similarly. */ + /* */ + /* The feedback terms table consists of 256, 32-bit entries. Notes: */ + /* */ + /* The table can be generated at runtime if desired; code to do so */ + /* is shown later. It might not be obvious, but the feedback */ + /* terms simply represent the results of eight shift/xor opera- */ + /* tions for all combinations of data and CRC register values. */ + /* */ + /* The values must be right-shifted by eight bits by the "updcrc" */ + /* logic; the shift must be unsigned (bring in zeroes). On some */ + /* hardware you could probably optimize the shift in assembler by */ + /* using byte-swap instructions. */ + /* polynomial $edb88320 */ + /* */ + /* -------------------------------------------------------------------- */ + +static unsigned long crc32_tab[] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL + }; + +/* Return a 32-bit CRC of the contents of the buffer. */ + +unsigned long crc32(const unsigned char *s, unsigned int len) +{ + unsigned int i; + unsigned long crc32val; + + crc32val = 0; + for (i = 0; i < len; i ++) + { + crc32val = + crc32_tab[(crc32val ^ s[i]) & 0xff] ^ + (crc32val >> 8); + } + return crc32val; +} + +/* + * Hashing function for a string + */ +unsigned int hashmap_hash_int(hashmap_map * m, char* keystring){ + + unsigned long key = crc32((unsigned char*)(keystring), strlen(keystring)); + + /* Robert Jenkins' 32 bit Mix Function */ + key += (key << 12); + key ^= (key >> 22); + key += (key << 4); + key ^= (key >> 9); + key += (key << 10); + key ^= (key >> 2); + key += (key << 7); + key ^= (key >> 12); + + /* Knuth's Multiplicative Method */ + key = (key >> 3) * 2654435761; + + return key % m->table_size; +} + +/* + * Return the integer of the location in data + * to store the point to the item, or MAP_FULL. + */ +int hashmap_hash(map_t in, char* key){ + int curr; + int i; + + /* Cast the hashmap */ + hashmap_map* m = (hashmap_map *) in; + + /* If full, return immediately */ + if(m->size >= (m->table_size/2)) return MAP_FULL; + + /* Find the best index */ + curr = hashmap_hash_int(m, key); + + /* Linear probing */ + for(i = 0; i< MAX_CHAIN_LENGTH; i++){ + if(m->data[curr].in_use == 0) + return curr; + + if(m->data[curr].in_use == 1 && (strcmp(m->data[curr].key,key)==0)) + return curr; + + curr = (curr + 1) % m->table_size; + } + + return MAP_FULL; +} + +/* + * Doubles the size of the hashmap, and rehashes all the elements + */ +int hashmap_rehash(map_t in){ + int i; + int old_size; + hashmap_element* curr; + + /* Setup the new elements */ + hashmap_map *m = (hashmap_map *) in; + hashmap_element* temp = (hashmap_element *) + calloc(2 * m->table_size, sizeof(hashmap_element)); + if(!temp) return MAP_OMEM; + + /* Update the array */ + curr = m->data; + m->data = temp; + + /* Update the size */ + old_size = m->table_size; + m->table_size = 2 * m->table_size; + m->size = 0; + + /* Rehash the elements */ + for(i = 0; i < old_size; i++){ + int status; + + if (curr[i].in_use == 0) + continue; + + status = hashmap_put(m, curr[i].key, curr[i].data); + if (status != MAP_OK) + return status; + } + + free(curr); + + return MAP_OK; +} + +/* + * Add a pointer to the hashmap with some key + */ +int hashmap_put(map_t in, char* key, any_t value){ + int index; + hashmap_map* m; + + /* Cast the hashmap */ + m = (hashmap_map *) in; + + /* Find a place to put our value */ + index = hashmap_hash(in, key); + while(index == MAP_FULL){ + if (hashmap_rehash(in) == MAP_OMEM) { + return MAP_OMEM; + } + index = hashmap_hash(in, key); + } + + /* Set the data */ + m->data[index].data = value; + m->data[index].key = key; + m->data[index].in_use = 1; + m->size++; + + return MAP_OK; +} + +/* + * Get your pointer out of the hashmap with a key + */ +int hashmap_get(map_t in, char* key, any_t *arg){ + int curr; + int i; + hashmap_map* m; + + /* Cast the hashmap */ + m = (hashmap_map *) in; + + /* Find data location */ + curr = hashmap_hash_int(m, key); + + /* Linear probing, if necessary */ + for(i = 0; i<MAX_CHAIN_LENGTH; i++){ + + int in_use = m->data[curr].in_use; + if (in_use == 1){ + if (strcmp(m->data[curr].key,key)==0){ + *arg = (m->data[curr].data); + return MAP_OK; + } + } + + curr = (curr + 1) % m->table_size; + } + + *arg = NULL; + + /* Not found */ + return MAP_MISSING; +} + +/* + * Iterate the function parameter over each element in the hashmap. The + * additional any_t argument is passed to the function as its first + * argument and the hashmap element is the second. + */ +int hashmap_iterate(map_t in, PFany f, any_t item) { + int i; + + /* Cast the hashmap */ + hashmap_map* m = (hashmap_map*) in; + + /* On empty hashmap, return immediately */ + if (hashmap_length(m) <= 0) + return MAP_MISSING; + + /* Linear probing */ + for(i = 0; i< m->table_size; i++) + if(m->data[i].in_use != 0) { + any_t data = (any_t) (m->data[i].data); + int status = f(item, data); + if (status != MAP_OK) { + return status; + } + } + + return MAP_OK; +} + +/* + * Remove an element with that key from the map + */ +int hashmap_remove(map_t in, char* key){ + int i; + int curr; + hashmap_map* m; + + /* Cast the hashmap */ + m = (hashmap_map *) in; + + /* Find key */ + curr = hashmap_hash_int(m, key); + + /* Linear probing, if necessary */ + for(i = 0; i<MAX_CHAIN_LENGTH; i++){ + + int in_use = m->data[curr].in_use; + if (in_use == 1){ + if (strcmp(m->data[curr].key,key)==0){ + /* Blank out the fields */ + m->data[curr].in_use = 0; + m->data[curr].data = NULL; + m->data[curr].key = NULL; + + /* Reduce the size */ + m->size--; + return MAP_OK; + } + } + curr = (curr + 1) % m->table_size; + } + + /* Data not found */ + return MAP_MISSING; +} + +/* Deallocate the hashmap */ +void hashmap_free(map_t in){ + hashmap_map* m = (hashmap_map*) in; + free(m->data); + free(m); +} + +/* Return the length of the hashmap */ +int hashmap_length(map_t in){ + hashmap_map* m = (hashmap_map *) in; + if(m != NULL) return m->size; + else return 0; +} diff --git a/src/shared/util/hashmap.h b/src/shared/util/hashmap.h new file mode 100644 index 0000000..16c76dd --- /dev/null +++ b/src/shared/util/hashmap.h @@ -0,0 +1,81 @@ +/* + * Generic hashmap manipulation functions + * + * Originally by Elliot C Back - http://elliottback.com/wp/hashmap-implementation-in-c/ + * + * Modified by Pete Warden to fix a serious performance problem, support strings as keys + * and removed thread synchronization - http://petewarden.typepad.com + */ +#ifndef __HASHMAP_H__ +#define __HASHMAP_H__ + +#define MAP_MISSING -3 /* No such element */ +#define MAP_FULL -2 /* Hashmap is full */ +#define MAP_OMEM -1 /* Out of Memory */ +#define MAP_OK 0 /* OK */ + +/* + * any_t is a pointer. This allows you to put arbitrary structures in + * the hashmap. + */ +typedef void *any_t; + +/* + * PFany is a pointer to a function that can take two any_t arguments + * and return an integer. Returns status code.. + */ +typedef int (*PFany)(any_t, any_t); + +/* + * map_t is a pointer to an internally maintained data structure. + * Clients of this package do not need to know how hashmaps are + * represented. They see and manipulate only map_t's. + */ +typedef any_t map_t; + +/* + * Return an empty hashmap. Returns NULL if empty. +*/ +extern map_t hashmap_new(); + +/* + * Iteratively call f with argument (item, data) for + * each element data in the hashmap. The function must + * return a map status code. If it returns anything other + * than MAP_OK the traversal is terminated. f must + * not reenter any hashmap functions, or deadlock may arise. + */ +extern int hashmap_iterate(map_t in, PFany f, any_t item); + +/* + * Add an element to the hashmap. Return MAP_OK or MAP_OMEM. + */ +extern int hashmap_put(map_t in, char* key, any_t value); + +/* + * Get an element from the hashmap. Return MAP_OK or MAP_MISSING. + */ +extern int hashmap_get(map_t in, char* key, any_t *arg); + +/* + * Remove an element from the hashmap. Return MAP_OK or MAP_MISSING. + */ +extern int hashmap_remove(map_t in, char* key); + +/* + * Get any element. Return MAP_OK or MAP_MISSING. + * remove - should the element be removed from the hashmap + */ +extern int hashmap_get_one(map_t in, any_t *arg, int remove); + +/* + * Free the hashmap + */ +extern void hashmap_free(map_t in); + +/* + * Get the current size of a hashmap + */ +extern int hashmap_length(map_t in); + +#endif //__HASHMAP_H__ |
