summary refs log tree commit diff stats
path: root/tests/manyloc/keineschweine
diff options
context:
space:
mode:
Diffstat (limited to 'tests/manyloc/keineschweine')
-rw-r--r--tests/manyloc/keineschweine/README.md26
-rw-r--r--tests/manyloc/keineschweine/TODO.md21
-rw-r--r--tests/manyloc/keineschweine/client_settings.json10
-rw-r--r--tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim1516
-rw-r--r--tests/manyloc/keineschweine/dependencies/enet/enet.nim614
-rw-r--r--tests/manyloc/keineschweine/dependencies/enet/testclient.nim49
-rw-r--r--tests/manyloc/keineschweine/dependencies/enet/testserver.nim45
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim295
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim296
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim73
-rw-r--r--tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim47
-rw-r--r--tests/manyloc/keineschweine/dependencies/nake/nake.nim83
-rw-r--r--tests/manyloc/keineschweine/dependencies/nake/nakefile.nim23
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/README.md13
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml.nim1115
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim899
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim15
-rw-r--r--tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim2
-rw-r--r--tests/manyloc/keineschweine/enet_server/enet_client.nim228
-rw-r--r--tests/manyloc/keineschweine/enet_server/enet_server.nim294
-rw-r--r--tests/manyloc/keineschweine/enet_server/nakefile.nim13
-rw-r--r--tests/manyloc/keineschweine/enet_server/nimrod.cfg9
-rw-r--r--tests/manyloc/keineschweine/enet_server/server_settings.json8
-rw-r--r--tests/manyloc/keineschweine/enet_server/server_utils.nim120
-rw-r--r--tests/manyloc/keineschweine/keineschweine.nim725
-rw-r--r--tests/manyloc/keineschweine/keineschweine.nimrod.cfg8
-rw-r--r--tests/manyloc/keineschweine/lib/animations.nim75
-rw-r--r--tests/manyloc/keineschweine/lib/client_helpers.nim142
-rw-r--r--tests/manyloc/keineschweine/lib/estreams.nim126
-rw-r--r--tests/manyloc/keineschweine/lib/game_objects.nim34
-rw-r--r--tests/manyloc/keineschweine/lib/idgen.nim23
-rw-r--r--tests/manyloc/keineschweine/lib/input_helpers.nim138
-rw-r--r--tests/manyloc/keineschweine/lib/map_filter.nim41
-rw-r--r--tests/manyloc/keineschweine/lib/math_helpers.nim10
-rw-r--r--tests/manyloc/keineschweine/lib/sfml_stuff.nim37
-rw-r--r--tests/manyloc/keineschweine/lib/sg_assets.nim609
-rw-r--r--tests/manyloc/keineschweine/lib/sg_gui.nim281
-rw-r--r--tests/manyloc/keineschweine/lib/sg_packets.nim106
-rw-r--r--tests/manyloc/keineschweine/lib/sound_buffer.nim38
-rw-r--r--tests/manyloc/keineschweine/lib/vehicles.nim35
-rw-r--r--tests/manyloc/keineschweine/lib/zlib_helpers.nim40
-rw-r--r--tests/manyloc/keineschweine/nakefile.nim155
-rw-r--r--tests/manyloc/keineschweine/nakefile.nimrod.cfg1
-rw-r--r--tests/manyloc/keineschweine/server/dirserver_settings.json7
-rw-r--r--tests/manyloc/keineschweine/server/nimrod.cfg6
-rw-r--r--tests/manyloc/keineschweine/server/old_dirserver.nim201
-rw-r--r--tests/manyloc/keineschweine/server/old_server_utils.nim98
-rw-r--r--tests/manyloc/keineschweine/server/old_sg_server.nim254
-rw-r--r--tests/manyloc/keineschweine/server/sg_lobby.nim267
49 files changed, 9271 insertions, 0 deletions
diff --git a/tests/manyloc/keineschweine/README.md b/tests/manyloc/keineschweine/README.md
new file mode 100644
index 000000000..2a6b78a8e
--- /dev/null
+++ b/tests/manyloc/keineschweine/README.md
@@ -0,0 +1,26 @@
+keineSchweine
+========================
+Just a dumb little game
+
+### Dependencies
+
+* Nimrod 0.8.15, Until this version is released I'm working off Nimrod HEAD: https://github.com/Araq/Nimrod
+* SFML 2.0 (git), https://github.com/LaurentGomila/SFML
+* CSFML 2.0 (git), https://github.com/LaurentGomila/CSFML
+* Chipmunk 6.1.1 http://chipmunk-physics.net/downloads.php
+
+### How to build?
+
+* `git clone --recursive git://github.com/fowlmouth/keineSchweine.git somedir`
+* `cd somedir`
+*  `nimrod c -r nakefile test` or `nimrod c -r keineschweine && ./keineschweine`
+
+### Download the game data
+
+You need to download the game data before you can play:
+http://dl.dropbox.com/u/37533467/data-08-01-2012.7z
+
+Unpack it to the root directory. You can use the nakefile to do this easily: 
+
+* `nimrod c -r nakefile`
+* `./nakefile download`
diff --git a/tests/manyloc/keineschweine/TODO.md b/tests/manyloc/keineschweine/TODO.md
new file mode 100644
index 000000000..1145949aa
--- /dev/null
+++ b/tests/manyloc/keineschweine/TODO.md
@@ -0,0 +1,21 @@
+##Main State
+* Add GUI:
+  * Player list
+  * Chat box
+  * Escape menu
+
+##Lobby
+* Add GUI: 
+  * options menu
+  * key configuration
+
+## Animations
+* Need one-shot explosion animations
+  * Thrusters (maybe a particle system instead)
+
+## Networking
+* zone server should verify users through the dir server or handle its own users
+* directory server should handle asset patching
+
+## Genpacket
+* add support for branching types with case
diff --git a/tests/manyloc/keineschweine/client_settings.json b/tests/manyloc/keineschweine/client_settings.json
new file mode 100644
index 000000000..59facf1ad
--- /dev/null
+++ b/tests/manyloc/keineschweine/client_settings.json
@@ -0,0 +1,10 @@
+{
+ "resolution": [800,600,32],
+ "default-file": "alphazone.json",
+ "alias": "foo",
+ "directory-server":{
+  "host":"localhost",
+  "port":8024
+ },
+ "website":"https://github.com/fowlmouth/keineSchweine"
+}
diff --git a/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim
new file mode 100644
index 000000000..8226b0b04
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/chipmunk/chipmunk.nim
@@ -0,0 +1,1516 @@
+# Copyright (c) 2007 Scott Lembcke
+#  
+#  Permission is hereby granted, free of charge, to any person obtaining a copy
+#  of this software and associated documentation files (the "Software"), to deal
+#  in the Software without restriction, including without limitation the rights
+#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+#  copies of the Software, and to permit persons to whom the Software is
+#  furnished to do so, subject to the following conditions:
+#  
+#  The above copyright notice and this permission notice shall be included in
+#  all copies or substantial portions of the Software.
+#  
+#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+#  SOFTWARE.
+# 
+when defined(Linux):
+  const Lib = "libchipmunk.so.6.1.1"
+else:
+  {.error: "Platform unsupported".}
+when defined(MoreNimrod):
+  {.hint: "MoreNimrod defined; some Chipmunk functions replaced in Nimrod".}
+{.deadCodeElim: on.}
+from math import sqrt, sin, cos, arctan2
+when defined(CpUseFloat):
+  {.hint: "CpUseFloat defined; using float32 as float".}
+  type CpFloat* = cfloat
+else:
+  type CpFloat* = cdouble
+const 
+  CP_BUFFER_BYTES* = (32 * 1024)  
+  CP_MAX_CONTACTS_PER_ARBITER* = 4
+  CpInfinity*: CpFloat = 1.0/0
+{.pragma: pf, pure, final.}
+type 
+  Bool32* = cint  #replace one day with cint-compatible bool
+  CpDataPointer* = pointer
+  TVector* {.final, pure.} = object
+    x*, y*: CpFloat
+  TTimestamp* = cuint
+  TBodyVelocityFunc* = proc(body: PBody, gravity: TVector,
+                            damping: CpFloat; dt: CpFloat){.cdecl.}
+  TBodyPositionFunc* = proc(body: PBody; dt: CpFloat){.cdecl.}
+  TComponentNode*{.pf.} = object 
+    root*: PBody
+    next*: PBody
+    idleTime*: CpFloat
+  
+  THashValue = cuint  # uintptr_t 
+  TCollisionType* = cuint #uintptr_t
+  TGroup * = cuint #uintptr_t
+  TLayers* = cuint
+  PArray = ptr TArray
+  TArray{.pure,final.} = object
+  PHashSet = ptr THashSet
+  THashSet{.pf.} = object
+  PContact* = ptr TContact
+  TContact*{.pure,final.} = object
+  PArbiter* = ptr TArbiter
+  TArbiter*{.pf.} = object 
+    e*: CpFloat
+    u*: CpFloat 
+    surface_vr*: TVector
+    a*: PShape
+    b*: PShape
+    body_a*: PBody
+    body_b*: PBody
+    thread_a*: TArbiterThread
+    thread_b*: TArbiterThread
+    numContacts*: cint
+    contacts*: PContact
+    stamp*: TTimestamp
+    handler*: PCollisionHandler
+    swappedColl*: bool32
+    state*: TArbiterState
+  PCollisionHandler* = ptr TCollisionHandler
+  TCollisionHandler*{.pf.} = object 
+    a*: TCollisionType
+    b*: TCollisionType
+    begin*: TCollisionBeginFunc
+    preSolve*: TCollisionPreSolveFunc
+    postSolve*: TCollisionPostSolveFunc
+    separate*: TCollisionSeparateFunc
+    data*: pointer
+  TArbiterState*{.size: sizeof(cint).} = enum 
+    ArbiterStateFirstColl,    # Arbiter is active and its not the first collision.
+    ArbiterStateNormal,       # Collision has been explicitly ignored.
+                              # Either by returning false from a begin collision handler or calling cpArbiterIgnore().
+    ArbiterStateIgnore,       # Collison is no longer active. A space will cache an arbiter for up to cpSpace.collisionPersistence more steps.
+    ArbiterStateCached
+  TArbiterThread*{.pf.} = object 
+    next*: PArbiter        # Links to next and previous arbiters in the contact graph.
+    prev*: PArbiter
+  
+  TContactPoint*{.pf.} = object 
+    point*: TVector    #/ The position of the contact point.
+    normal*: TVector   #/ The normal of the contact point.
+    dist*: CpFloat     #/ The depth of the contact point.
+  #/ A struct that wraps up the important collision data for an arbiter.
+  PContactPointSet* = ptr TContactPointSet
+  TContactPointSet*{.pf.} = object 
+    count*: cint              #/ The number of contact points in the set.
+    points*: array[0..CP_MAX_CONTACTS_PER_ARBITER - 1, TContactPoint] #/ The array of contact points.
+  
+  #/ Collision begin event function callback type.
+  #/ Returning false from a begin callback causes the collision to be ignored until
+  #/ the the separate callback is called when the objects stop colliding.
+  TCollisionBeginFunc* = proc (arb: PArbiter; space: PSpace; data: pointer): Bool{.
+      cdecl.}
+  #/ Collision pre-solve event function callback type.
+  #/ Returning false from a pre-step callback causes the collision to be ignored until the next step.
+  TCollisionPreSolveFunc* = proc (arb: PArbiter; space: PSpace; 
+                                  data: pointer): bool {.cdecl.}
+  #/ Collision post-solve event function callback type.
+  TCollisionPostSolveFunc* = proc (arb: PArbiter; space: PSpace; 
+                                   data: pointer){.cdecl.}
+  #/ Collision separate event function callback type.
+  TCollisionSeparateFunc* = proc (arb: PArbiter; space: PSpace; 
+                                  data: pointer){.cdecl.}
+  
+  #/ Chipmunk's axis-aligned 2D bounding box type. (left, bottom, right, top)
+  PBB* = ptr TBB
+  TBB* {.pf.} = object 
+    l*, b*, r*, t*: CpFloat
+  
+  #/ Spatial index bounding box callback function type.
+  #/ The spatial index calls this function and passes you a pointer to an object you added
+  #/ when it needs to get the bounding box associated with that object.
+  TSpatialIndexBBFunc* = proc (obj: pointer): TBB{.cdecl.}
+  #/ Spatial index/object iterator callback function type.
+  TSpatialIndexIteratorFunc* = proc (obj: pointer; data: pointer){.cdecl.}
+  #/ Spatial query callback function type. 
+  TSpatialIndexQueryFunc* = proc (obj1: pointer; obj2: pointer; data: pointer){.
+      cdecl.}
+  #/ Spatial segment query callback function type.
+  TSpatialIndexSegmentQueryFunc* = proc (obj1: pointer; obj2: pointer; 
+      data: pointer): CpFloat {.cdecl.}
+  #/ private
+  PSpatialIndex = ptr TSpatialIndex
+  TSpatialIndex{.pf.} = object 
+    klass: PSpatialIndexClass
+    bbfunc: TSpatialIndexBBFunc
+    staticIndex: PSpatialIndex
+    dynamicIndex: PSpatialIndex
+
+  TSpatialIndexDestroyImpl* = proc (index: PSpatialIndex){.cdecl.}
+  TSpatialIndexCountImpl* = proc (index: PSpatialIndex): cint{.cdecl.}
+  TSpatialIndexEachImpl* = proc (index: PSpatialIndex; 
+                                 func: TSpatialIndexIteratorFunc; data: pointer){.
+      cdecl.}
+  TSpatialIndexContainsImpl* = proc (index: PSpatialIndex; obj: pointer; 
+                                     hashid: THashValue): Bool32 {.cdecl.}
+  TSpatialIndexInsertImpl* = proc (index: PSpatialIndex; obj: pointer; 
+                                   hashid: THashValue){.cdecl.}
+  TSpatialIndexRemoveImpl* = proc (index: PSpatialIndex; obj: pointer; 
+                                   hashid: THashValue){.cdecl.}
+  TSpatialIndexReindexImpl* = proc (index: PSpatialIndex){.cdecl.}
+  TSpatialIndexReindexObjectImpl* = proc (index: PSpatialIndex; 
+      obj: pointer; hashid: THashValue){.cdecl.}
+  TSpatialIndexReindexQueryImpl* = proc (index: PSpatialIndex; 
+      func: TSpatialIndexQueryFunc; data: pointer){.cdecl.}
+  TSpatialIndexPointQueryImpl* = proc (index: PSpatialIndex; point: TVector; 
+                                       func: TSpatialIndexQueryFunc; 
+                                       data: pointer){.cdecl.}
+  TSpatialIndexSegmentQueryImpl* = proc (index: PSpatialIndex; obj: pointer; 
+      a: TVector; b: TVector; t_exit: CpFloat; func: TSpatialIndexSegmentQueryFunc; 
+      data: pointer){.cdecl.}
+  TSpatialIndexQueryImpl* = proc (index: PSpatialIndex; obj: pointer; 
+                                  bb: TBB; func: TSpatialIndexQueryFunc; 
+                                  data: pointer){.cdecl.}
+  PSpatialIndexClass* = ptr TSpatialIndexClass
+  TSpatialIndexClass*{.pf.} = object 
+    destroy*: TSpatialIndexDestroyImpl
+    count*: TSpatialIndexCountImpl
+    each*: TSpatialIndexEachImpl
+    contains*: TSpatialIndexContainsImpl
+    insert*: TSpatialIndexInsertImpl
+    remove*: TSpatialIndexRemoveImpl
+    reindex*: TSpatialIndexReindexImpl
+    reindexObject*: TSpatialIndexReindexObjectImpl
+    reindexQuery*: TSpatialIndexReindexQueryImpl
+    pointQuery*: TSpatialIndexPointQueryImpl
+    segmentQuery*: TSpatialIndexSegmentQueryImpl
+    query*: TSpatialIndexQueryImpl
+  
+  PSpaceHash* = ptr TSpaceHash
+  TSpaceHash* {.pf.} = object
+  PBBTree* = ptr TBBTree
+  TBBTree* {.pf.} = object
+  PSweep1D* = ptr TSweep1D
+  TSweep1D* {.pf.} = object
+  
+  #/ Bounding box tree velocity callback function.
+  #/ This function should return an estimate for the object's velocity.
+  TBBTreeVelocityFunc* = proc (obj: pointer): TVector {.cdecl.}
+  
+  PContactBufferHeader* = ptr TContentBufferHeader
+  TContentBufferHeader* {.pf.} = object
+  TSpaceArbiterApplyImpulseFunc* = proc (arb: PArbiter){.cdecl.}
+  
+  PSpace* = ptr TSpace
+  TSpace* {.pf.} = object
+    iterations*: cint 
+    gravity*: TVector
+    damping*: CpFloat
+    idleSpeedThreshold*: CpFloat 
+    sleepTimeThreshold*: CpFloat 
+    collisionSlop*: CpFloat 
+    collisionBias*: CpFloat
+    collisionPersistence*: TTimestamp        
+    enableContactGraph*: cint ##BOOL
+    data*: pointer
+    staticBody*: PBody
+    stamp: TTimestamp
+    currDT: CpFloat
+    bodies: PArray
+    rousedBodies: PArray
+    sleepingComponents: PArray
+    staticShapes: PSpatialIndex
+    activeShapes: PSpatialIndex
+    arbiters: PArray
+    contactBuffersHead: PContactBufferHeader
+    cachedArbiters: PHashSet
+    pooledArbiters: PArray
+    constraints: PArray
+    allocatedBuffers: PArray
+    locked: cint
+    collisionHandlers: PHashSet
+    defaultHandler: TCollisionHandler
+    postStepCallbacks: PHashSet
+    arbiterApplyImpulse: TSpaceArbiterApplyImpulseFunc
+    staticBody2: TBody  #_staticBody 
+  PBody* = ptr TBody
+  TBody*{.pf.} = object 
+    velocityFunc*: TBodyVelocityFunc 
+    positionFunc*: TBodyPositionFunc                                       
+    m*: CpFloat           
+    mInv*: CpFloat       
+    i*: CpFloat           
+    iInv*: CpFloat       
+    p*: TVector            
+    v*: TVector            
+    f*: TVector 
+    a*: CpFloat 
+    w*: CpFloat 
+    t*: CpFloat 
+    rot*: TVector 
+    data*: pointer
+    vLimit*: CpFloat   
+    wLimit*: CpFloat
+    vBias*: TVector
+    wBias*: CpFloat
+    space*: PSpace
+    shapeList*: PShape
+    arbiterList*: PArbiter
+    constraintList*: PConstraint
+    node*: TComponentNode
+  #/ Body/shape iterator callback function type. 
+  TBodyShapeIteratorFunc* = proc (body: PBody; shape: PShape; 
+                                   data: pointer) {.cdecl.}
+  #/ Body/constraint iterator callback function type. 
+  TBodyConstraintIteratorFunc* = proc (body: PBody; 
+                                        constraint: PConstraint; 
+                                        data: pointer) {.cdecl.}
+  #/ Body/arbiter iterator callback function type. 
+  TBodyArbiterIteratorFunc* = proc (body: PBody; arbiter: PArbiter; 
+                                     data: pointer) {.cdecl.}
+  
+  PNearestPointQueryInfo* = ptr TNearestPointQueryInfo
+  #/ Nearest point query info struct.
+  TNearestPointQueryInfo*{.pf.} = object
+    shape: PShape  #/ The nearest shape, NULL if no shape was within range.
+    p: TVector     #/ The closest point on the shape's surface. (in world space coordinates)
+    d: CpFloat      #/ The distance to the point. The distance is negative if the point is inside the shape.
+  
+  PSegmentQueryInfo* = ptr TSegmentQueryInfo
+  #/ Segment query info struct.
+  TSegmentQueryInfo*{.pf.} = object 
+    shape*: PShape         #/ The shape that was hit, NULL if no collision occured.
+    t*: CpFloat            #/ The normalized distance along the query segment in the range [0, 1].
+    n*: TVector            #/ The normal of the surface hit.
+  TShapeType*{.size: sizeof(cint).} = enum 
+    CP_CIRCLE_SHAPE, CP_SEGMENT_SHAPE, CP_POLY_SHAPE, CP_NUM_SHAPES
+  TShapeCacheDataImpl* = proc (shape: PShape; p: TVector; rot: TVector): TBB{.cdecl.}
+  TShapeDestroyImpl* = proc (shape: PShape){.cdecl.}
+  TShapePointQueryImpl* = proc (shape: PShape; p: TVector): bool32 {.cdecl.}
+  TShapeSegmentQueryImpl* = proc (shape: PShape; a: TVector; b: TVector; 
+                                  info: PSegmentQueryInfo){.cdecl.}
+  PShapeClass* = ptr TShapeClass
+  TShapeClass*{.pf.} = object 
+    kind*: TShapeType
+    cacheData*: TShapeCacheDataImpl
+    destroy*: TShapeDestroyImpl
+    pointQuery*: TShapePointQueryImpl
+    segmentQuery*: TShapeSegmentQueryImpl
+  PShape* = ptr TShape
+  TShape*{.pf.} = object 
+    klass: PShapeClass   #/ PRIVATE
+    body*: PBody           #/ The rigid body this collision shape is attached to.
+    bb*: TBB               #/ The current bounding box of the shape.   
+    sensor*: Bool32        #/ Sensor flag.
+                           #/ Sensor shapes call collision callbacks but don't produce collisions.  
+    e*: CpFloat            #/ Coefficient of restitution. (elasticity)
+    u*: CpFloat            #/ Coefficient of friction.
+    surface_v*: TVector    #/ Surface velocity used when solving for friction.
+    data*: pointer        #/ User definable data pointer. Generally this points to your the game object class so you can access it when given a cpShape reference in a callback.
+    collision_type*: TCollisionType #/ Collision type of this shape used when picking collision handlers.
+    group*: TGroup      #/ Group of this shape. Shapes in the same group don't collide.
+    layers*: TLayers   #/ Layer bitmask for this shape. Shapes only collide if the bitwise and of their layers is non-zero.
+    space: PSpace        #PRIVATE
+    next: PShape         #PRIVATE
+    prev: PShape         #PRIVATE
+    hashid: THashValue  #PRIVATE
+  PCircleShape* = ptr TCircleShape
+  TCircleShape*{.pf.} = object
+    shape: PShape
+    c, tc: TVector
+    r: CpFloat
+  PPolyShape* = ptr TPolyShape
+  TPolyShape*{.pf.} = object
+    shape: PShape
+    numVerts: cint
+    verts, tVerts: TVector
+    planes, tPlanes: PSplittingPlane
+  PSegmentShape* = ptr TSegmentShape
+  TSegmentShape*{.pf.} = object
+    shape: PShape
+    a, b, n: TVector
+    ta, tb, tn: TVector
+    r: CpFloat
+    aTangent, bTangent: TVector
+  PSplittingPlane* = ptr TSplittingPlane
+  TSplittingPlane*{.pf.} = object
+    n: TVector
+    d: CpFloat
+  
+  #/ Post Step callback function type.
+  TPostStepFunc* = proc (space: PSpace; obj: pointer; data: pointer){.cdecl.}
+  #/ Point query callback function type.
+  TSpacePointQueryFunc* = proc (shape: PShape; data: pointer){.cdecl.}
+  #/ Segment query callback function type.
+  TSpaceSegmentQueryFunc* = proc (shape: PShape; t: CpFloat; n: TVector; 
+                                  data: pointer){.cdecl.}
+  #/ Rectangle Query callback function type.
+  TSpaceBBQueryFunc* = proc (shape: PShape; data: pointer){.cdecl.}
+  #/ Shape query callback function type.
+  TSpaceShapeQueryFunc* = proc (shape: PShape; points: PContactPointSet; 
+                                data: pointer){.cdecl.}
+  #/ Space/body iterator callback function type.
+  TSpaceBodyIteratorFunc* = proc (body: PBody; data: pointer){.cdecl.}
+  #/ Space/body iterator callback function type.
+  TSpaceShapeIteratorFunc* = proc (shape: PShape; data: pointer){.cdecl.}
+  #/ Space/constraint iterator callback function type.
+  TSpaceConstraintIteratorFunc* = proc (constraint: PConstraint; 
+                                        data: pointer){.cdecl.}
+  #/ Opaque cpConstraint struct.
+  PConstraint* = ptr TConstraint
+  TConstraint*{.pf.} = object 
+    klass: PConstraintClass #/PRIVATE
+    a*: PBody            #/ The first body connected to this constraint.
+    b*: PBody              #/ The second body connected to this constraint.
+    space: PSpace         #/PRIVATE
+    next_a: PConstraint  #/PRIVATE
+    next_b: PConstraint #/PRIVATE
+    maxForce*: CpFloat  #/ The maximum force that this constraint is allowed to use. Defaults to infinity.
+    errorBias*: CpFloat #/ The rate at which joint error is corrected. Defaults to pow(1.0 - 0.1, 60.0) meaning that it will correct 10% of the error every 1/60th of a second.
+    maxBias*: CpFloat    #/ The maximum rate at which joint error is corrected. Defaults to infinity.       
+    preSolve*: TConstraintPreSolveFunc  #/ Function called before the solver runs. Animate your joint anchors, update your motor torque, etc.
+    postSolve*: TConstraintPostSolveFunc #/ Function called after the solver runs. Use the applied impulse to perform effects like breakable joints.
+    data*: CpDataPointer  # User definable data pointer. Generally this points to your the game object class so you can access it when given a cpConstraint reference in a callback.
+  TConstraintPreStepImpl = proc (constraint: PConstraint; dt: CpFloat){.cdecl.}
+  TConstraintApplyCachedImpulseImpl = proc (constraint: PConstraint; dt_coef: CpFloat){.cdecl.}
+  TConstraintApplyImpulseImpl = proc (constraint: PConstraint){.cdecl.}
+  TConstraintGetImpulseImpl = proc (constraint: PConstraint): CpFloat{.cdecl.}
+  PConstraintClass = ptr TConstraintClass
+  TConstraintClass{.pf.} = object 
+    preStep*: TConstraintPreStepImpl
+    applyCachedImpulse*: TConstraintApplyCachedImpulseImpl
+    applyImpulse*: TConstraintApplyImpulseImpl
+    getImpulse*: TConstraintGetImpulseImpl
+  #/ Callback function type that gets called before solving a joint.
+  TConstraintPreSolveFunc* = proc (constraint: PConstraint; space: PSpace){.
+    cdecl.}
+  #/ Callback function type that gets called after solving a joint.
+  TConstraintPostSolveFunc* = proc (constraint: PConstraint; space: PSpace){.
+    cdecl.}
+
+##cp property emulators
+template defGetter(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} =
+  proc `get procName`*(obj: otype): memberType {.cdecl.} =
+    return obj.memberName
+template defSetter(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} =
+  proc `set procName`*(obj: otype, value: memberType) {.cdecl.} =
+    obj.memberName = value
+template defProp(otype: typedesc, memberType: typedesc, memberName: expr, procName: expr): stmt {.immediate.} =
+  defGetter(otype, memberType, memberName, procName)
+  defSetter(otype, memberType, memberName, procName)
+
+
+##cpspace.h
+proc allocSpace*(): PSpace {.
+  importc: "cpSpaceAlloc", dynlib: Lib.}
+proc Init*(space: PSpace): PSpace {.
+  importc: "cpSpaceInit", dynlib: Lib.}
+proc newSpace*(): PSpace {.
+  importc: "cpSpaceNew", dynlib: Lib.}
+proc destroy*(space: PSpace) {.
+  importc: "cpSpaceDestroy", dynlib: Lib.}
+proc free*(space: PSpace) {.
+  importc: "cpSpaceFree", dynlib: Lib.}
+
+defProp(PSpace, cint, iterations, Iterations)
+defProp(PSpace, TVector, gravity, Gravity)
+defProp(PSpace, CpFloat, damping, Damping)
+defProp(PSpace, CpFloat, idleSpeedThreshold, IdleSpeedThreshold)
+defProp(PSpace, CpFloat, sleepTimeThreshold, SleepTimeThreshold)
+defProp(PSpace, CpFloat, collisionSlop, CollisionSlop)
+defProp(PSpace, CpFloat, collisionBias, CollisionBias)
+defProp(PSpace, TTimestamp, collisionPersistence, CollisionPersistence)
+defProp(PSpace, Bool32, enableContactGraph, EnableContactGraph)
+defProp(PSpace, pointer, data, UserData)
+defGetter(PSpace, PBody, staticBody, StaticBody)
+defGetter(PSpace, CpFloat, currDt, CurrentTimeStep)
+
+
+#/ returns true from inside a callback and objects cannot be added/removed.
+proc isLocked*(space: PSpace): Bool{.inline.} = 
+  result = space.locked.bool
+
+#/ Set a default collision handler for this space.
+#/ The default collision handler is invoked for each colliding pair of shapes
+#/ that isn't explicitly handled by a specific collision handler.
+#/ You can pass NULL for any function you don't want to implement.
+proc setDefaultCollisionHandler*(space: PSpace; begin: TCollisionBeginFunc; 
+                                  preSolve: TCollisionPreSolveFunc; 
+                                  postSolve: TCollisionPostSolveFunc; 
+                                  separate: TCollisionSeparateFunc; 
+                                  data: pointer){.
+  cdecl, importc: "cpSpaceSetDefaultCollisionHandler", dynlib: Lib.}
+#/ Set a collision handler to be used whenever the two shapes with the given collision types collide.
+#/ You can pass NULL for any function you don't want to implement.
+proc addCollisionHandler*(space: PSpace; a, b: TCollisionType; 
+                           begin: TCollisionBeginFunc; 
+                           preSolve: TCollisionPreSolveFunc; 
+                           postSolve: TCollisionPostSolveFunc; 
+                           separate: TCollisionSeparateFunc; data: pointer){.
+  cdecl, importc: "cpSpaceAddCollisionHandler", dynlib: Lib.}
+#/ Unset a collision handler.
+proc removeCollisionHandler*(space: PSpace; a: TCollisionType; 
+                                  b: TCollisionType){.
+  cdecl, importc: "cpSpaceRemoveCollisionHandler", dynlib: Lib.}
+#/ Add a collision shape to the simulation.
+#/ If the shape is attached to a static body, it will be added as a static shape.
+proc addShape*(space: PSpace; shape: PShape): PShape{.
+  cdecl, importc: "cpSpaceAddShape", dynlib: Lib.}
+#/ Explicity add a shape as a static shape to the simulation.
+proc addStaticShape*(space: PSpace; shape: PShape): PShape{.
+  cdecl, importc: "cpSpaceAddStaticShape", dynlib: Lib.}
+#/ Add a rigid body to the simulation.
+proc addBody*(space: PSpace; body: PBody): PBody{.
+  cdecl, importc: "cpSpaceAddBody", dynlib: Lib.}
+#/ Add a constraint to the simulation.
+proc addConstraint*(space: PSpace; constraint: PConstraint): PConstraint{.
+    cdecl, importc: "cpSpaceAddConstraint", dynlib: Lib.}
+#/ Remove a collision shape from the simulation.
+proc removeShape*(space: PSpace; shape: PShape){.
+  cdecl, importc: "cpSpaceRemoveShape", dynlib: Lib.}
+#/ Remove a collision shape added using cpSpaceAddStaticShape() from the simulation.
+proc removeStaticShape*(space: PSpace; shape: PShape){.
+  cdecl, importc: "cpSpaceRemoveStaticShape", dynlib: Lib.}
+#/ Remove a rigid body from the simulation.
+proc removeBody*(space: PSpace; body: PBody){.
+  cdecl, importc: "cpSpaceRemoveBody", dynlib: Lib.}
+#/ Remove a constraint from the simulation.
+proc RemoveConstraint*(space: PSpace; constraint: PConstraint){.
+  cdecl, importc: "cpSpaceRemoveConstraint", dynlib: Lib.}
+#/ Test if a collision shape has been added to the space.
+proc containsShape*(space: PSpace; shape: PShape): Bool{.
+  cdecl, importc: "cpSpaceContainsShape", dynlib: Lib.}
+#/ Test if a rigid body has been added to the space.
+proc containsBody*(space: PSpace; body: PBody): Bool{.
+  cdecl, importc: "cpSpaceContainsBody", dynlib: Lib.}
+#/ Test if a constraint has been added to the space.
+
+proc containsConstraint*(space: PSpace; constraint: PConstraint): Bool{.
+  cdecl, importc: "cpSpaceContainsConstraint", dynlib: Lib.}
+#/ Schedule a post-step callback to be called when cpSpaceStep() finishes.
+#/ @c obj is used a key, you can only register one callback per unique value for @c obj
+proc addPostStepCallback*(space: PSpace; func: TPostStepFunc; 
+                               obj: pointer; data: pointer){.
+  cdecl, importc: "cpSpaceAddPostStepCallback", dynlib: Lib.}
+                                        
+#/ Query the space at a point and call @c func for each shape found.
+proc pointQuery*(space: PSpace; point: TVector; layers: TLayers; 
+                      group: TGroup; func: TSpacePointQueryFunc; data: pointer){.
+  cdecl, importc: "cpSpacePointQuery", dynlib: Lib.}
+
+#/ Query the space at a point and return the first shape found. Returns NULL if no shapes were found.
+proc pointQueryFirst*(space: PSpace; point: TVector; layers: TLayers; 
+                       group: TGroup): PShape{.
+  cdecl, importc: "cpSpacePointQueryFirst", dynlib: Lib.}
+
+#/ Perform a directed line segment query (like a raycast) against the space calling @c func for each shape intersected.
+proc segmentQuery*(space: PSpace; start: TVector; to: TVector; 
+                    layers: TLayers; group: TGroup; 
+                    func: TSpaceSegmentQueryFunc; data: pointer){.
+  cdecl, importc: "cpSpaceSegmentQuery", dynlib: Lib.}
+#/ Perform a directed line segment query (like a raycast) against the space and return the first shape hit. Returns NULL if no shapes were hit.
+proc segmentQueryFirst*(space: PSpace; start: TVector; to: TVector; 
+                         layers: TLayers; group: TGroup; 
+                         res: PSegmentQueryInfo): PShape{.
+  cdecl, importc: "cpSpaceSegmentQueryFirst", dynlib: Lib.}
+
+#/ Perform a fast rectangle query on the space calling @c func for each shape found.
+#/ Only the shape's bounding boxes are checked for overlap, not their full shape.
+proc BBQuery*(space: PSpace; bb: TBB; layers: TLayers; group: TGroup; 
+                   func: TSpaceBBQueryFunc; data: pointer){.
+  cdecl, importc: "cpSpaceBBQuery", dynlib: Lib.}
+
+#/ Query a space for any shapes overlapping the given shape and call @c func for each shape found.
+proc shapeQuery*(space: PSpace; shape: PShape; func: TSpaceShapeQueryFunc; data: pointer): Bool {.
+  cdecl, importc: "cpSpaceShapeQuery", dynlib: Lib.}
+#/ Call cpBodyActivate() for any shape that is overlaps the given shape.
+proc activateShapesTouchingShape*(space: PSpace; shape: PShape){.
+    cdecl, importc: "cpSpaceActivateShapesTouchingShape", dynlib: Lib.}
+
+#/ Call @c func for each body in the space.
+proc eachBody*(space: PSpace; func: TSpaceBodyIteratorFunc; data: pointer){.
+  cdecl, importc: "cpSpaceEachBody", dynlib: Lib.}
+
+#/ Call @c func for each shape in the space.
+proc eachShape*(space: PSpace; func: TSpaceShapeIteratorFunc; 
+                     data: pointer){.
+  cdecl, importc: "cpSpaceEachShape", dynlib: Lib.}
+#/ Call @c func for each shape in the space.
+proc eachConstraint*(space: PSpace; func: TSpaceConstraintIteratorFunc; 
+                          data: pointer){.
+  cdecl, importc: "cpSpaceEachConstraint", dynlib: Lib.}
+#/ Update the collision detection info for the static shapes in the space.
+proc reindexStatic*(space: PSpace){.
+  cdecl, importc: "cpSpaceReindexStatic", dynlib: Lib.}
+#/ Update the collision detection data for a specific shape in the space.
+proc reindexShape*(space: PSpace; shape: PShape){.
+  cdecl, importc: "cpSpaceReindexShape", dynlib: Lib.}
+#/ Update the collision detection data for all shapes attached to a body.
+proc reindexShapesForBody*(space: PSpace; body: PBody){.
+  cdecl, importc: "cpSpaceReindexShapesForBody", dynlib: Lib.}
+#/ Switch the space to use a spatial has as it's spatial index.
+proc SpaceUseSpatialHash*(space: PSpace; dim: CpFloat; count: cint){.
+  cdecl, importc: "cpSpaceUseSpatialHash", dynlib: Lib.}
+#/ Step the space forward in time by @c dt.
+proc step*(space: PSpace; dt: CpFloat) {.
+  cdecl, importc: "cpSpaceStep", dynlib: Lib.}
+
+
+#/ Convenience constructor for cpVect structs.
+proc vector*(x, y: CpFloat): TVector {.inline.} =
+  result.x = x
+  result.y = y
+proc newVector*(x, y: CpFloat): TVector {.inline.} =
+  return vector(x, y)
+#let VectorZero* = newVector(0.0, 0.0)
+var VectorZero* = newVector(0.0, 0.0)
+
+#/ Vector dot product.
+proc dot*(v1, v2: TVector): CpFloat {.inline.} = 
+  result = v1.x * v2.x + v1.y * v2.y
+
+#/ Returns the length of v.
+#proc len*(v: TVector): CpFloat {.
+#  cdecl, importc: "cpvlength", dynlib: Lib.}
+proc len*(v: TVector): CpFloat {.inline.} =
+  result = v.dot(v).sqrt
+#/ Spherical linearly interpolate between v1 and v2.
+proc slerp*(v1, v2: TVector; t: CpFloat): TVector {.
+  cdecl, importc: "cpvslerp", dynlib: Lib.}
+#/ Spherical linearly interpolate between v1 towards v2 by no more than angle a radians
+proc slerpconst*(v1, v2: TVector; a: CpFloat): TVector {.
+  cdecl, importc: "cpvslerpconst", dynlib: Lib.}
+#/ Returns the unit length vector for the given angle (in radians).
+#proc vectorForAngle*(a: CpFloat): TVector {.
+#  cdecl, importc: "cpvforangle", dynlib: Lib.}
+proc vectorForAngle*(a: CpFloat): TVector {.inline.} =
+  result = newVector(math.cos(a), math.sin(a))
+#/ Returns the angular direction v is pointing in (in radians).
+proc toAngle*(v: TVector): CpFloat {.inline.} =
+  result = math.arctan2(v.y, v.x)
+#/	Returns a string representation of v. Intended mostly for debugging purposes and not production use.
+#/	@attention The string points to a static local and is reset every time the function is called.
+#/	If you want to print more than one vector you will have to split up your printing onto separate lines.
+proc `$`*(v: TVector): cstring {.cdecl, importc: "cpvstr", dynlib: Lib.}
+
+
+#/ Check if two vectors are equal. (Be careful when comparing floating point numbers!)
+proc `==`*(v1, v2: TVector): bool {.inline.} =
+  result = v1.x == v2.x and v1.y == v2.y
+
+#/ Add two vectors
+proc `+`*(v1, v2: TVector): TVector {.inline.} =
+  result = newVector(v1.x + v2.x, v1.y + v2.y)
+proc `+=`*(v1: var TVector; v2: TVector) =
+  v1.x = v1.x + v2.x
+  v1.y = v1.y + v2.y
+
+#/ Subtract two vectors.
+proc `-`*(v1, v2: TVector): TVector {.inline.} =
+  result = newVector(v1.x - v2.x, v1.y - v2.y)
+proc `-=`*(v1: var TVector; v2: TVector) =
+  v1.x = v1.x - v2.x
+  v1.y = v1.y - v2.y
+
+#/ Negate a vector.
+proc `-`*(v: TVector): TVector {.inline.} = 
+  result = newVector(- v.x, - v.y)
+
+#/ Scalar multiplication.
+proc `*`*(v: TVector, s: CpFloat): TVector {.inline.} =
+  result.x = v.x * s
+  result.y = v.y * s
+proc `*=`*(v: var TVector; s: CpFloat) =
+  v.x = v.x * s
+  v.y = v.y * s
+
+#/ 2D vector cross product analog.
+#/ The cross product of 2D vectors results in a 3D vector with only a z component.
+#/ This function returns the magnitude of the z value.
+proc cross*(v1, v2: TVector): CpFloat {.inline.} = 
+  result = v1.x * v2.y - v1.y * v2.x
+
+#/ Returns a perpendicular vector. (90 degree rotation)
+proc perp*(v: TVector): TVector {.inline.} = 
+  result = newVector(- v.y, v.x)
+
+#/ Returns a perpendicular vector. (-90 degree rotation)
+proc rperp*(v: TVector): TVector {.inline.} = 
+  result = newVector(v.y, - v.x)
+
+#/ Returns the vector projection of v1 onto v2.
+proc project*(v1,v2: TVector): TVector {.inline.} = 
+  result = v2 * (v1.dot(v2) / v2.dot(v2))
+
+#/ Uses complex number multiplication to rotate v1 by v2. Scaling will occur if v1 is not a unit vector.
+
+proc rotate*(v1, v2: TVector): TVector {.inline.} = 
+  result = newVector(v1.x * v2.x - v1.y * v2.y, v1.x * v2.y + v1.y * v2.x)
+#/ Inverse of cpvrotate().
+proc unrotate*(v1, v2: TVector): TVector {.inline.} = 
+  result = newVector(v1.x * v2.x + v1.y * v2.y, v1.y * v2.x - v1.x * v2.y)
+#/ Returns the squared length of v. Faster than cpvlength() when you only need to compare lengths.
+proc lenSq*(v: TVector): CpFloat {.inline.} = 
+  result = v.dot(v)
+#/ Linearly interpolate between v1 and v2.
+proc lerp*(v1, v2: TVector; t: CpFloat): TVector {.inline.} = 
+  result = (v1 * (1.0 - t)) + (v2 * t)
+#/ Returns a normalized copy of v.
+proc normalize*(v: TVector): TVector {.inline.} = 
+  result = v * (1.0 / v.len)
+#/ Returns a normalized copy of v or cpvzero if v was already cpvzero. Protects against divide by zero errors.
+proc normalizeSafe*(v: TVector): TVector {.inline.} = 
+  result = if v.x == 0.0 and v.y == 0.0: VectorZero else: v.normalize
+#/ Clamp v to length len.
+proc clamp*(v: TVector; len: CpFloat): TVector {.inline.} = 
+  result = if v.dot(v) > len * len: v.normalize * len else: v
+#/ Linearly interpolate between v1 towards v2 by distance d.
+proc lerpconst*(v1, v2: TVector; d: CpFloat): TVector {.inline.} = 
+  result = v1 + clamp(v2 - v1, d)             #vadd(v1 + vclamp(vsub(v2, v1), d))
+#/ Returns the distance between v1 and v2.
+proc dist*(v1, v2: TVector): CpFloat {.inline.} = 
+  result = (v1 - v2).len #vlength(vsub(v1, v2))
+#/ Returns the squared distance between v1 and v2. Faster than cpvdist() when you only need to compare distances.
+proc distsq*(v1, v2: TVector): CpFloat {.inline.} = 
+  result = (v1 - v2).lenSq  #vlengthsq(vsub(v1, v2))
+#/ Returns true if the distance between v1 and v2 is less than dist.
+proc near*(v1, v2: TVector; dist: CpFloat): Bool{.inline.} = 
+  result = v1.distSq(v2) < dist * dist
+
+
+
+##cpBody.h
+proc allocBody*(): PBody {.importc: "cpBodyAlloc", dynlib: Lib.}
+proc init*(body: PBody; m: CpFloat; i: CpFloat): PBody {.
+  importc: "cpBodyInit", dynlib: Lib.}
+proc newBody*(m: CpFloat; i: CpFloat): PBody {.
+  importc: "cpBodyNew", dynlib: Lib.}
+
+proc initStaticBody*(body: PBody): PBody{.
+  importc: "cpBodyInitStatic", dynlib: Lib.}
+#/ Allocate and initialize a static cpBody.
+proc newStatic*(): PBody{.importc: "cpBodyNewStatic", dynlib: Lib.}
+#/ Destroy a cpBody.
+proc destroy*(body: PBody){.importc: "cpBodyDestroy", dynlib: Lib.}
+#/ Destroy and free a cpBody.
+proc free*(body: PBody){.importc: "cpBodyFree", dynlib: Lib.}
+
+#/ Wake up a sleeping or idle body.
+proc activate*(body: PBody){.importc: "cpBodyActivate", dynlib: Lib.}
+#/ Wake up any sleeping or idle bodies touching a static body.
+proc activateStatic*(body: PBody; filter: PShape){.
+    importc: "cpBodyActivateStatic", dynlib: Lib.}
+#/ Force a body to fall asleep immediately.
+proc Sleep*(body: PBody){.importc: "cpBodySleep", dynlib: Lib.}
+#/ Force a body to fall asleep immediately along with other bodies in a group.
+proc SleepWithGroup*(body: PBody; group: PBody){.
+    importc: "cpBodySleepWithGroup", dynlib: Lib.}
+#/ Returns true if the body is sleeping.
+proc isSleeping*(body: PBody): Bool {.inline.} = 
+  return body.node.root != nil
+#/ Returns true if the body is static.
+proc isStatic*(body: PBody): bool {.inline.} = 
+  return body.node.idleTime == CpInfinity
+#/ Returns true if the body has not been added to a space.
+proc isRogue*(body: PBody): Bool {.inline.} = 
+  return body.space == nil
+
+# #define CP_DefineBodyStructGetter(type, member, name) \
+# static inline type cpBodyGet##name(const cpBody *body){return body->member;}
+# #define CP_DefineBodyStructSetter(type, member, name) \
+# static inline void cpBodySet##name(cpBody *body, const type value){ \
+# 	cpBodyActivate(body); \
+# 	cpBodyAssertSane(body); \
+# 	body->member = value; \
+# }
+# #define CP_DefineBodyStructProperty(type, member, name) \
+# CP_DefineBodyStructGetter(type, member, name) \
+# CP_DefineBodyStructSetter(type, member, name)
+
+defGetter(PBody, CpFloat, m, Mass)
+#/ Set the mass of a body.
+when defined(MoreNimrod):
+  defSetter(PBody, CpFloat, m, Mass)
+else:
+  proc setMass*(body: PBody; m: CpFloat){.
+    cdecl, importc: "cpBodySetMass", dynlib: Lib.}
+
+#/ Get the moment of a body.
+defGetter(PBody, CpFloat, i, Moment)
+#/ Set the moment of a body.
+when defined(MoreNimrod):
+  defSetter(PBody, CpFloat, i, Moment)
+else: 
+  proc SetMoment*(body: PBody; i: CpFloat) {.
+    cdecl, importc: "cpBodySetMoment", dynlib: Lib.}
+
+#/ Get the position of a body.
+defGetter(PBody, TVector, p, Pos)
+#/ Set the position of a body.
+when defined(MoreNimrod):
+  defSetter(PBody, TVector, p, Pos)
+else:
+  proc setPos*(body: PBody; pos: TVector) {.
+    cdecl, importc: "cpBodySetPos", dynlib: Lib.}
+
+defProp(PBody, TVector, v, Vel)
+defProp(PBody, TVector, f, Force)
+
+#/ Get the angle of a body.
+defGetter(PBody, CpFloat, a, Angle)
+#/ Set the angle of a body.
+proc setAngle*(body: PBody; a: CpFloat){.
+  cdecl, importc: "cpBodySetAngle", dynlib: Lib.}
+
+defProp(PBody, CpFloat, w, AngVel)
+defProp(PBody, CpFloat, t, Torque)
+defGetter(PBody, TVector, rot, Rot)
+defProp(PBody, CpFloat, v_limit, VelLimit)
+defProp(PBody, CpFloat, w_limit, AngVelLimit)
+defProp(PBody, pointer, data, UserData)
+
+#/ Default Integration functions.
+proc UpdateVelocity*(body: PBody; gravity: TVector; damping: CpFloat; dt: CpFloat){.
+  cdecl, importc: "cpBodyUpdateVelocity", dynlib: Lib.}
+proc UpdatePosition*(body: PBody; dt: CpFloat){.
+  cdecl, importc: "cpBodyUpdatePosition", dynlib: Lib.}
+#/ Convert body relative/local coordinates to absolute/world coordinates.
+proc Local2World*(body: PBody; v: TVector): TVector{.inline.} = 
+  result = body.p + v.rotate(body.rot) ##return cpvadd(body.p, cpvrotate(v, body.rot))
+#/ Convert body absolute/world coordinates to  relative/local coordinates.
+proc world2Local*(body: PBody; v: TVector): TVector{.inline.} = 
+  result = (v - body.p).unrotate(body.rot)
+#/ Set the forces and torque or a body to zero.
+proc resetForces*(body: PBody){.
+  cdecl, importc: "cpBodyResetForces", dynlib: Lib.}
+#/ Apply an force (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
+proc applyForce*(body: PBody; f, r: TVector){.
+  cdecl, importc: "cpBodyApplyForce", dynlib: Lib.}
+#/ Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
+proc applyImpulse*(body: PBody; j, r: TVector){.
+  cdecl, importc: "cpBodyApplyImpulse", dynlib: Lib.}
+#/ Get the velocity on a body (in world units) at a point on the body in world coordinates.
+
+proc getVelAtWorldPoint*(body: PBody; point: TVector): TVector{.
+  cdecl, importc: "cpBodyGetVelAtWorldPoint", dynlib: Lib.}
+#/ Get the velocity on a body (in world units) at a point on the body in local coordinates.
+proc getVelAtLocalPoint*(body: PBody; point: TVector): TVector{.
+  cdecl, importc: "cpBodyGetVelAtLocalPoint", dynlib: Lib.}
+#/ Get the kinetic energy of a body.
+# static inline CpFloat cpBodyKineticEnergy(const cpBody *body)
+# {
+# 	// Need to do some fudging to avoid NaNs
+# 	cpFloat vsq = cpvdot(body->v, body->v);
+# 	cpFloat wsq = body->w*body->w;
+# 	return (vsq ? vsq*body->m : 0.0f) + (wsq ? wsq*body->i : 0.0f);
+# }
+proc kineticEnergy*(body: PBOdy): CpFloat =
+  result = (body.v.dot(body.v) * body.m) + (body.w * body.w * body.i)
+
+#/ Call @c func once for each shape attached to @c body and added to the space.
+proc eachShape*(body: PBody; func: TBodyShapeIteratorFunc; 
+                      data: pointer){.
+  cdecl, importc: "cpBodyEachShape", dynlib: Lib.}
+#/ Call @c func once for each constraint attached to @c body and added to the space.
+proc eachConstraint*(body: PBody; func: TBodyConstraintIteratorFunc; 
+                           data: pointer) {.
+  cdecl, importc: "cpBodyEachConstraint", dynlib: Lib.}
+#/ Call @c func once for each arbiter that is currently active on the body.
+proc eachArbiter*(body: PBody; func: TBodyArbiterIteratorFunc; 
+                        data: pointer){.
+  cdecl, importc: "cpBodyEachArbiter", dynlib: Lib.}
+#/ Allocate a spatial hash.
+proc SpaceHashAlloc*(): PSpaceHash{.
+  cdecl, importc: "cpSpaceHashAlloc", dynlib: Lib.}
+#/ Initialize a spatial hash. 
+proc SpaceHashInit*(hash: PSpaceHash; celldim: CpFloat; numcells: cint; 
+                    bbfunc: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{.
+  cdecl, importc: "cpSpaceHashInit", dynlib: Lib.}
+#/ Allocate and initialize a spatial hash.
+proc SpaceHashNew*(celldim: CpFloat; cells: cint; bbfunc: TSpatialIndexBBFunc; 
+                   staticIndex: PSpatialIndex): PSpatialIndex{.
+  cdecl, importc: "cpSpaceHashNew", dynlib: Lib.}
+#/ Change the cell dimensions and table size of the spatial hash to tune it.
+#/ The cell dimensions should roughly match the average size of your objects
+#/ and the table size should be ~10 larger than the number of objects inserted.
+#/ Some trial and error is required to find the optimum numbers for efficiency.
+proc SpaceHashResize*(hash: PSpaceHash; celldim: CpFloat; numcells: cint){.
+  cdecl, importc: "cpSpaceHashResize", dynlib: Lib.}
+#MARK: AABB Tree
+
+
+#/ Allocate a bounding box tree.
+proc BBTreeAlloc*(): PBBTree{.cdecl, importc: "cpBBTreeAlloc", dynlib: Lib.}
+#/ Initialize a bounding box tree.
+proc BBTreeInit*(tree: PBBTree; bbfunc: TSpatialIndexBBFunc; 
+                 staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl, 
+    importc: "cpBBTreeInit", dynlib: Lib.}
+#/ Allocate and initialize a bounding box tree.
+proc BBTreeNew*(bbfunc: TSpatialIndexBBFunc; staticIndex: PSpatialIndex): PSpatialIndex{.
+    cdecl, importc: "cpBBTreeNew", dynlib: Lib.}
+#/ Perform a static top down optimization of the tree.
+proc BBTreeOptimize*(index: PSpatialIndex){.
+  cdecl, importc: "cpBBTreeOptimize", dynlib: Lib.}
+#/ Set the velocity function for the bounding box tree to enable temporal coherence.
+
+proc BBTreeSetVelocityFunc*(index: PSpatialIndex; func: TBBTreeVelocityFunc){.
+    cdecl, importc: "cpBBTreeSetVelocityFunc", dynlib: Lib.}
+#MARK: Single Axis Sweep
+
+
+#/ Allocate a 1D sort and sweep broadphase.
+
+proc Sweep1DAlloc*(): ptr TSweep1D{.cdecl, importc: "cpSweep1DAlloc", 
+                                    dynlib: Lib.}
+#/ Initialize a 1D sort and sweep broadphase.
+
+proc Sweep1DInit*(sweep: ptr TSweep1D; bbfunc: TSpatialIndexBBFunc; 
+                  staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.cdecl, 
+    importc: "cpSweep1DInit", dynlib: Lib.}
+#/ Allocate and initialize a 1D sort and sweep broadphase.
+
+proc Sweep1DNew*(bbfunc: TSpatialIndexBBFunc; staticIndex: ptr TSpatialIndex): ptr TSpatialIndex{.
+    cdecl, importc: "cpSweep1DNew", dynlib: Lib.}
+
+
+
+defProp(PArbiter, CpFloat, e, Elasticity)
+defProp(PArbiter, CpFloat, u, Friction)
+defProp(PArbiter, TVector, surface_vr, SurfaceVelocity)
+
+#/ Calculate the total impulse that was applied by this 
+#/ This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
+proc totalImpulse*(obj: PArbiter): TVector {.cdecl, importc: "cpArbiterTotalImpulse", dynlib: Lib.}
+
+#/ Calculate the total impulse including the friction that was applied by this arbiter.
+#/ This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
+proc totalImpulseWithFriction*(obj: PArbiter): TVector {.cdecl, importc: "cpArbiterTotalImpulseWithFriction", dynlib: Lib.}
+
+#/ Calculate the amount of energy lost in a collision including static, but not dynamic friction.
+#/ This function should only be called from a post-solve, post-step or cpBodyEachArbiter callback.
+proc totalKE*(obj: PArbiter): CpFloat {.cdecl, importc: "cpArbiterTotalKE", dynlib: Lib.}
+
+
+#/ Causes a collision pair to be ignored as if you returned false from a begin callback.
+#/ If called from a pre-step callback, you will still need to return false
+#/ if you want it to be ignored in the current step.
+proc ignore*(arb: PArbiter) {.cdecl, importc: "cpArbiterIgnore", dynlib: Lib.}
+
+#/ Return the colliding shapes involved for this arbiter.
+#/ The order of their cpSpace.collision_type values will match
+#/ the order set when the collision handler was registered.
+proc getShapes*(arb: PArbiter, a, b: var PShape) {.inline.} =
+  if arb.swappedColl.bool:
+    a = arb.b
+    b = arb.a
+  else:
+    a = arb.a
+    b = arb.b
+
+#/ A macro shortcut for defining and retrieving the shapes from an arbiter.
+#define CP_ARBITER_GET_SHAPES(arb, a, b) cpShape *a, *b; cpArbiterGetShapes(arb, &a, &b);
+template getShapes*(arb: PArbiter, name1, name2: expr): stmt {.immediate.} =
+  var name1, name2: PShape
+  getShapes(arb, name1, name2)
+
+
+#/ Return the colliding bodies involved for this arbiter.
+#/ The order of the cpSpace.collision_type the bodies are associated with values will match
+#/ the order set when the collision handler was registered.
+#proc getBodies*(arb: PArbiter, a, b: var PBody) {.inline.} = 
+#  getShapes(arb, shape1, shape2)
+#  a = shape1.body
+#  b = shape2.body
+
+#/ A macro shortcut for defining and retrieving the bodies from an arbiter.
+#define CP_ARBITER_GET_BODIES(arb, a, b) cpBody *a, *b; cpArbiterGetBodies(arb, &a, &b);
+template getBodies*(arb: PArbiter, name1, name2: expr): stmt {.immediate.} =
+  var name1, name2: PBOdy
+  getBodies(arb, name1, name2)
+
+proc isFirstContact*(arb: PArbiter): bool {.inline.} =
+  result = arb.state == ArbiterStateFirstColl
+
+proc getCount*(arb: PArbiter): cint {.inline.} =
+  result = arb.numContacts
+
+#/ Return a contact set from an arbiter.
+proc getContactPointSet*(arb: PArbiter): TContactPointSet {.
+  cdecl, importc: "cpArbiterGetContactPointSet", dynlib: Lib.}
+#/ Get the normal of the @c ith contact point.
+proc getNormal*(arb: PArbiter; i: cint): TVector {.
+  cdecl, importc: "cpArbiterGetNormal", dynlib: Lib.}
+#/ Get the position of the @c ith contact point.
+proc getPoint*(arb: PArbiter; i: cint): TVector {.
+  cdecl, importc: "cpArbiterGetPoint", dynlib: Lib.}
+#/ Get the depth of the @c ith contact point.
+proc getDepth*(arb: PArbiter; i: cint): CpFloat {.
+  cdecl, importc: "cpArbiterGetDepth", dynlib: Lib.}
+
+##Shapes
+template defShapeSetter(memberType: typedesc, memberName: expr, procName: expr, activates: bool): stmt {.immediate.} =
+  proc `set procName`*(obj: PShape, value: memberType) {.cdecl.} =
+    if activates and obj.body != nil: obj.body.activate()
+    obj.memberName = value
+template defShapeProp(memberType: typedesc, memberName: expr, procName: expr, activates: bool): stmt {.immediate.} =
+  defGetter(PShape, memberType, memberName, procName)
+  defShapeSetter(memberType, memberName, procName, activates)
+
+#/ Destroy a shape.
+proc destroy*(shape: PShape) {.
+  cdecl, importc: "cpShapeDestroy", dynlib: Lib.}
+#/ Destroy and Free a shape.
+proc free*(shape: PShape){.
+  cdecl, importc: "cpShapeFree", dynlib: Lib.}
+#/ Update, cache and return the bounding box of a shape based on the body it's attached to.
+proc cacheBB*(shape: PShape): TBB{.
+  cdecl, importc: "cpShapeCacheBB", dynlib: Lib.}
+#/ Update, cache and return the bounding box of a shape with an explicit transformation.
+proc update*(shape: PShape; pos: TVector; rot: TVector): TBB {.
+  cdecl, importc: "cpShapeUpdate", dynlib: Lib.}
+#/ Test if a point lies within a shape.
+proc pointQuery*(shape: PShape; p: TVector): Bool32 {.
+  cdecl, importc: "cpShapePointQuery", dynlib: Lib.}
+
+#/ Perform a nearest point query. It finds the closest point on the surface of shape to a specific point.
+#/ The value returned is the distance between the points. A negative distance means the point is inside the shape.
+proc nearestPointQuery*(shape: PShape; p: TVector; res: PNearestPointQueryInfo): CpFloat {.
+  cdecl, importc: "cpShapeNearestPointQuery", dynlib: Lib.}
+#/ Perform a segment query against a shape. @c info must be a pointer to a valid cpSegmentQueryInfo structure.
+proc segmentQuery*(shape: PShape, a, b: TVector, info: PSegmentQueryInfo): bool {.
+  cdecl, importc: "cpShapeSegmentQuery", dynlib: Lib.}
+
+#/ Get the hit point for a segment query.
+## Possibly change; info to PSegmentQueryInfo 
+proc queryHitPoint*(start, to: TVector, info: TSegmentQueryInfo): TVector {.inline.} =
+  result = start.lerp(to, info.t)
+
+#/ Get the hit distance for a segment query.
+proc queryHitDist*(start, to: TVector, info: TSegmentQueryInfo): CpFloat {.inline.} =
+  result = start.dist(to) * info.t
+
+defGetter(PShape, PSpace, space, Space)
+
+defGetter(PShape, PBody, body, Body)
+proc setBody*(shape: PShape, value: PBody) {.
+  cdecl, importc: "cpShapeSetBody", dynlib: Lib.}
+
+
+defGetter(PShape, TBB, bb, BB)
+defShapeProp(Bool32, sensor, Sensor, true)
+defShapeProp(CpFloat, e, Elasticity, false)
+defShapeProp(CpFloat, u, Friction, true)
+defShapeProp(TVector, surface_v, SurfaceVelocity, true)
+defShapeProp(pointer, data, UserData, false)
+defShapeProp(TCollisionType, collision_type, CollisionType, true)
+defShapeProp(TGroup, group, Group, true)
+defShapeProp(TLayers, layers, Layers, true)
+
+#/ When initializing a shape, it's hash value comes from a counter.
+#/ Because the hash value may affect iteration order, you can reset the shape ID counter
+#/ when recreating a space. This will make the simulation be deterministic.
+proc resetShapeIdCounter*(): void {.cdecl, importc: "cpResetShapeIdCounter", dynlib: Lib.}
+#/ Allocate a circle shape.
+proc CircleShapeAlloc*(): PCircleShape {.cdecl, importc: "cpCircleShapeAlloc", dynlib: Lib.}
+#/ Initialize a circle shape.
+proc init*(circle: PCircleShape, body: PBody, radius: CpFloat, offset: TVector): PCircleShape {.
+  cdecl, importc: "cpCircleShapeInit", dynlib: Lib.}
+#/ Allocate and initialize a circle shape.
+proc newCircleShape*(body: PBody, radius: CpFloat, offset: TVector): PShape {.
+  cdecl, importc: "cpCircleShapeNew", dynlib: Lib.}
+
+proc getCircleOffset*(shape: PShape): TVector {.
+  cdecl, importc: "cpCircleShapeGetOffset", dynlib: Lib.}
+proc getCircleRadius*(shape: PShape): CpFloat {.
+  cdecl, importc: "cpCircleShapeGetRadius", dynlib: Lib.}
+
+
+#/ Allocate a polygon shape.
+proc allocPolyShape*(): PPolyShape {.
+  cdecl, importc: "cpPolyShapeAlloc", dynlib: Lib.}
+#/ Initialize a polygon shape.
+#/ A convex hull will be created from the vertexes.
+proc init*(poly: PPolyShape; body: PBody, numVerts: cint;
+            verts: ptr TVector; offset: TVector): PPolyShape {.
+  cdecl, importc: "cpPolyShapeInit", dynlib: Lib.}
+#/ Allocate and initialize a polygon shape.
+#/ A convex hull will be created from the vertexes.
+proc newPolyShape*(body: PBody; numVerts: cint; verts: ptr TVector; 
+                    offset: TVector): PShape {.
+  cdecl, importc: "cpPolyShapeNew", dynlib: Lib.}
+#/ Initialize a box shaped polygon shape.
+proc init*(poly: PPolyShape; body: PBody; width, height: CpFloat): PPolyShape {.
+  cdecl, importc: "cpBoxShapeInit", dynlib: Lib.}
+#/ Initialize an offset box shaped polygon shape.
+proc init*(poly: PPolyShape; body: PBody; box: TBB): PPolyShape {.
+  cdecl, importc: "cpBoxShapeInit2", dynlib: Lib.}
+#/ Allocate and initialize a box shaped polygon shape.
+proc newBoxShape*(body: PBody; width, height: CpFloat): PShape {.
+  cdecl, importc: "cpBoxShapeNew", dynlib: Lib.}
+#/ Allocate and initialize an offset box shaped polygon shape.
+proc newBoxShape*(body: PBody; box: TBB): PShape {.
+  cdecl, importc: "cpBoxShapeNew2", dynlib: Lib.}
+
+#/ Check that a set of vertexes is convex and has a clockwise winding.
+#/ NOTE: Due to floating point precision issues, hulls created with cpQuickHull() are not guaranteed to validate!
+proc validatePoly*(verts: ptr TVector; numVerts: cint): bool {.
+  cdecl, importc: "cpPolyValidate", dynlib: Lib.}
+#/ Get the number of verts in a polygon shape.
+proc getNumVerts*(shape: PShape): cint {.
+  cdecl, importc: "cpPolyShapeGetNumVerts", dynlib: Lib.}
+#/ Get the @c ith vertex of a polygon shape.
+proc getVert*(shape: PShape; index: cint): TVector {.
+  cdecl, importc: "cpPolyShapeGetVert", dynlib: Lib.}
+
+#/ Allocate a segment shape.
+proc allocSegmentShape*(): PSegmentShape {.
+  cdecl, importc: "cpSegmentShapeAlloc", dynlib: Lib.}
+#/ Initialize a segment shape.
+proc init*(seg: PSegmentShape, body: PBody, a, b: TVector, radius: CpFloat): PSegmentShape {.
+  cdecl, importc: "cpSegmentShapeInit", dynlib: Lib.}
+#/ Allocate and initialize a segment shape.
+proc newSegmentShape*(body: PBody, a, b: TVector, radius: CpFloat): PShape {.
+  cdecl, importc: "cpSegmentShapeNew", dynlib: Lib.}
+
+proc setSegmentNeighbors*(shape: PShape, prev, next: TVector) {.
+  cdecl, importc: "cpSegmentShapeSetNeighbors", dynlib: Lib.}
+proc getSegmentA*(shape: PShape): TVector {.
+  cdecl, importc: "cpSegmentShapeGetA", dynlib: Lib.}
+proc getSegmentB*(shape: PShape): TVector {.
+  cdecl, importc: "cpSegmentShapeGetB", dynlib: Lib.}
+proc getSegmentNormal*(shape: PShape): TVector {.
+  cdecl, importc: "cpSegmentShapeGetNormal", dynlib: Lib.}
+proc getSegmentRadius*(shape: PShape): CpFloat {.
+  cdecl, importc: "cpSegmentShapeGetRadius", dynlib: Lib.}
+
+
+#/ Version string.
+#var VersionString*{.importc: "cpVersionString", dynlib: Lib.}: cstring
+#/ Calculate the moment of inertia for a circle.
+#/ @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.
+when defined(MoreNimrod):
+  proc momentForCircle*(m, r1, r2: CpFloat; offset: TVector): CpFloat {.cdecl.} =
+    result = m * (0.5 * (r1 * r1 + r2 * r2) + lenSq(offset))
+else:
+  proc momentForCircle*(m, r1, r2: CpFloat; offset: TVector): CpFloat {.
+    cdecl, importc: "cpMomentForCircle", dynlib: Lib.}
+
+#/ Calculate area of a hollow circle.
+#/ @c r1 and @c r2 are the inner and outer diameters. A solid circle has an inner diameter of 0.
+proc AreaForCircle*(r1: CpFloat; r2: CpFloat): CpFloat {.
+  cdecl, importc: "cpAreaForCircle", dynlib: Lib.}
+#/ Calculate the moment of inertia for a line segment.
+#/ Beveling radius is not supported.
+proc MomentForSegment*(m: CpFloat; a, b: TVector): CpFloat {.
+  cdecl, importc: "cpMomentForSegment", dynlib: Lib.}
+#/ Calculate the area of a fattened (capsule shaped) line segment.
+proc AreaForSegment*(a, b: TVector; r: CpFloat): CpFloat {.
+  cdecl, importc: "cpAreaForSegment", dynlib: Lib.}
+#/ Calculate the moment of inertia for a solid polygon shape assuming it's center of gravity is at it's centroid. The offset is added to each vertex.
+proc MomentForPoly*(m: CpFloat; numVerts: cint; verts: ptr TVector; offset: TVector): CpFloat {.
+  cdecl, importc: "cpMomentForPoly", dynlib: Lib.}
+#/ Calculate the signed area of a polygon. A Clockwise winding gives positive area.
+#/ This is probably backwards from what you expect, but matches Chipmunk's the winding for poly shapes.
+proc AreaForPoly*(numVerts: cint; verts: ptr TVector): CpFloat {.
+  cdecl, importc: "cpAreaForPoly", dynlib: Lib.}
+#/ Calculate the natural centroid of a polygon.
+proc CentroidForPoly*(numVerts: cint; verts: ptr TVector): TVector {.
+  cdecl, importc: "cpCentroidForPoly", dynlib: Lib.}
+#/ Center the polygon on the origin. (Subtracts the centroid of the polygon from each vertex)
+proc RecenterPoly*(numVerts: cint; verts: ptr TVector) {.
+  cdecl, importc: "cpRecenterPoly", dynlib: Lib.}
+#/ Calculate the moment of inertia for a solid box.
+proc MomentForBox*(m, width, height: CpFloat): CpFloat {.
+  cdecl, importc: "cpMomentForBox", dynlib: Lib.}
+#/ Calculate the moment of inertia for a solid box.
+proc MomentForBox2*(m: CpFloat; box: TBB): CpFloat {.
+  cdecl, importc: "cpMomentForBox2", dynlib: Lib.}
+
+
+
+##constraints
+type 
+  #TODO: all these are private
+  #TODO: defConstraintProp()
+  PPinJoint = ptr TPinJoint
+  TPinJoint{.pf.} = object 
+    constraint: PConstraint
+    anchr1: TVector
+    anchr2: TVector
+    dist: CpFloat
+    r1: TVector
+    r2: TVector
+    n: TVector
+    nMass: CpFloat
+    jnAcc: CpFloat
+    jnMax: CpFloat
+    bias: CpFloat
+  PSlideJoint = ptr TSlideJoint
+  TSlideJoint{.pf.} = object 
+    constraint: PConstraint
+    anchr1: TVector
+    anchr2: TVector
+    min: CpFloat
+    max: CpFloat
+    r1: TVector
+    r2: TVector
+    n: TVector
+    nMass: CpFloat
+    jnAcc: CpFloat
+    jnMax: CpFloat
+    bias: CpFloat
+  PPivotJoint = ptr TPivotJoint
+  TPivotJoint{.pf.} = object 
+    constraint: PConstraint
+    anchr1: TVector
+    anchr2: TVector
+    r1: TVector
+    r2: TVector
+    k1: TVector
+    k2: TVector
+    jAcc: TVector
+    jMaxLen: CpFloat
+    bias: TVector
+  PGrooveJoint = ptr TGrooveJoint
+  TGrooveJoint{.pf.} = object 
+    constraint: PConstraint
+    grv_n: TVector
+    grv_a: TVector
+    grv_b: TVector
+    anchr2: TVector
+    grv_tn: TVector
+    clamp: CpFloat
+    r1: TVector
+    r2: TVector
+    k1: TVector
+    k2: TVector
+    jAcc: TVector
+    jMaxLen: CpFloat
+    bias: TVector
+  PDampedSpring = ptr TDampedSpring
+  TDampedSpring{.pf.} = object 
+    constraint: PConstraint
+    anchr1: TVector
+    anchr2: TVector
+    restLength: CpFloat
+    stiffness: CpFloat
+    damping: CpFloat
+    springForceFunc: TDampedSpringForceFunc
+    target_vrn: CpFloat
+    v_coef: CpFloat
+    r1: TVector
+    r2: TVector
+    nMass: CpFloat
+    n: TVector
+  PDampedRotarySpring = ptr TDampedRotarySpring
+  TDampedRotarySpring{.pf.} = object 
+    constraint: PConstraint
+    restAngle: CpFloat
+    stiffness: CpFloat
+    damping: CpFloat
+    springTorqueFunc: TDampedRotarySpringTorqueFunc
+    target_wrn: CpFloat
+    w_coef: CpFloat
+    iSum: CpFloat
+  PRotaryLimitJoint = ptr TRotaryLimitJoint
+  TRotaryLimitJoint{.pf.} = object 
+    constraint: PConstraint
+    min: CpFloat
+    max: CpFloat
+    iSum: CpFloat
+    bias: CpFloat
+    jAcc: CpFloat
+    jMax: CpFloat
+  PRatchetJoint = ptr TRatchetJoint
+  TRatchetJoint{.pf.} = object 
+    constraint: PConstraint
+    angle: CpFloat
+    phase: CpFloat
+    ratchet: CpFloat
+    iSum: CpFloat
+    bias: CpFloat
+    jAcc: CpFloat
+    jMax: CpFloat
+  PGearJoint = ptr TGearJoint
+  TGearJoint{.pf.} = object 
+    constraint: PConstraint
+    phase: CpFloat
+    ratio: CpFloat
+    ratio_inv: CpFloat
+    iSum: CpFloat
+    bias: CpFloat
+    jAcc: CpFloat
+    jMax: CpFloat
+  PSimpleMotor = ptr TSimpleMotor
+  TSimpleMotor{.pf.} = object 
+    constraint: PConstraint
+    rate: CpFloat
+    iSum: CpFloat
+    jAcc: CpFloat
+    jMax: CpFloat
+  TDampedSpringForceFunc* = proc (spring: PConstraint; dist: CpFloat): CpFloat{.
+    cdecl.}
+  TDampedRotarySpringTorqueFunc* = proc (spring: PConstraint; 
+      relativeAngle: CpFloat): CpFloat {.cdecl.}
+#/ Destroy a constraint.
+proc destroy*(constraint: PConstraint){.
+  cdecl, importc: "cpConstraintDestroy", dynlib: Lib.}
+#/ Destroy and free a constraint.111
+proc free*(constraint: PConstraint){.
+  cdecl, importc: "cpConstraintFree", dynlib: Lib.}
+
+#/ @private
+proc activateBodies(constraint: PConstraint) {.inline.} = 
+  if not constraint.a.isNil: constraint.a.activate()
+  if not constraint.b.isNil: constraint.b.activate()
+
+# /// @private
+# #define CP_DefineConstraintStructGetter(type, member, name) \
+# static inline type cpConstraint##Get##name(const cpConstraint *constraint){return constraint->member;}
+# /// @private
+# #define CP_DefineConstraintStructSetter(type, member, name) \
+# static inline void cpConstraint##Set##name(cpConstraint *constraint, type value){ \
+# 	cpConstraintActivateBodies(constraint); \
+# 	constraint->member = value; \
+# }
+template defConstraintSetter(memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
+  proc `set name`*(constraint: PConstraint, value: memberType) {.cdecl.} =
+    activateBodies(constraint)
+    constraint.member = value
+template defConstraintProp(memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
+  defGetter(PConstraint, memberType, member, name)
+  defConstraintSetter(memberType, member, name)
+# CP_DefineConstraintStructGetter(cpSpace*, CP_PRIVATE(space), Space)
+defGetter(PConstraint, PSpace, space, Space)
+defGetter(PConstraint, PBody, a, A)
+defGetter(PConstraint, PBody, a, B)
+defGetter(PConstraint, CpFloat, maxForce, MaxForce)
+defGetter(PConstraint, CpFloat, errorBias, ErrorBias)
+defGetter(PConstraint, CpFloat, maxBias, MaxBias)
+defGetter(PConstraint, TConstraintPreSolveFunc, preSolve, PreSolveFunc)
+defGetter(PConstraint, TConstraintPostSolveFunc, postSolve, PostSolveFunc)
+defGetter(PConstraint, CpDataPointer, data, UserData)
+# Get the last impulse applied by this constraint.
+proc getImpulse*(constraint: PConstraint): CpFloat {.inline.} = 
+  return constraint.klass.getImpulse(constraint)
+
+# #define cpConstraintCheckCast(constraint, struct) \
+# 	cpAssertHard(constraint->CP_PRIVATE(klass) == struct##GetClass(), "Constraint is not a "#struct)
+# #define CP_DefineConstraintGetter(struct, type, member, name) \
+# static inline type struct##Get##name(const cpConstraint *constraint){ \
+# 	cpConstraintCheckCast(constraint, struct); \
+# 	return ((struct *)constraint)->member; \
+# }
+# #define CP_DefineConstraintSetter(struct, type, member, name) \
+# static inline void struct##Set##name(cpConstraint *constraint, type value){ \
+# 	cpConstraintCheckCast(constraint, struct); \
+# 	cpConstraintActivateBodies(constraint); \
+# 	((struct *)constraint)->member = value; \
+# }
+template constraintCheckCast(constraint: PConstraint, ctype: expr): stmt {.immediate.} =
+  assert(constraint.klass == `ctype getClass`(), "Constraint is the wrong class")
+template defCGetter(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} = 
+  proc `get ctype name`*(constraint: PConstraint): memberType {.cdecl.} =
+    constraintCheckCast(constraint, ctype)
+    result = cast[`P ctype`](constraint).member
+template defCSetter(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
+  proc `set ctype name`*(constraint: PConstraint, value: memberType) {.cdecl.} =
+    constraintCheckCast(constraint, ctype)
+    activateBodies(constraint)
+    cast[`P ctype`](constraint).member = value
+template defCProp(ctype: expr, memberType: typedesc, member: expr, name: expr): stmt {.immediate.} =
+  defCGetter(ctype, memberType, member, name)
+  defCSetter(ctype, memberType, member, name)
+
+proc PinJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpPinJointGetClass", dynlib: Lib.}
+#/ @private
+
+#/ Allocate a pin joint.
+proc AllocPinJoint*(): PPinJoint{.
+  cdecl, importc: "cpPinJointAlloc", dynlib: Lib.}
+#/ Initialize a pin joint.
+proc PinJointInit*(joint: PPinJoint; a: PBody; b: PBody; anchr1: TVector; 
+                   anchr2: TVector): PPinJoint{.
+  cdecl, importc: "cpPinJointInit", dynlib: Lib.}
+#/ Allocate and initialize a pin joint.
+proc newPinJoint*(a: PBody; b: PBody; anchr1: TVector; anchr2: TVector): PConstraint{.
+  cdecl, importc: "cpPinJointNew", dynlib: Lib.}
+# CP_DefineConstraintProperty(cpPinJoint, cpVect, anchr1, Anchr1)
+defCProp(PinJoint, TVector, anchr1, Anchr1)
+defCProp(PinJoint, TVector, anchr2, Anchr2)
+defCProp(PinJoint, CpFloat, dist, Dist)
+
+proc SlideJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpSlideJointGetClass", dynlib: Lib.}
+#/ Allocate a slide joint.
+proc AllocSlideJoint*(): PSlideJoint{.
+  cdecl, importc: "cpSlideJointAlloc", dynlib: Lib.}
+#/ Initialize a slide joint.
+proc init*(joint: PSlideJoint; a, b: PBody; anchr1, anchr2: TVector;
+            min, max: CpFloat): PSlideJoint{.
+  cdecl, importc: "cpSlideJointInit", dynlib: Lib.}
+#/ Allocate and initialize a slide joint.
+proc newSlideJoint*(a, b: PBody; anchr1, anchr2: TVector; min, max: CpFloat): PConstraint{.
+  cdecl, importc: "cpSlideJointNew", dynlib: Lib.}
+
+defCProp(SlideJoint, TVector, anchr1, Anchr1)
+defCProp(SlideJoint, TVector, anchr2, Anchr2)
+defCProp(SlideJoint, CpFloat, min, Min)
+defCProp(SlideJoint, CpFloat, max, Max)
+
+proc pivotJointGetClass*(): PConstraintClass {.
+  cdecl, importc: "cpPivotJointGetClass", dynlib: Lib.}
+
+#/ Allocate a pivot joint
+proc allocPivotJoint*(): PPivotJoint{.
+  cdecl, importc: "cpPivotJointAlloc", dynlib: Lib.}
+#/ Initialize a pivot joint.
+proc init*(joint: PPivotJoint; a, b: PBody; anchr1, anchr2: TVector): PPivotJoint{.
+  cdecl, importc: "cpPivotJointInit", dynlib: Lib.}
+#/ Allocate and initialize a pivot joint.
+proc newPivotJoint*(a, b: PBody; pivot: TVector): PConstraint{.
+  cdecl, importc: "cpPivotJointNew", dynlib: Lib.}
+#/ Allocate and initialize a pivot joint with specific anchors.
+proc newPivotJoint*(a, b: PBody; anchr1, anchr2: TVector): PConstraint{.
+  cdecl, importc: "cpPivotJointNew2", dynlib: Lib.}
+
+defCProp(PivotJoint, TVector, anchr1, Anchr1)
+defCProp(PivotJoint, TVector, anchr2, Anchr2)
+
+
+proc GrooveJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpGrooveJointGetClass", dynlib: Lib.}
+#/ Allocate a groove joint.
+proc GrooveJointAlloc*(): ptr TGrooveJoint{.
+  cdecl, importc: "cpGrooveJointAlloc", dynlib: Lib.}
+#/ Initialize a groove joint.
+proc Init*(joint: PGrooveJoint; a, b: PBody; groove_a, groove_b, anchr2: TVector): PGrooveJoint{.
+  cdecl, importc: "cpGrooveJointInit", dynlib: Lib.}
+#/ Allocate and initialize a groove joint.
+proc newGrooveJoint*(a, b: PBody; groove_a, groove_b, anchr2: TVector): PConstraint{.
+  cdecl, importc: "cpGrooveJointNew", dynlib: Lib.}
+
+defCGetter(GrooveJoint, TVector, grv_a, GrooveA)
+defCGetter(GrooveJoint, TVector, grv_b, GrooveB)
+# /// Set endpoint a of a groove joint's groove
+proc SetGrooveA*(constraint: PConstraint, value: TVector) {.
+  cdecl, importc: "cpGrooveJointSetGrooveA", dynlib: Lib.}
+# /// Set endpoint b of a groove joint's groove
+proc SetGrooveB*(constraint: PConstraint, value: TVector) {.
+  cdecl, importc: "cpGrooveJointSetGrooveB", dynlib: Lib.}
+defCProp(GrooveJoint, TVector, anchr2, Anchr2)
+
+proc DampedSpringGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpDampedSpringGetClass", dynlib: Lib.}
+#/ Allocate a damped spring.
+proc AllocDampedSpring*(): PDampedSpring{.
+  cdecl, importc: "cpDampedSpringAlloc", dynlib: Lib.}
+#/ Initialize a damped spring.
+proc init*(joint: PDampedSpring; a, b: PBody; anchr1, anchr2: TVector;
+            restLength, stiffness, damping: CpFloat): PDampedSpring{.
+  cdecl, importc: "cpDampedSpringInit", dynlib: Lib.}
+#/ Allocate and initialize a damped spring.
+proc newDampedSpring*(a, b: PBody; anchr1, anchr2: TVector; 
+                      restLength, stiffness, damping: CpFloat): PConstraint{.
+  cdecl, importc: "cpDampedSpringNew", dynlib: Lib.}
+
+# CP_DefineConstraintProperty(cpDampedSpring, cpVect, anchr1, Anchr1)
+defCProp(DampedSpring, TVector, anchr1, Anchr1)
+defCProp(DampedSpring, TVector, anchr2, Anchr2)
+defCProp(DampedSpring, CpFloat, restLength, RestLength)
+defCProp(DampedSpring, CpFloat, stiffness, Stiffness)
+defCProp(DampedSpring, CpFloat, damping, Damping)
+defCProp(DampedSpring, TDampedSpringForceFunc, springForceFunc, SpringForceFunc)
+
+
+proc DampedRotarySpringGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpDampedRotarySpringGetClass", dynlib: Lib.}
+
+#/ Allocate a damped rotary spring.
+proc DampedRotarySpringAlloc*(): PDampedRotarySpring{.
+  cdecl, importc: "cpDampedRotarySpringAlloc", dynlib: Lib.}
+#/ Initialize a damped rotary spring.
+proc init*(joint: PDampedRotarySpring; a, b: PBody; 
+            restAngle, stiffness, damping: CpFloat): PDampedRotarySpring{.
+  cdecl, importc: "cpDampedRotarySpringInit", dynlib: Lib.}
+#/ Allocate and initialize a damped rotary spring.
+proc DampedRotarySpringNew*(a, b: PBody; restAngle, stiffness, damping: CpFloat): PConstraint{.
+  cdecl, importc: "cpDampedRotarySpringNew", dynlib: Lib.}
+
+defCProp(DampedRotarySpring, CpFloat, restAngle, RestAngle)
+defCProp(DampedRotarySpring, CpFloat, stiffness, Stiffness)
+defCProp(DampedRotarySpring, CpFloat, damping, Damping)
+defCProp(DampedRotarySpring, TDampedRotarySpringTorqueFunc, springTorqueFunc, SpringTorqueFunc)
+
+
+proc RotaryLimitJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpRotaryLimitJointGetClass", dynlib: Lib.}
+#/ Allocate a damped rotary limit joint.
+proc allocRotaryLimitJoint*(): PRotaryLimitJoint{.
+  cdecl, importc: "cpRotaryLimitJointAlloc", dynlib: Lib.}
+#/ Initialize a damped rotary limit joint.
+proc init*(joint: PRotaryLimitJoint; a, b: PBody; min, max: CpFloat): PRotaryLimitJoint{.
+  cdecl, importc: "cpRotaryLimitJointInit", dynlib: Lib.}
+#/ Allocate and initialize a damped rotary limit joint.
+proc newRotaryLimitJoint*(a, b: PBody; min, max: CpFloat): PConstraint{.
+  cdecl, importc: "cpRotaryLimitJointNew", dynlib: Lib.}
+
+defCProp(RotaryLimitJoint, CpFloat, min, Min)
+defCProp(RotaryLimitJoint, CpFloat, max, Max)
+
+
+proc RatchetJointGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpRatchetJointGetClass", dynlib: Lib.}
+#/ Allocate a ratchet joint.
+proc AllocRatchetJoint*(): PRatchetJoint{.
+  cdecl, importc: "cpRatchetJointAlloc", dynlib: Lib.}
+#/ Initialize a ratched joint.
+proc init*(joint: PRatchetJoint; a, b: PBody; phase, ratchet: CpFloat): PRatchetJoint{.
+  cdecl, importc: "cpRatchetJointInit", dynlib: Lib.}
+#/ Allocate and initialize a ratchet joint.
+proc NewRatchetJoint*(a, b: PBody; phase, ratchet: CpFloat): PConstraint{.
+  cdecl, importc: "cpRatchetJointNew", dynlib: Lib.}
+
+defCProp(RatchetJoint, CpFloat, angle, Angle)
+defCProp(RatchetJoint, CpFloat, phase, Phase)
+defCProp(RatchetJoint, CpFloat, ratchet, Ratchet)
+
+
+proc GearJointGetClass*(): PConstraintClass{.cdecl, 
+    importc: "cpGearJointGetClass", dynlib: Lib.}
+#/ Allocate a gear joint.
+proc AllocGearJoint*(): PGearJoint{.
+  cdecl, importc: "cpGearJointAlloc", dynlib: Lib.}
+#/ Initialize a gear joint.
+proc init*(joint: PGearJoint; a, b: PBody, phase, ratio: CpFloat): PGearJoint{.
+  cdecl, importc: "cpGearJointInit", dynlib: Lib.}
+#/ Allocate and initialize a gear joint.
+proc NewGearJoint*(a, b: PBody; phase, ratio: CpFloat): PConstraint{.
+  cdecl, importc: "cpGearJointNew", dynlib: Lib.}
+
+defCProp(GearJoint, CpFloat, phase, Phase)
+defCGetter(GearJoint, CpFloat, ratio, Ratio)
+#/ Set the ratio of a gear joint.
+proc GearJointSetRatio*(constraint: PConstraint; value: CpFloat){.
+  cdecl, importc: "cpGearJointSetRatio", dynlib: Lib.}
+
+
+proc SimpleMotorGetClass*(): PConstraintClass{.
+  cdecl, importc: "cpSimpleMotorGetClass", dynlib: Lib.}
+#/ Allocate a simple motor.
+proc AllocSimpleMotor*(): PSimpleMotor{.
+  cdecl, importc: "cpSimpleMotorAlloc", dynlib: Lib.}
+#/ initialize a simple motor.
+proc init*(joint: PSimpleMotor; a, b: PBody; 
+                      rate: CpFloat): PSimpleMotor{.
+  cdecl, importc: "cpSimpleMotorInit", dynlib: Lib.}
+#/ Allocate and initialize a simple motor.
+proc newSimpleMotor*(a, b: PBody; rate: CpFloat): PConstraint{.
+  cdecl, importc: "cpSimpleMotorNew", dynlib: Lib.}
+
+defCProp(SimpleMotor, CpFloat, rate, Rate)
+
+
+
diff --git a/tests/manyloc/keineschweine/dependencies/enet/enet.nim b/tests/manyloc/keineschweine/dependencies/enet/enet.nim
new file mode 100644
index 000000000..ad43c69b7
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/enet/enet.nim
@@ -0,0 +1,614 @@
+discard """Copyright (c) 2002-2012 Lee Salzman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of 
+this software and associated documentation files (the "Software"), to deal in 
+the Software without restriction, including without limitation the rights to 
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all 
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+"""
+when defined(Linux):
+  const Lib = "libenet.so.1(|.0.3)"
+else:
+  {.error: "Your platform has not been accounted for."}
+{.deadCodeElim: ON.}
+const 
+  ENET_VERSION_MAJOR* = 1
+  ENET_VERSION_MINOR* = 3
+  ENET_VERSION_PATCH* = 3
+template ENET_VERSION_CREATE(major, minor, patch: expr): expr = 
+  (((major) shl 16) or ((minor) shl 8) or (patch))
+
+const 
+  ENET_VERSION* = ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, 
+                                      ENET_VERSION_PATCH)
+type 
+  TVersion* = cuint
+  TSocketType*{.size: sizeof(cint).} = enum 
+    ENET_SOCKET_TYPE_STREAM = 1, ENET_SOCKET_TYPE_DATAGRAM = 2
+  TSocketWait*{.size: sizeof(cint).} = enum 
+    ENET_SOCKET_WAIT_NONE = 0, ENET_SOCKET_WAIT_SEND = (1 shl 0), 
+    ENET_SOCKET_WAIT_RECEIVE = (1 shl 1)
+  TSocketOption*{.size: sizeof(cint).} = enum 
+    ENET_SOCKOPT_NONBLOCK = 1, ENET_SOCKOPT_BROADCAST = 2, 
+    ENET_SOCKOPT_RCVBUF = 3, ENET_SOCKOPT_SNDBUF = 4, 
+    ENET_SOCKOPT_REUSEADDR = 5
+const 
+  ENET_HOST_ANY* = 0
+  ENET_HOST_BROADCAST* = 0xFFFFFFFF
+  ENET_PORT_ANY* = 0
+  
+  ENET_PROTOCOL_MINIMUM_MTU* = 576
+  ENET_PROTOCOL_MAXIMUM_MTU* = 4096
+  ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS* = 32
+  ENET_PROTOCOL_MINIMUM_WINDOW_SIZE* = 4096
+  ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE* = 32768
+  ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT* = 1
+  ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT* = 255
+  ENET_PROTOCOL_MAXIMUM_PEER_ID* = 0x00000FFF
+type
+  PAddress* = ptr TAddress
+  TAddress*{.pure, final.} = object 
+    host*: cuint
+    port*: cushort
+  
+  TPacketFlag*{.size: sizeof(cint).} = enum 
+    FlagReliable = (1 shl 0), 
+    FlagUnsequenced = (1 shl 1), 
+    NoAllocate = (1 shl 2), 
+    UnreliableFragment = (1 shl 3)
+  
+  TENetListNode*{.pure, final.} = object 
+      next*: ptr T_ENetListNode
+      previous*: ptr T_ENetListNode
+
+  PENetListIterator* = ptr TENetListNode
+  TENetList*{.pure, final.} = object 
+    sentinel*: TENetListNode
+  
+  T_ENetPacket*{.pure, final.} = object 
+  TPacketFreeCallback* = proc (a2: ptr T_ENetPacket){.cdecl.}
+  
+  PPacket* = ptr TPacket
+  TPacket*{.pure, final.} = object 
+    referenceCount: csize
+    flags*: cint
+    data*: cstring#ptr cuchar
+    dataLength*: csize
+    freeCallback*: TPacketFreeCallback
+
+  PAcknowledgement* = ptr TAcknowledgement
+  TAcknowledgement*{.pure, final.} = object 
+    acknowledgementList*: TEnetListNode
+    sentTime*: cuint
+    command*: TEnetProtocol
+
+  POutgoingCommand* = ptr TOutgoingCommand
+  TOutgoingCommand*{.pure, final.} = object 
+    outgoingCommandList*: TEnetListNode
+    reliableSequenceNumber*: cushort
+    unreliableSequenceNumber*: cushort
+    sentTime*: cuint
+    roundTripTimeout*: cuint
+    roundTripTimeoutLimit*: cuint
+    fragmentOffset*: cuint
+    fragmentLength*: cushort
+    sendAttempts*: cushort
+    command*: TEnetProtocol
+    packet*: PPacket
+
+  PIncomingCommand* = ptr TIncomingCommand
+  TIncomingCommand*{.pure, final.} = object 
+    incomingCommandList*: TEnetListNode
+    reliableSequenceNumber*: cushort
+    unreliableSequenceNumber*: cushort
+    command*: TEnetProtocol
+    fragmentCount*: cuint
+    fragmentsRemaining*: cuint
+    fragments*: ptr cuint
+    packet*: ptr TPacket
+
+  TPeerState*{.size: sizeof(cint).} = enum 
+    ENET_PEER_STATE_DISCONNECTED = 0, ENET_PEER_STATE_CONNECTING = 1, 
+    ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, 
+    ENET_PEER_STATE_CONNECTION_PENDING = 3, 
+    ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, ENET_PEER_STATE_CONNECTED = 5, 
+    ENET_PEER_STATE_DISCONNECT_LATER = 6, ENET_PEER_STATE_DISCONNECTING = 7, 
+    ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, ENET_PEER_STATE_ZOMBIE = 9
+  
+  TENetProtocolCommand*{.size: sizeof(cint).} = enum 
+    ENET_PROTOCOL_COMMAND_NONE = 0, ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, 
+    ENET_PROTOCOL_COMMAND_CONNECT = 2, 
+    ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, 
+    ENET_PROTOCOL_COMMAND_DISCONNECT = 4, ENET_PROTOCOL_COMMAND_PING = 5, 
+    ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, 
+    ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, 
+    ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, 
+    ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, 
+    ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, 
+    ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, 
+    ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, 
+    ENET_PROTOCOL_COMMAND_COUNT = 13, ENET_PROTOCOL_COMMAND_MASK = 0x0000000F
+  TENetProtocolFlag*{.size: sizeof(cint).} = enum 
+    ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12,
+    ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 shl 6), 
+    ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 shl 7), 
+    ENET_PROTOCOL_HEADER_SESSION_MASK = (3 shl 12), 
+    ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 shl 14), 
+    ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 shl 15),
+    ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED.cint or
+        ENET_PROTOCOL_HEADER_FLAG_SENT_TIME.cint
+  
+  TENetProtocolHeader*{.pure, final.} = object 
+    peerID*: cushort
+    sentTime*: cushort
+
+  TENetProtocolCommandHeader*{.pure, final.} = object 
+    command*: cuchar
+    channelID*: cuchar
+    reliableSequenceNumber*: cushort
+
+  TENetProtocolAcknowledge*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    receivedReliableSequenceNumber*: cushort
+    receivedSentTime*: cushort
+
+  TENetProtocolConnect*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    outgoingPeerID*: cushort
+    incomingSessionID*: cuchar
+    outgoingSessionID*: cuchar
+    mtu*: cuint
+    windowSize*: cuint
+    channelCount*: cuint
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+    packetThrottleInterval*: cuint
+    packetThrottleAcceleration*: cuint
+    packetThrottleDeceleration*: cuint
+    connectID*: cuint
+    data*: cuint
+
+  TENetProtocolVerifyConnect*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    outgoingPeerID*: cushort
+    incomingSessionID*: cuchar
+    outgoingSessionID*: cuchar
+    mtu*: cuint
+    windowSize*: cuint
+    channelCount*: cuint
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+    packetThrottleInterval*: cuint
+    packetThrottleAcceleration*: cuint
+    packetThrottleDeceleration*: cuint
+    connectID*: cuint
+
+  TENetProtocolBandwidthLimit*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+
+  TENetProtocolThrottleConfigure*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    packetThrottleInterval*: cuint
+    packetThrottleAcceleration*: cuint
+    packetThrottleDeceleration*: cuint
+
+  TENetProtocolDisconnect*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    data*: cuint
+
+  TENetProtocolPing*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+
+  TENetProtocolSendReliable*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    dataLength*: cushort
+
+  TENetProtocolSendUnreliable*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    unreliableSequenceNumber*: cushort
+    dataLength*: cushort
+
+  TENetProtocolSendUnsequenced*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    unsequencedGroup*: cushort
+    dataLength*: cushort
+
+  TENetProtocolSendFragment*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+    startSequenceNumber*: cushort
+    dataLength*: cushort
+    fragmentCount*: cuint
+    fragmentNumber*: cuint
+    totalLength*: cuint
+    fragmentOffset*: cuint
+  
+  ## this is incomplete; need helper templates or something
+  ## ENetProtocol
+  TENetProtocol*{.pure, final.} = object 
+    header*: TENetProtocolCommandHeader
+const 
+  ENET_BUFFER_MAXIMUM* = (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS)
+  ENET_HOST_RECEIVE_BUFFER_SIZE          = 256 * 1024
+  ENET_HOST_SEND_BUFFER_SIZE             = 256 * 1024
+  ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL  = 1000
+  ENET_HOST_DEFAULT_MTU                  = 1400
+
+  ENET_PEER_DEFAULT_ROUND_TRIP_TIME      = 500
+  ENET_PEER_DEFAULT_PACKET_THROTTLE      = 32
+  ENET_PEER_PACKET_THROTTLE_SCALE        = 32
+  ENET_PEER_PACKET_THROTTLE_COUNTER      = 7
+  ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2
+  ENET_PEER_PACKET_THROTTLE_DECELERATION = 2
+  ENET_PEER_PACKET_THROTTLE_INTERVAL     = 5000
+  ENET_PEER_PACKET_LOSS_SCALE            = (1 shl 16)
+  ENET_PEER_PACKET_LOSS_INTERVAL         = 10000
+  ENET_PEER_WINDOW_SIZE_SCALE            = 64 * 1024
+  ENET_PEER_TIMEOUT_LIMIT                = 32
+  ENET_PEER_TIMEOUT_MINIMUM              = 5000
+  ENET_PEER_TIMEOUT_MAXIMUM              = 30000
+  ENET_PEER_PING_INTERVAL                = 500
+  ENET_PEER_UNSEQUENCED_WINDOWS          = 64
+  ENET_PEER_UNSEQUENCED_WINDOW_SIZE      = 1024
+  ENET_PEER_FREE_UNSEQUENCED_WINDOWS     = 32
+  ENET_PEER_RELIABLE_WINDOWS             = 16
+  ENET_PEER_RELIABLE_WINDOW_SIZE         = 0x1000
+  ENET_PEER_FREE_RELIABLE_WINDOWS        = 8
+
+when defined(Linux):
+  import posix
+  const
+    ENET_SOCKET_NULL*: cint = -1
+  type 
+    TENetSocket* = cint
+    PEnetBuffer* = ptr object
+    TENetBuffer*{.pure, final.} = object 
+      data*: pointer
+      dataLength*: csize
+    TENetSocketSet* = Tfd_set
+  ## see if these are different on win32, if not then get rid of these
+  template ENET_HOST_TO_NET_16*(value: expr): expr = 
+    (htons(value))
+  template ENET_HOST_TO_NET_32*(value: expr): expr = 
+    (htonl(value))
+  template ENET_NET_TO_HOST_16*(value: expr): expr = 
+    (ntohs(value))
+  template ENET_NET_TO_HOST_32*(value: expr): expr = 
+    (ntohl(value))
+
+  template ENET_SOCKETSET_EMPTY*(sockset: expr): expr = 
+    FD_ZERO(addr((sockset)))
+  template ENET_SOCKETSET_ADD*(sockset, socket: expr): expr = 
+    FD_SET(socket, addr((sockset)))
+  template ENET_SOCKETSET_REMOVE*(sockset, socket: expr): expr = 
+    FD_CLEAR(socket, addr((sockset)))
+  template ENET_SOCKETSET_CHECK*(sockset, socket: expr): expr = 
+    FD_ISSET(socket, addr((sockset)))
+
+when defined(Windows):
+  ## put the content of win32.h in here
+
+
+type 
+  PChannel* = ptr TChannel
+  TChannel*{.pure, final.} = object 
+    outgoingReliableSequenceNumber*: cushort
+    outgoingUnreliableSequenceNumber*: cushort
+    usedReliableWindows*: cushort
+    reliableWindows*: array[0..ENET_PEER_RELIABLE_WINDOWS - 1, cushort]
+    incomingReliableSequenceNumber*: cushort
+    incomingUnreliableSequenceNumber*: cushort
+    incomingReliableCommands*: TENetList
+    incomingUnreliableCommands*: TENetList
+
+  PPeer* = ptr TPeer
+  TPeer*{.pure, final.} = object 
+    dispatchList*: TEnetListNode
+    host*: ptr THost
+    outgoingPeerID*: cushort
+    incomingPeerID*: cushort
+    connectID*: cuint
+    outgoingSessionID*: cuchar
+    incomingSessionID*: cuchar
+    address*: TAddress
+    data*: pointer
+    state*: TPeerState
+    channels*: PChannel
+    channelCount*: csize
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+    incomingBandwidthThrottleEpoch*: cuint
+    outgoingBandwidthThrottleEpoch*: cuint
+    incomingDataTotal*: cuint
+    outgoingDataTotal*: cuint
+    lastSendTime*: cuint
+    lastReceiveTime*: cuint
+    nextTimeout*: cuint
+    earliestTimeout*: cuint
+    packetLossEpoch*: cuint
+    packetsSent*: cuint
+    packetsLost*: cuint
+    packetLoss*: cuint
+    packetLossVariance*: cuint
+    packetThrottle*: cuint
+    packetThrottleLimit*: cuint
+    packetThrottleCounter*: cuint
+    packetThrottleEpoch*: cuint
+    packetThrottleAcceleration*: cuint
+    packetThrottleDeceleration*: cuint
+    packetThrottleInterval*: cuint
+    lastRoundTripTime*: cuint
+    lowestRoundTripTime*: cuint
+    lastRoundTripTimeVariance*: cuint
+    highestRoundTripTimeVariance*: cuint
+    roundTripTime*: cuint
+    roundTripTimeVariance*: cuint
+    mtu*: cuint
+    windowSize*: cuint
+    reliableDataInTransit*: cuint
+    outgoingReliableSequenceNumber*: cushort
+    acknowledgements*: TENetList
+    sentReliableCommands*: TENetList
+    sentUnreliableCommands*: TENetList
+    outgoingReliableCommands*: TENetList
+    outgoingUnreliableCommands*: TENetList
+    dispatchedCommands*: TENetList
+    needsDispatch*: cint
+    incomingUnsequencedGroup*: cushort
+    outgoingUnsequencedGroup*: cushort
+    unsequencedWindow*: array[0..ENET_PEER_UNSEQUENCED_WINDOW_SIZE div 32 - 1, 
+                              cuint]
+    eventData*: cuint
+
+  PCompressor* = ptr TCompressor
+  TCompressor*{.pure, final.} = object 
+    context*: pointer
+    compress*: proc (context: pointer; inBuffers: ptr TEnetBuffer; 
+                     inBufferCount: csize; inLimit: csize; 
+                     outData: ptr cuchar; outLimit: csize): csize{.cdecl.}
+    decompress*: proc (context: pointer; inData: ptr cuchar; inLimit: csize; 
+                       outData: ptr cuchar; outLimit: csize): csize{.cdecl.}
+    destroy*: proc (context: pointer){.cdecl.}
+
+  TChecksumCallback* = proc (buffers: ptr TEnetBuffer; bufferCount: csize): cuint{.
+      cdecl.}
+  
+  PHost* = ptr THost
+  THost*{.pure, final.} = object 
+    socket*: TEnetSocket
+    address*: TAddress
+    incomingBandwidth*: cuint
+    outgoingBandwidth*: cuint
+    bandwidthThrottleEpoch*: cuint
+    mtu*: cuint
+    randomSeed*: cuint
+    recalculateBandwidthLimits*: cint
+    peers*: ptr TPeer
+    peerCount*: csize
+    channelLimit*: csize
+    serviceTime*: cuint
+    dispatchQueue*: TEnetList
+    continueSending*: cint
+    packetSize*: csize
+    headerFlags*: cushort
+    commands*: array[0..ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS - 1, 
+                     TEnetProtocol]
+    commandCount*: csize
+    buffers*: array[0..ENET_BUFFER_MAXIMUM - 1, TEnetBuffer]
+    bufferCount*: csize
+    checksum*: TChecksumCallback
+    compressor*: TCompressor
+    packetData*: array[0..ENET_PROTOCOL_MAXIMUM_MTU - 1, 
+                       array[0..2 - 1, cuchar]]
+    receivedAddress*: TAddress
+    receivedData*: ptr cuchar
+    receivedDataLength*: csize
+    totalSentData*: cuint
+    totalSentPackets*: cuint
+    totalReceivedData*: cuint
+    totalReceivedPackets*: cuint
+  
+  TEventType*{.size: sizeof(cint).} = enum 
+    EvtNone = 0, EvtConnect = 1, 
+    EvtDisconnect = 2, EvtReceive = 3
+  PEvent* = ptr TEvent
+  TEvent*{.pure, final.} = object 
+    kind*: TEventType
+    peer*: ptr TPeer
+    channelID*: cuchar
+    data*: cuint
+    packet*: ptr TPacket
+
+  TENetCallbacks*{.pure, final.} = object 
+    malloc*: proc (size: csize): pointer{.cdecl.}
+    free*: proc (memory: pointer){.cdecl.}
+    no_memory*: proc (){.cdecl.}
+
+{.push callConv:cdecl.}
+proc enet_malloc*(a2: csize): pointer{.
+  importc: "enet_malloc", dynlib: Lib.}
+proc enet_free*(a2: pointer){.
+  importc: "enet_free", dynlib: Lib.}
+
+proc enetInit*(): cint{.
+  importc: "enet_initialize", dynlib: Lib.}
+proc enetInit*(version: TVersion; inits: ptr TENetCallbacks): cint{.
+  importc: "enet_initialize_with_callbacks", dynlib: Lib.}
+proc enetDeinit*(){.
+  importc: "enet_deinitialize", dynlib: Lib.}
+proc enet_time_get*(): cuint{.
+  importc: "enet_time_get", dynlib: Lib.}
+proc enet_time_set*(a2: cuint){.
+  importc: "enet_time_set", dynlib: Lib.}
+
+#enet docs are pretty lacking, i'm not sure what the names of these arguments should be
+proc createSocket*(kind: TSocketType): TEnetSocket{.
+  importc: "enet_socket_create", dynlib: Lib.}
+proc bindTo*(socket: TEnetSocket; address: var TAddress): cint{.
+  importc: "enet_socket_bind", dynlib: Lib.}
+proc bindTo*(socket: TEnetSocket; address: ptr TAddress): cint{.
+  importc: "enet_socket_bind", dynlib: Lib.}
+proc listen*(socket: TEnetSocket; a3: cint): cint{.
+  importc: "enet_socket_listen", dynlib: Lib.}
+proc accept*(socket: TEnetSocket; address: var TAddress): TEnetSocket{.
+  importc: "enet_socket_accept", dynlib: Lib.}
+proc accept*(socket: TEnetSocket; address: ptr TAddress): TEnetSocket{.
+  importc: "enet_socket_accept", dynlib: Lib.}
+proc connect*(socket: TEnetSocket; address: var TAddress): cint{.
+  importc: "enet_socket_connect", dynlib: Lib.}
+proc connect*(socket: TEnetSocket; address: ptr TAddress): cint{.
+  importc: "enet_socket_connect", dynlib: Lib.}
+proc send*(socket: TEnetSocket; address: var TAddress; buffer: ptr TEnetBuffer; size: csize): cint{.
+  importc: "enet_socket_send", dynlib: Lib.}
+proc send*(socket: TEnetSocket; address: ptr TAddress; buffer: ptr TEnetBuffer; size: csize): cint{.
+  importc: "enet_socket_send", dynlib: Lib.}
+proc receive*(socket: TEnetSocket; address: var TAddress; 
+               buffer: ptr TEnetBuffer; size: csize): cint{.
+  importc: "enet_socket_receive", dynlib: Lib.}
+proc receive*(socket: TEnetSocket; address: ptr TAddress; 
+               buffer: ptr TEnetBuffer; size: csize): cint{.
+  importc: "enet_socket_receive", dynlib: Lib.}
+proc wait*(socket: TEnetSocket; a3: ptr cuint; a4: cuint): cint{.
+  importc: "enet_socket_wait", dynlib: Lib.}
+proc setOption*(socket: TEnetSocket; a3: TSocketOption; a4: cint): cint{.
+  importc: "enet_socket_set_option", dynlib: Lib.}
+proc destroy*(socket: TEnetSocket){.
+  importc: "enet_socket_destroy", dynlib: Lib.}
+proc select*(socket: TEnetSocket; a3: ptr TENetSocketSet; 
+              a4: ptr TENetSocketSet; a5: cuint): cint{.
+  importc: "enet_socketset_select", dynlib: Lib.}
+
+proc setHost*(address: PAddress; hostName: cstring): cint{.
+  importc: "enet_address_set_host", dynlib: Lib.}
+proc setHost*(address: var TAddress; hostName: cstring): cint{.
+  importc: "enet_address_set_host", dynlib: Lib.}
+proc getHostIP*(address: var TAddress; hostName: cstring; nameLength: csize): cint{.
+  importc: "enet_address_get_host_ip", dynlib: Lib.}
+proc getHost*(address: var TAddress; hostName: cstring; nameLength: csize): cint{.
+  importc: "enet_address_get_host", dynlib: Lib.}
+
+## Call the above two funcs but trim the result string
+proc getHostIP*(address: var TAddress; hostName: var string; nameLength: csize): cint{.inline.} =
+  hostName.setLen nameLength
+  result = getHostIP(address, cstring(hostName), nameLength)
+  if result == 0:
+    hostName.setLen(len(cstring(hostName)))
+proc getHost*(address: var TAddress; hostName: var string; nameLength: csize): cint{.inline.} =
+  hostName.setLen nameLength
+  result = getHost(address, cstring(hostName), nameLength)
+  if result == 0:
+    hostName.setLen(len(cstring(hostName)))
+
+proc createPacket*(data: pointer; len: csize; flag: TPacketFlag): PPacket{.
+  importc: "enet_packet_create", dynlib: Lib.}
+proc destroy*(packet: PPacket){.
+  importc: "enet_packet_destroy", dynlib: Lib.}
+proc resize*(packet: PPacket; dataLength: csize): cint{.
+  importc: "enet_packet_resize", dynlib: Lib.}
+
+proc crc32*(buffers: ptr TEnetBuffer; bufferCount: csize): cuint{.
+  importc: "enet_crc32", dynlib: Lib.}
+
+proc createHost*(address: ptr TAddress; maxConnections, maxChannels: csize; downSpeed, upSpeed: cuint): PHost{.
+  importc: "enet_host_create", dynlib: Lib.}
+proc createHost*(address: var TAddress; maxConnections, maxChannels: csize; downSpeed, upSpeed: cuint): PHost{.
+  importc: "enet_host_create", dynlib: Lib.}
+proc destroy*(host: PHost){.
+  importc: "enet_host_destroy", dynlib: Lib.}
+proc connect*(host: PHost; address: ptr TAddress; channelCount: csize; data: cuint): PPeer{.
+  importc: "enet_host_connect", dynlib: Lib.}
+proc connect*(host: PHost; address: var TAddress; channelCount: csize; data: cuint): PPeer{.
+  importc: "enet_host_connect", dynlib: Lib.}
+
+proc checkEvents*(host: PHost; event: var TEvent): cint{.
+  importc: "enet_host_check_events", dynlib: Lib.}
+proc checkEvents*(host: PHost; event: ptr TEvent): cint{.
+  importc: "enet_host_check_events", dynlib: Lib.}
+proc hostService*(host: PHost; event: var TEvent; timeout: cuint): cint{.
+  importc: "enet_host_service", dynlib: Lib.}
+proc hostService*(host: PHost; event: ptr TEvent; timeout: cuint): cint{.
+  importc: "enet_host_service", dynlib: Lib.}
+proc flush*(host: PHost){.
+  importc: "enet_host_flush", dynlib: Lib.}
+proc broadcast*(host: PHost; channelID: cuchar; packet: PPacket){.
+  importc: "enet_host_broadcast", dynlib: Lib.}
+proc compress*(host: PHost; compressor: PCompressor){.
+  importc: "enet_host_compress", dynlib: Lib.}
+proc compressWithRangeCoder*(host: PHost): cint{.
+  importc: "enet_host_compress_with_range_coder", dynlib: Lib.}
+proc channelLimit*(host: PHost; channelLimit: csize){.
+  importc: "enet_host_channel_limit", dynlib: Lib.}
+proc bandwidthLimit*(host: PHost; incoming, outgoing: cuint){.
+  importc: "enet_host_bandwidth_limit", dynlib: Lib.}
+proc bandwidthThrottle*(host: PHost){.
+  importc: "enet_host_bandwidth_throttle", dynlib: Lib.}
+
+
+proc send*(peer: PPeer; channel: cuchar; packet: PPacket): cint{.
+  importc: "enet_peer_send", dynlib: Lib.}
+proc receive*(peer: PPeer; channelID: ptr cuchar): PPacket{.
+  importc: "enet_peer_receive", dynlib: Lib.}
+proc ping*(peer: PPeer){.
+  importc: "enet_peer_ping", dynlib: Lib.}
+proc reset*(peer: PPeer){.
+  importc: "enet_peer_reset", dynlib: Lib.}
+proc disconnect*(peer: PPeer; a3: cuint){.
+  importc: "enet_peer_disconnect", dynlib: Lib.}
+proc disconnectNow*(peer: PPeer; a3: cuint){.
+  importc: "enet_peer_disconnect_now", dynlib: Lib.}
+proc disconnectLater*(peer: PPeer; a3: cuint){.
+  importc: "enet_peer_disconnect_later", dynlib: Lib.}
+proc throttleConfigure*(peer: PPeer; interval, acceleration, deceleration: cuint){.
+  importc: "enet_peer_throttle_configure", dynlib: Lib.}
+proc throttle*(peer: PPeer; rtt: cuint): cint{.
+  importc: "enet_peer_throttle", dynlib: Lib.}
+proc resetQueues*(peer: PPeer){.
+  importc: "enet_peer_reset_queues", dynlib: Lib.}
+proc setupOutgoingCommand*(peer: PPeer; outgoingCommand: POutgoingCommand){.
+  importc: "enet_peer_setup_outgoing_command", dynlib: Lib.}
+
+proc queueOutgoingCommand*(peer: PPeer; command: ptr TEnetProtocol; 
+          packet: PPacket; offset: cuint; length: cushort): POutgoingCommand{.
+  importc: "enet_peer_queue_outgoing_command", dynlib: Lib.}
+proc queueIncomingCommand*(peer: PPeer; command: ptr TEnetProtocol; 
+                    packet: PPacket; fragmentCount: cuint): PIncomingCommand{.
+  importc: "enet_peer_queue_incoming_command", dynlib: Lib.}
+proc queueAcknowledgement*(peer: PPeer; command: ptr TEnetProtocol; 
+                            sentTime: cushort): PAcknowledgement{.
+  importc: "enet_peer_queue_acknowledgement", dynlib: Lib.}
+proc dispatchIncomingUnreliableCommands*(peer: PPeer; channel: PChannel){.
+  importc: "enet_peer_dispatch_incoming_unreliable_commands", dynlib: Lib.}
+proc dispatchIncomingReliableCommands*(peer: PPeer; channel: PChannel){.
+  importc: "enet_peer_dispatch_incoming_reliable_commands", dynlib: Lib.}
+
+proc createRangeCoder*(): pointer{.
+  importc: "enet_range_coder_create", dynlib: Lib.}
+proc rangeCoderDestroy*(context: pointer){.
+  importc: "enet_range_coder_destroy", dynlib: Lib.}
+proc rangeCoderCompress*(context: pointer; inBuffers: PEnetBuffer; inLimit, 
+               bufferCount: csize; outData: cstring; outLimit: csize): csize{.
+  importc: "enet_range_coder_compress", dynlib: Lib.}
+proc rangeCoderDecompress*(context: pointer; inData: cstring; inLimit: csize; 
+                            outData: cstring; outLimit: csize): csize{.
+  importc: "enet_range_coder_decompress", dynlib: Lib.}
+proc protocolCommandSize*(commandNumber: cuchar): csize{.
+  importc: "enet_protocol_command_size", dynlib: Lib.}
+
+{.pop.}
+
+from hashes import `!$`, `!&`, THash, hash
+proc hash*(x: TAddress): THash {.nimcall, noSideEffect.} =
+  result = !$(hash(x.host.int32) !& hash(x.port.int16))
+
diff --git a/tests/manyloc/keineschweine/dependencies/enet/testclient.nim b/tests/manyloc/keineschweine/dependencies/enet/testclient.nim
new file mode 100644
index 000000000..2447a1fb5
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/enet/testclient.nim
@@ -0,0 +1,49 @@
+import enet, strutils
+
+if enetInit() != 0:
+  quit "Could not initialize ENet"
+var
+  address: enet.TAddress
+  event: TEvent
+  peer: PPeer
+  client: PHost
+
+client = createHost(nil, 1, 2, 0, 0)
+if client == nil:
+  quit "Could not create client!"
+
+if setHost(addr address, "localhost") != 0:
+  quit "Could not set host"
+address.port = 8024
+
+peer = client.connect(addr address, 2, 0)
+if peer == nil:
+  quit "No available peers"
+
+block:
+  var bConnected = false
+  while not bConnected:
+    if client.hostService(event, 5000) > 0 and event.kind == EvtConnect:
+      echo "Connected"
+      bConnected = true
+    else:
+      echo "Connection failed"
+      quit 0
+
+var runServer = true
+while client.hostService(event, 1000) >= 0 and runServer:
+  case event.kind
+  of EvtReceive:
+    echo "Recvd ($1) $2 ".format(
+      event.packet.dataLength,
+      event.packet.data)
+  of EvtDisconnect:
+    echo "Disconnected"
+    event.peer.data = nil
+    runServer = false
+  of EvtNone: discard
+  else:
+    echo repr(event)
+
+
+client.destroy()
diff --git a/tests/manyloc/keineschweine/dependencies/enet/testserver.nim b/tests/manyloc/keineschweine/dependencies/enet/testserver.nim
new file mode 100644
index 000000000..28a6bd1f7
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/enet/testserver.nim
@@ -0,0 +1,45 @@
+import enet, strutils
+var
+  address: enet.TAddress
+  server: PHost
+  event: TEvent
+
+if enetInit() != 0:
+  quit "Could not initialize ENet"
+
+address.host = EnetHostAny
+address.port = 8024
+
+server = enet.createHost(
+  addr address, 32, 2,  0,  0)
+if server == nil:
+  quit "Could not create the server!"
+
+while server.hostService(addr event, 2500) >= 0:
+  case event.kind
+  of EvtConnect:
+    echo "New client from $1:$2".format(event.peer.address.host, event.peer.address.port)
+    
+    var
+      msg = "hello" 
+      resp = createPacket(cstring(msg), msg.len + 1, FlagReliable)
+      
+    if event.peer.send(0.cuchar, resp) < 0:
+      echo "FAILED"
+    else:
+      echo "Replied"
+  of EvtReceive:
+    echo "Recvd ($1) $2 ".format(
+      event.packet.dataLength,
+      event.packet.data)
+    
+    destroy(event.packet)
+    
+  of EvtDisconnect:
+    echo "Disconnected"
+    event.peer.data = nil
+  else:
+    discard
+
+server.destroy()
+enetDeinit()
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim
new file mode 100644
index 000000000..ae9dfb39f
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket.nim
@@ -0,0 +1,295 @@
+import macros, macro_dsl, streams, streams_enh
+from strutils import format
+
+template newLenName(): stmt {.immediate.} =
+  let lenName {.inject.} = ^("len"& $lenNames)
+  inc(lenNames)
+
+template defPacketImports*(): stmt {.immediate, dirty.} =
+  import macros, macro_dsl, streams, streams_enh
+  from strutils import format
+
+proc `$`*[T](x: seq[T]): string =
+  result = "[seq len="
+  result.add($x.len)
+  result.add ':'
+  for i in 0.. <len(x):
+    result.add "   "
+    result.add($x[i])
+  result.add ']'
+
+macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} = 
+  result = newNimNode(nnkStmtList)
+  let 
+    typeName = quoted2ident(typeNameN)
+    packetID = ^"p"
+    streamID = ^"s"
+  var
+    constructorParams = newNimNode(nnkFormalParams).und(typeName)
+    constructor = newNimNode(nnkProcDef).und(
+      postfix(^("new"& $typeName.ident), "*"),
+      emptyNode(),
+      emptyNode(),
+      constructorParams,
+      emptyNode(),
+      emptyNode())
+    pack = newNimNode(nnkProcDef).und(
+      postfix(^"pack", "*"),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        emptyNode(),   # : void
+        newNimNode(nnkIdentDefs).und(
+          packetID,    # p: var typeName
+          newNimNode(nnkVarTy).und(typeName),
+          emptyNode()),
+        newNimNode(nnkIdentDefs).und(
+          streamID,    # s: PStream
+          ^"PStream",
+          newNimNode(nnkNilLit))),
+      emptyNode(),
+      emptyNode())
+    read = newNimNode(nnkProcDef).und(
+      newIdentNode("read"& $typeName.ident).postfix("*"),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        typeName,   #result type
+        newNimNode(nnkIdentDefs).und(
+          streamID, # s: PStream = nil
+          ^"PStream",
+          newNimNode(nnkNilLit))),
+      emptyNode(),
+      emptyNode())
+    constructorBody = newNimNode(nnkStmtList)
+    packBody = newNimNode(nnkStmtList)
+    readBody = newNimNode(nnkStmtList)
+    lenNames = 0
+  for i in 0.. typeFields.len - 1:
+    let 
+      name = typeFields[i][0]
+      dotName = packetID.dot(name)
+      resName = newIdentNode(!"result").dot(name)
+    case typeFields[i][1].kind
+    of nnkBracketExpr: #ex: paddedstring[32, '\0'], array[range, type]
+      case $typeFields[i][1][0].ident
+      of "paddedstring":
+        let length = typeFields[i][1][1]
+        let padChar = typeFields[i][1][2]
+        packBody.add(newCall(
+          "writePaddedStr", streamID, dotName, length, padChar))
+        ## result.name = readPaddedStr(s, length, char)
+        readBody.add(resName := newCall(
+          "readPaddedStr", streamID, length, padChar))
+        ## make the type a string
+        typeFields[i] = newNimNode(nnkIdentDefs).und(
+          name,
+          ^"string",
+          newNimNode(nnkEmpty))
+      of "array":
+        readBody.add(
+          newNimNode(nnkDiscardStmt).und(
+            newCall("readData", streamID, newNimNode(nnkAddr).und(resName), newCall("sizeof", resName))))
+        packBody.add(
+          newCall("writeData", streamID, newNimNode(nnkAddr).und(dotName), newCall("sizeof", dotName))) 
+      of "seq":
+        ## let lenX = readInt16(s)
+        newLenName()
+        let 
+          item = ^"item"  ## item name in our iterators
+          seqType = typeFields[i][1][1] ## type of seq
+          readName = newIdentNode("read"& $seqType.ident)
+        readBody.add(newNimNode(nnkLetSection).und(
+          newNimNode(nnkIdentDefs).und(
+            lenName,
+            newNimNode(nnkEmpty),
+            newCall("readInt16", streamID))))
+        readBody.add(      ## result.name = @[]
+          resName := ("@".prefix(newNimNode(nnkBracket))),
+          newNimNode(nnkForStmt).und(  ## for item in 1..len:
+            item, 
+            infix(1.lit, "..", lenName),
+            newNimNode(nnkStmtList).und(
+              newCall(  ## add(result.name, unpack[seqType](stream))
+                "add", resName, newNimNode(nnkCall).und(readName, streamID)
+        ) ) ) )
+        packbody.add(
+          newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und(
+            lenName,  ## var lenName = int16(len(p.name))
+            newIdentNode("int16"),
+            newCall("int16", newCall("len", dotName)))), 
+          newCall("writeData", streamID, newNimNode(nnkAddr).und(lenName), 2.lit),
+          newNimNode(nnkForStmt).und(  ## for item in 0..length - 1: pack(p.name[item], stream)
+            item,
+            infix(0.lit, "..", infix(lenName, "-", 1.lit)),
+            newNimNode(nnkStmtList).und(
+              newCall("echo", item, ": ".lit),
+              newCall("pack", dotName[item], streamID))))
+        #set the default value to @[] (new sequence)
+        typeFields[i][2] = "@".prefix(newNimNode(nnkBracket))
+      else:
+        error("Unknown type: "& treeRepr(typeFields[i]))
+    of nnkIdent: ##normal type
+      case $typeFields[i][1].ident
+      of "string": # length encoded string
+        packBody.add(newCall("writeLEStr", streamID, dotName))
+        readBody.add(resName := newCall("readLEStr", streamID))
+      of "int8", "int16", "int32", "float32", "float64", "char", "bool":
+        packBody.add(newCall(
+          "writeData", streamID, newNimNode(nnkAddr).und(dotName), newCall("sizeof", dotName)))
+        readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
+      else:  ## hopefully the type you specified was another defpacket() type
+        packBody.add(newCall("pack", dotName, streamID))
+        readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
+    else:
+      error("I dont know what to do with: "& treerepr(typeFields[i]))
+  
+  var 
+    toStringFunc = newNimNode(nnkProcDef).und(
+      newNimNode(nnkPostfix).und(
+        ^"*",
+        newNimNode(nnkAccQuoted).und(^"$")),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        ^"string",
+        newNimNode(nnkIdentDefs).und(
+          packetID, # p: typeName
+          typeName,
+          emptyNode())),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkStmtList).und(#[6]
+        newNimNode(nnkAsgn).und(
+          ^"result",                  ## result = 
+          newNimNode(nnkCall).und(#[6][0][1]
+            ^"format",  ## format
+            emptyNode()))))  ## "[TypeName   $1   $2]"
+    formatStr = "["& $typeName.ident
+  
+  const emptyFields = {nnkEmpty, nnkNilLit}
+  var objFields = newNimNode(nnkRecList)
+  for i in 0.. < len(typeFields):
+    let fname = typeFields[i][0]
+    constructorParams.add(newNimNode(nnkIdentDefs).und(
+      fname,
+      typeFields[i][1],
+      typeFields[i][2]))
+    constructorBody.add((^"result").dot(fname) := fname)
+    #export the name
+    typeFields[i][0] = fname.postfix("*")
+    if not(typeFields[i][2].kind in emptyFields):
+      ## empty the type default for the type def
+      typeFields[i][2] = newNimNode(nnkEmpty)
+    objFields.add(typeFields[i])
+    toStringFunc[6][0][1].add(
+      prefix("$", packetID.dot(fname)))
+    formatStr.add "   $"
+    formatStr.add($(i + 1))
+  
+  formatStr.add ']'
+  toStringFunc[6][0][1][1] = formatStr.lit()
+  
+  result.add(
+    newNimNode(nnkTypeSection).und(
+      newNimNode(nnkTypeDef).und(
+        typeName.postfix("*"),
+        newNimNode(nnkEmpty),
+        newNimNode(nnkObjectTy).und(
+          newNimNode(nnkEmpty), #not sure what this is
+          newNimNode(nnkEmpty), #parent: OfInherit(Ident(!"SomeObj"))
+          objFields))))
+  result.add(constructor.und(constructorBody))
+  result.add(pack.und(packBody))
+  result.add(read.und(readBody))
+  result.add(toStringFunc)
+  when defined(GenPacketShowOutput):
+    echo(repr(result))
+
+proc `->`(a: string, b: string): PNimrodNode {.compileTime.} =
+  result = newNimNode(nnkIdentDefs).und(^a, ^b, newNimNode(nnkEmpty))
+proc `->`(a: string, b: PNimrodNode): PNimrodNode {.compileTime.} =
+  result = newNimNode(nnkIdentDefs).und(^a, b, newNimNode(nnkEmpty))
+proc `->`(a, b: PNimrodNode): PNimrodNode {.compileTime.} =
+  a[2] = b
+  result = a
+
+proc newProc*(name: string, params: varargs[PNimrodNode], resultType: PNimrodNode): PNimrodNode {.compileTime.} =
+  result = newNimNode(nnkProcDef).und(
+    ^name,
+    emptyNode(),
+    emptyNode(),
+    newNimNode(nnkFormalParams).und(resultType),
+    emptyNode(),
+    emptyNode(),
+    newNimNode(nnkStmtList))
+  result[3].add(params)
+macro forwardPacket*(typeName: expr, underlyingType: typedesc): stmt {.immediate.} =
+  result = newNimNode(nnkStmtList).und(
+    newProc(
+      "read"& $typeName.ident, 
+      ["s" -> "PStream" -> newNimNode(nnkNilLit)],
+      typeName),
+    newProc(
+      "pack",
+      [ "p" -> newNimNode(nnkVarTy).und(typeName),
+        "s" -> "PStream" -> newNimNode(nnkNilLit)],
+      emptyNode()))
+  result[0][6].add(newNimNode(nnkDiscardStmt).und(
+    newCall(
+      "readData", ^"s", newNimNode(nnkAddr).und(^"result"), newCall("sizeof", ^"result")
+    )))
+  result[1][6].add(
+    newCall(
+      "writeData", ^"s", newNimNode(nnkAddr).und(^"p"), newCall(
+        "sizeof", ^"p")))
+  when defined(GenPacketShowOutput):
+    echo(repr(result))
+
+template forwardPacketT*(typeName: expr): stmt {.dirty, immediate.} =
+  proc `read typeName`*(s: PStream): typeName =
+    discard readData(s, addr result, sizeof(result))
+  proc `pack typeName`*(p: var typeName; s: PStream) =
+    writeData(s, addr p, sizeof(p))
+
+when isMainModule:
+  type
+    SomeEnum = enum
+      A = 0'i8,
+      B, C
+  forwardPacket(SomeEnum, int8)
+  
+  
+  defPacket(Foo, tuple[x: array[0..4, int8]])
+  var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8])
+  var s2 = newStringStream("")
+  f.pack(s2)
+  assert s2.data == "\4\3\2\1\0"
+  
+  var s = newStringStream()
+  s.flushImpl = proc(s: PStream) =
+    var z = PStringStream(s)
+    z.setPosition(0)
+    z.data.setLen(0)
+  
+  
+  s.setPosition(0)
+  s.data.setLen(0)
+  var o = B
+  o.pack(s)
+  o = A
+  o.pack(s)
+  o = C
+  o.pack(s)
+  assert s.data == "\1\0\2"
+  s.flush
+  
+  defPacket(Y, tuple[z: int8])
+  proc `$`(z: Y): string = result = "Y("& $z.z &")"
+  defPacket(TestPkt, tuple[x: seq[Y]])
+  var test = newTestPkt()
+  test.x.add([newY(5), newY(4), newY(3), newY(2), newY(1)])
+  for itm in test.x:
+    echo(itm)
+  test.pack(s)
+  echo(repr(s.data))
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
new file mode 100644
index 000000000..44d00db53
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/genpacket_enet.nim
@@ -0,0 +1,296 @@
+import macros, macro_dsl, estreams
+from strutils import format
+
+template newLenName(): stmt {.immediate.} =
+  let lenName {.inject.} = ^("len"& $lenNames)
+  inc(lenNames)
+
+template defPacketImports*(): stmt {.immediate, dirty.} =
+  import macros, macro_dsl, estreams
+  from strutils import format
+
+proc `$`*[T](x: seq[T]): string =
+  result = "[seq len="
+  result.add($x.len)
+  result.add ':'
+  for i in 0.. <len(x):
+    result.add "   "
+    result.add($x[i])
+  result.add ']'
+
+macro defPacket*(typeNameN: expr, typeFields: expr): stmt {.immediate.} = 
+  result = newNimNode(nnkStmtList)
+  let 
+    typeName = quoted2ident(typeNameN)
+    packetID = ^"p"
+    streamID = ^"s"
+  var
+    constructorParams = newNimNode(nnkFormalParams).und(typeName)
+    constructor = newNimNode(nnkProcDef).und(
+      postfix(^("new"& $typeName.ident), "*"),
+      emptyNode(),
+      emptyNode(),
+      constructorParams,
+      emptyNode(),
+      emptyNode())
+    pack = newNimNode(nnkProcDef).und(
+      postfix(^"pack", "*"),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        emptyNode(),   # : void
+        newNimNode(nnkIdentDefs).und(
+          streamID,    # s: PBuffer
+          ^"PBuffer",
+          newNimNode(nnkNilLit)),
+        newNimNode(nnkIdentDefs).und(
+          packetID,    # p: var typeName
+          newNimNode(nnkVarTy).und(typeName),
+          emptyNode())),
+      emptyNode(),
+      emptyNode())
+    read = newNimNode(nnkProcDef).und(
+      newIdentNode("read"& $typeName.ident).postfix("*"),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        typeName,   #result type
+        newNimNode(nnkIdentDefs).und(
+          streamID, # s: PBuffer = nil
+          ^"PBuffer",
+          newNimNode(nnkNilLit))),
+      emptyNode(),
+      emptyNode())
+    constructorBody = newNimNode(nnkStmtList)
+    packBody = newNimNode(nnkStmtList)
+    readBody = newNimNode(nnkStmtList)
+    lenNames = 0
+  for i in 0.. typeFields.len - 1:
+    let 
+      name = typeFields[i][0]
+      dotName = packetID.dot(name)
+      resName = newIdentNode(!"result").dot(name)
+    case typeFields[i][1].kind
+    of nnkBracketExpr: #ex: paddedstring[32, '\0'], array[range, type]
+      case $typeFields[i][1][0].ident
+      of "seq":
+        ## let lenX = readInt16(s)
+        newLenName()
+        let 
+          item = ^"item"  ## item name in our iterators
+          seqType = typeFields[i][1][1] ## type of seq
+          readName = newIdentNode("read"& $seqType.ident)
+        readBody.add(newNimNode(nnkLetSection).und(
+          newNimNode(nnkIdentDefs).und(
+            lenName,
+            newNimNode(nnkEmpty),
+            newCall("readInt16", streamID))))
+        readBody.add(      ## result.name = @[]
+          resName := ("@".prefix(newNimNode(nnkBracket))),
+          newNimNode(nnkForStmt).und(  ## for item in 1..len:
+            item, 
+            infix(1.lit, "..", lenName),
+            newNimNode(nnkStmtList).und(
+              newCall(  ## add(result.name, unpack[seqType](stream))
+                "add", resName, newNimNode(nnkCall).und(readName, streamID)
+        ) ) ) )
+        packbody.add(
+          newNimNode(nnkVarSection).und(newNimNode(nnkIdentDefs).und(
+            lenName,  ## var lenName = int16(len(p.name))
+            newIdentNode("int16"),
+            newCall("int16", newCall("len", dotName)))), 
+          newCall("writeBE", streamID, lenName),
+          newNimNode(nnkForStmt).und(  ## for item in 0..length - 1: pack(p.name[item], stream)
+            item,
+            infix(0.lit, "..", infix(lenName, "-", 1.lit)),
+            newNimNode(nnkStmtList).und(
+              newCall("echo", item, ": ".lit),
+              newCall("pack", streamID, dotName[item]))))
+        #set the default value to @[] (new sequence)
+        typeFields[i][2] = "@".prefix(newNimNode(nnkBracket))
+      else:
+        error("Unknown type: "& treeRepr(typeFields[i]))
+    of nnkIdent: ##normal type
+      case $typeFields[i][1].ident
+      of "string": # length encoded string
+        packBody.add(newCall("write", streamID, dotName))
+        readBody.add(resName := newCall("readStr", streamID))
+      of "int8", "int16", "int32", "float32", "float64", "char", "bool":
+        packBody.add(newCall(
+          "writeBE", streamID, dotName))
+        readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
+      else:  ## hopefully the type you specified was another defpacket() type
+        packBody.add(newCall("pack", streamID, dotName))
+        readBody.add(resName := newCall("read"& $typeFields[i][1].ident, streamID))
+    else:
+      error("I dont know what to do with: "& treerepr(typeFields[i]))
+  
+  var 
+    toStringFunc = newNimNode(nnkProcDef).und(
+      newNimNode(nnkPostfix).und(
+        ^"*",
+        newNimNode(nnkAccQuoted).und(^"$")),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkFormalParams).und(
+        ^"string",
+        newNimNode(nnkIdentDefs).und(
+          packetID, # p: typeName
+          typeName,
+          emptyNode())),
+      emptyNode(),
+      emptyNode(),
+      newNimNode(nnkStmtList).und(#[6]
+        newNimNode(nnkAsgn).und(
+          ^"result",                  ## result = 
+          newNimNode(nnkCall).und(#[6][0][1]
+            ^"format",  ## format
+            emptyNode()))))  ## "[TypeName   $1   $2]"
+    formatStr = "["& $typeName.ident
+  
+  const emptyFields = {nnkEmpty, nnkNilLit}
+  var objFields = newNimNode(nnkRecList)
+  for i in 0.. < len(typeFields):
+    let fname = typeFields[i][0]
+    constructorParams.add(newNimNode(nnkIdentDefs).und(
+      fname,
+      typeFields[i][1],
+      typeFields[i][2]))
+    constructorBody.add((^"result").dot(fname) := fname)
+    #export the name
+    typeFields[i][0] = fname.postfix("*")
+    if not(typeFields[i][2].kind in emptyFields):
+      ## empty the type default for the type def
+      typeFields[i][2] = newNimNode(nnkEmpty)
+    objFields.add(typeFields[i])
+    toStringFunc[6][0][1].add(
+      prefix("$", packetID.dot(fname)))
+    formatStr.add "   $"
+    formatStr.add($(i + 1))
+  
+  formatStr.add ']'
+  toStringFunc[6][0][1][1] = formatStr.lit()
+  
+  result.add(
+    newNimNode(nnkTypeSection).und(
+      newNimNode(nnkTypeDef).und(
+        typeName.postfix("*"),
+        newNimNode(nnkEmpty),
+        newNimNode(nnkObjectTy).und(
+          newNimNode(nnkEmpty), #not sure what this is
+          newNimNode(nnkEmpty), #parent: OfInherit(Ident(!"SomeObj"))
+          objFields))))
+  result.add(constructor.und(constructorBody))
+  result.add(pack.und(packBody))
+  result.add(read.und(readBody))
+  result.add(toStringFunc)
+  when defined(GenPacketShowOutput):
+    echo(repr(result))
+
+proc newProc*(name: PNimrodNode; params: varargs[PNimrodNode]; resultType: PNimrodNode): PNimrodNode {.compileTime.} =
+  result = newNimNode(nnkProcDef).und(
+    name,
+    emptyNode(),
+    emptyNode(),
+    newNimNode(nnkFormalParams).und(resultType),
+    emptyNode(),
+    emptyNode(),
+    newNimNode(nnkStmtList))
+  result[3].add(params)
+
+proc body*(procNode: PNimrodNode): PNimrodNode {.compileTime.} =
+  assert procNode.kind == nnkProcDef and procNode[6].kind == nnkStmtList
+  result = procNode[6]
+
+proc iddefs*(a, b: string; c: PNimrodNode): PNimrodNode {.compileTime.} =
+  result = newNimNode(nnkIdentDefs).und(^a, ^b, c)
+proc iddefs*(a: string; b: PNimrodNode): PNimrodNode {.compileTime.} =
+  result = newNimNode(nnkIdentDefs).und(^a, b, emptyNode())
+proc varTy*(a: PNimrodNode): PNimrodNode {.compileTime.} =
+  result = newNimNode(nnkVarTy).und(a)
+
+macro forwardPacket*(typeName: expr, underlyingType: expr): stmt {.immediate.} =
+  var
+    packetID = ^"p"
+    streamID = ^"s"
+  result = newNimNode(nnkStmtList).und(
+    newProc(
+      (^("read"& $typeName.ident)).postfix("*"), 
+      [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)) ],
+      typeName),
+    newProc(
+      (^"pack").postfix("*"),
+      [ iddefs("s", "PBuffer", newNimNode(nnkNilLit)),
+        iddefs("p", varTy(typeName)) ],
+      emptyNode()))
+  var
+    readBody = result[0][6]
+    packBody = result[1][6]
+    resName = ^"result"
+  
+  case underlyingType.kind
+  of nnkBracketExpr:
+    case $underlyingType[0].ident
+    of "array":
+      for i in underlyingType[1][1].intval.int .. underlyingType[1][2].intval.int:
+        readBody.add(
+          newCall("read", ^"s", resName[lit(i)]))
+        packBody.add(
+          newCall("writeBE", ^"s", packetID[lit(i)]))
+    else:
+      echo "Unknown type: ", repr(underlyingtype)
+  else:
+    echo "unknown type:", repr(underlyingtype)
+  echo(repr(result))
+
+template forwardPacketT*(typeName: expr; underlyingType: expr): stmt {.dirty, immediate.} =
+  proc `read typeName`*(buffer: PBuffer): typeName =
+    #discard readData(s, addr result, sizeof(result))
+    var res: underlyingType
+    buffer.read(res)
+    result = typeName(res)
+  proc `pack`*(buffer: PBuffer; ord: var typeName) =
+    #writeData(s, addr p, sizeof(p))
+    buffer.write(underlyingType(ord))
+
+when isMainModule:
+  type
+    SomeEnum = enum
+      A = 0'i8,
+      B, C
+  forwardPacket(SomeEnum, int8)
+  
+  
+  defPacket(Foo, tuple[x: array[0..4, int8]])
+  var f = newFoo([4'i8, 3'i8, 2'i8, 1'i8, 0'i8])
+  var s2 = newStringStream("")
+  f.pack(s2)
+  assert s2.data == "\4\3\2\1\0"
+  
+  var s = newStringStream()
+  s.flushImpl = proc(s: PStream) =
+    var z = PStringStream(s)
+    z.setPosition(0)
+    z.data.setLen(0)
+  
+  
+  s.setPosition(0)
+  s.data.setLen(0)
+  var o = B
+  o.pack(s)
+  o = A
+  o.pack(s)
+  o = C
+  o.pack(s)
+  assert s.data == "\1\0\2"
+  s.flush
+  
+  defPacket(Y, tuple[z: int8])
+  proc `$`(z: Y): string = result = "Y("& $z.z &")"
+  defPacket(TestPkt, tuple[x: seq[Y]])
+  var test = newTestPkt()
+  test.x.add([newY(5), newY(4), newY(3), newY(2), newY(1)])
+  for itm in test.x:
+    echo(itm)
+  test.pack(s)
+  echo(repr(s.data))
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim
new file mode 100644
index 000000000..cbae1334e
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/macro_dsl.nim
@@ -0,0 +1,73 @@
+import macros
+{.deadCodeElim: on.}
+#Inline macro.add() to allow for easier nesting
+proc und*(a: PNimrodNode; b: PNimrodNode): PNimrodNode {.compileTime.} =
+  a.add(b)
+  result = a
+proc und*(a: PNimrodNode; b: varargs[PNimrodNode]): PNimrodNode {.compileTime.} =
+  a.add(b)
+  result = a
+
+proc `^`*(a: string): PNimrodNode {.compileTime.} = 
+  ## new ident node
+  result = newIdentNode(!a)
+proc `[]`*(a, b: PNimrodNode): PNimrodNode {.compileTime.} =
+  ## new bracket expression: node[node] not to be confused with node[indx]
+  result = newNimNode(nnkBracketExpr).und(a, b)
+proc `:=`*(left, right: PNimrodNode): PNimrodNode {.compileTime.} =
+  ## new Asgn node:  left = right
+  result = newNimNode(nnkAsgn).und(left, right)
+
+proc lit*(a: string): PNimrodNode {.compileTime.} =
+  result = newStrLitNode(a)
+proc lit*(a: int): PNimrodNode {.compileTime.} =
+  result = newIntLitNode(a)
+proc lit*(a: float): PNimrodNode {.compileTime.} =
+  result = newFloatLitNode(a)
+proc lit*(a: char): PNimrodNode {.compileTime.} =
+  result = newNimNode(nnkCharLit)
+  result.intval = a.ord
+
+proc emptyNode*(): PNimrodNode {.compileTime.} =
+  result = newNimNode(nnkEmpty)
+
+proc dot*(left, right: PNimrodNode): PNimrodNode {.compileTime.} =
+  result = newNimNode(nnkDotExpr).und(left, right)
+proc postfix*(a: PNimrodNode, b: string): PNimrodNode {.compileTime.} =
+  result = newNimNode(nnkPostfix).und(newIdentNode(!b), a)
+proc prefix*(a: string, b: PNimrodNode): PNimrodNode {.compileTime.} =
+  result = newNimNode(nnkPrefix).und(newIdentNode(!a), b)
+
+proc infix*(a, b, c: PNimrodNode): PNimrodNode {.compileTime.} =
+  ## 5.infix("+", 10)  ## => 5 + 10
+  result = newNimNode(nnkInfix).und(b, a, c)
+proc infix*(a: PNimrodNode; b: string; c: PNimrodNode): PNimrodNode {.compileTime.} =
+  ## Infix operation: infix(5, "+", 10) ## => 
+  result = newNimNode(nnkInfix).und(newIdentNode(b), a, c)
+
+proc quoted2ident*(a: PNimrodNode): PNimrodNode {.compileTime.} = 
+  if a.kind != nnkAccQuoted:
+    return a
+  var pname = ""
+  for piece in 0..a.len - 1:
+    pname.add($a[piece].ident)
+  result = ^pname
+
+
+macro `?`(a: expr): expr =
+  ## Character literal ?A #=> 'A'
+  result = ($a[1].ident)[0].lit
+## echo(?F,?a,?t,?t,?y)
+
+when isMainModule:
+  macro foo(x: stmt): stmt =
+    result = newNimNode(nnkStmtList)
+    result.add(newNimNode(nnkCall).und(!!"echo", "Hello thar".lit))
+    result.add(newCall("echo", lit("3 * 45 = "), (3.lit.infix("*", 45.lit))))
+    let stmtlist = x[1]
+    for i in countdown(len(stmtlist)-1, 0):
+      result.add(stmtlist[i])
+  foo:
+    echo y, " * 2 = ", y * 2
+    let y = 320
+
diff --git a/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
new file mode 100644
index 000000000..a9759687f
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/genpacket/streams_enh.nim
@@ -0,0 +1,47 @@
+import streams
+from strutils import repeatChar
+
+proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString = 
+  var lastChr = length
+  result = s.readStr(length)
+  while lastChr >= 0 and result[lastChr - 1] == padChar: dec(lastChr)
+  result.setLen(lastChr)
+
+proc writePaddedStr*(s: PStream, str: string, length: int, padChar = '\0') =
+  if str.len < length:
+    s.write(str)
+    s.write(repeatChar(length - str.len, padChar))
+  elif str.len > length:
+    s.write(str.substr(0, length - 1))
+  else:
+    s.write(str)
+
+proc readLEStr*(s: PStream): TaintedString =
+  var len = s.readInt16()
+  result = s.readStr(len)
+
+proc writeLEStr*(s: PStream, str: string) =
+  s.write(str.len.int16)
+  s.write(str)
+
+when isMainModule:
+  var testStream = newStringStream()
+  
+  testStream.writeLEStr("Hello")
+  doAssert testStream.data == "\5\0Hello"
+  
+  testStream.setPosition 0
+  var res = testStream.readLEStr()
+  doAssert res == "Hello"
+  
+  testStream.setPosition 0
+  testStream.writePaddedStr("Sup", 10)
+  echo(repr(testStream), testStream.data.len)
+  doAssert testStream.data == "Sup"&repeatChar(7, '\0')
+  
+  testStream.setPosition 0
+  res = testStream.readPaddedStr(10)
+  doAssert res == "Sup"
+  
+  testStream.close()
+
diff --git a/tests/manyloc/keineschweine/dependencies/nake/nake.nim b/tests/manyloc/keineschweine/dependencies/nake/nake.nim
new file mode 100644
index 000000000..eade28c70
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/nake/nake.nim
@@ -0,0 +1,83 @@
+discard """
+DO AS THOU WILST PUBLIC LICENSE
+
+Whoever should stumble upon this document is henceforth and forever
+entitled to DO AS THOU WILST with aforementioned document and the
+contents thereof. 
+
+As said in the Olde Country, `Keepe it Gangster'."""
+
+import strutils, parseopt, tables, os
+
+type
+  PTask* = ref object
+    desc*: string
+    action*: TTaskFunction
+  TTaskFunction* = proc() {.closure.}
+var 
+  tasks* = initTable[string, PTask](16)
+
+proc newTask*(desc: string; action: TTaskFunction): PTask
+proc runTask*(name: string) {.inline.}
+proc shell*(cmd: varargs[string, `$`]): int {.discardable.}
+proc cd*(dir: string) {.inline.}
+
+template nakeImports*(): stmt {.immediate.} =
+  import tables, parseopt, strutils, os
+
+template task*(name: string; description: string; body: stmt): stmt {.dirty, immediate.} =
+  block:
+    var t = newTask(description, proc() {.closure.} =
+      body)
+    tasks[name] = t
+
+proc newTask*(desc: string; action: TTaskFunction): PTask =
+  new(result)
+  result.desc = desc
+  result.action = action
+proc runTask*(name: string) = tasks[name].action()
+
+proc shell*(cmd: varargs[string, `$`]): int =
+  result = execShellCmd(cmd.join(" "))
+proc cd*(dir: string) = setCurrentDir(dir)
+template withDir*(dir: string; body: stmt): stmt =
+  ## temporary cd
+  ## withDir "foo":
+  ##   # inside foo
+  ## #back to last dir
+  var curDir = getCurrentDir()
+  cd(dir)
+  body
+  cd(curDir)
+
+when isMainModule:
+  if not existsFile("nakefile.nim"):
+    echo "No nakefile.nim found. Current working dir is ", getCurrentDir()
+    quit 1
+  var args = ""
+  for i in 1..paramCount():
+    args.add paramStr(i)
+    args.add " "
+  quit(shell("nimrod", "c", "-r", "nakefile.nim", args))
+else:
+  addQuitProc(proc() {.noconv.} =
+    var 
+      task: string
+      printTaskList: bool
+    for kind, key, val in getOpt():
+      case kind
+      of cmdLongOption, cmdShortOption:
+        case key.tolower
+        of "tasks", "t":
+          printTaskList = true
+        else: 
+          echo "Unknown option: ", key, ": ", val
+      of cmdArgument:
+        task = key
+      else: nil
+    if printTaskList or task.isNil or not(tasks.hasKey(task)):
+      echo "Available tasks:"
+      for name, task in pairs(tasks):
+        echo name, " - ", task.desc
+      quit 0
+    tasks[task].action())
diff --git a/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim b/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim
new file mode 100644
index 000000000..24af63d10
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/nake/nakefile.nim
@@ -0,0 +1,23 @@
+import nake
+nakeImports
+
+task "install", "compile and install nake binary":
+  if shell("nimrod", "c", "nake") == 0:
+    let path = getEnv("PATH").split(PathSep)
+    for index, dir in pairs(path):
+      echo "  ", index, ". ", dir
+    echo "Where to install nake binary? (quit with ^C or quit or exit)"
+    let ans = stdin.readLine().toLower
+    var index = 0
+    case ans
+    of "q", "quit", "x", "exit":
+      quit 0
+    else:
+      index = parseInt(ans)
+    if index > path.len or index < 0:
+      echo "Invalid index."
+      quit 1
+    moveFile "nake", path[index]/"nake"
+    echo "Great success!"
+
+
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/README.md b/tests/manyloc/keineschweine/dependencies/sfml/README.md
new file mode 100644
index 000000000..bd9b3d0e7
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/README.md
@@ -0,0 +1,13 @@
+sfml-nimrod
+===========
+
+Nimrod binding of SFML 2.0
+
+This is only tested for Linux at the moment
+
+### What is needed for Windows / OS X?
+
+* The library names need filling in
+* TWindowHandle is handled differently on those platforms
+
+I believe that is it
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim
new file mode 100644
index 000000000..27163e271
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml.nim
@@ -0,0 +1,1115 @@
+import 
+  strutils, math
+when defined(linux):
+  const
+    LibG = "libcsfml-graphics.so.2.0"
+    LibS = "libcsfml-system.so.2.0"
+    LibW = "libcsfml-window.so.2.0"
+else:
+  {.error: "Platform unsupported".}
+{.deadCodeElim: on.}
+{.pragma: pf, pure, final.}
+type
+  PClock* = ptr TClock
+  TClock* {.pf.} = object
+  TTime* {.pf.} = object
+    microseconds*: int64
+  TVector2i* {.pf.} = object
+    x*, y*: cint
+  TVector2f* {.pf.} = object
+    x*, y*: cfloat
+  TVector3f* {.pf.} = object
+    x*, y*, z*: cfloat
+
+  PInputStream* = ptr TInputStream
+  TInputStream* {.pf.} = object 
+    read*: TInputStreamReadFunc
+    seek*: TInputStreamSeekFunc
+    tell*: TInputStreamTellFunc
+    getSize*: TInputStreamGetSizeFunc
+    userData*: pointer
+  TInputStreamReadFunc* = proc (data: pointer, size: int64, userData: pointer): int64{.
+    cdecl.}
+  TInputStreamSeekFunc* = proc (position: int16, userData: pointer): int64{.
+    cdecl.}
+  TInputStreamTellFunc* = proc (userData: pointer): int64 {.cdecl.}
+  TInputStreamGetSizeFunc* = proc (userData: pointer): int64 {.cdecl.}
+  PWindow* = ptr TWindow
+  TWindow* {.pf.} = object
+  PContextSettings* = ptr TContextSettings
+  TContextSettings*{.pf.} = object
+    depthBits: cint
+    stencilBits: cint
+    antialiasingLevel: cint
+    majorVersion: cint
+    minorVersion: cint
+  TVideoMode* {.pf.} = object
+    width*: cint
+    height*: cint
+    bitsPerPixel*: cint
+  TEventType*{.size: sizeof(cint).} = enum 
+    EvtClosed, EvtResized, EvtLostFocus, EvtGainedFocus, 
+    EvtTextEntered, EvtKeyPressed, EvtKeyReleased, EvtMouseWheelMoved, 
+    EvtMouseButtonPressed, EvtMouseButtonReleased, EvtMouseMoved, 
+    EvtMouseEntered, EvtMouseLeft, EvtJoystickButtonPressed, 
+    EvtJoystickButtonReleased, EvtJoystickMoved, EvtJoystickConnected, 
+    EvtJoystickDisconnected
+  TKeyEvent*{.pf.} = object 
+    code*: TKeyCode
+    alt*    : bool
+    control*: bool
+    shift*  : bool
+    system* : bool
+  TJoystickConnectEvent*{.pf.} = object
+    joystickId*: cint
+  TJoystickButtonEvent*{.pf.} = object
+    joystickId*: cint
+    button*: cint
+  TJoystickMoveEvent*{.pf.} = object
+    joystickId*: cint
+    axis*: TJoystickAxis
+    position*: cfloat
+  TMouseWheelEvent*{.pf.} = object 
+    delta*: cint
+    x*: cint
+    y*: cint
+  TMouseButtonEvent*{.pf.} = object
+    button*: TMouseButton
+    x*: cint
+    y*: cint
+  TMouseMoveEvent*{.pf.} = object
+    x*: cint
+    y*: cint
+  TTextEvent*{.pf.} = object
+    unicode*: cint
+  PEvent* = ptr TEvent
+  TEvent*{.pf.} = object
+    case kind*: TEventType
+    of EvtKeyPressed, EvtKeyReleased: 
+      key*: TKeyEvent
+    of EvtMouseButtonPressed, EvtMouseButtonReleased:
+      mouseButton*: TMouseButtonEvent
+    of EvtTextEntered:
+      text*: TTextEvent
+    of EvtJoystickConnected, EvtJoystickDisconnected:
+      joystickConnect*: TJoystickConnectEvent
+    of EvtJoystickMoved:
+      joystickMove*: TJoystickMoveEvent
+    of EvtJoystickButtonPressed, EvtJoystickButtonReleased:
+      joystickButton*: TJoystickButtonEvent
+    of EvtResized:
+      size*: TSizeEvent
+    of EvtMouseMoved, EvtMouseEntered, EvtMouseLeft:
+      mouseMove*: TMouseMoveEvent
+    of EvtMouseWheelMoved:
+      mouseWheel*: TMouseWheelEvent
+    else: nil
+  TJoystickAxis*{.size: sizeof(cint).} = enum 
+    JoystickX, JoystickY, JoystickZ, JoystickR,      
+    JoystickU, JoystickV, JoystickPovX, JoystickPovY
+  TSizeEvent*{.pf.} = object
+    width*: cint
+    height*: cint
+  TMouseButton*{.size: sizeof(cint).} = enum 
+    MouseLeft, MouseRight, MouseMiddle,  
+    MouseXButton1, MouseXButton2, MouseButtonCount
+  TKeyCode*{.size: sizeof(cint).} = enum 
+    KeyUnknown = - 1, KeyA, KeyB, KeyC, KeyD, KeyE,
+    KeyF, KeyG, KeyH, KeyI, KeyJ, KeyK, KeyL, KeyM,                 #/< The M key
+    KeyN, KeyO, KeyP, KeyQ, KeyR, KeyS, KeyT, KeyU,                 #/< The U key
+    KeyV, KeyW, KeyX, KeyY, KeyZ, KeyNum0, KeyNum1,              #/< The 1 key
+    KeyNum2, KeyNum3, KeyNum4, KeyNum5, KeyNum6,              #/< The 6 key
+    KeyNum7, KeyNum8, KeyNum9, KeyEscape, KeyLControl,          #/< The left Control key
+    KeyLShift, KeyLAlt, KeyLSystem, KeyRControl,          #/< The right Control key
+    KeyRShift, KeyRAlt, KeyRSystem, KeyMenu,              #/< The Menu key
+    KeyLBracket, KeyRBracket, KeySemiColon, KeyComma,             #/< The , key
+    KeyPeriod, KeyQuote, KeySlash, KeyBackSlash,         #/< The \ key
+    KeyTilde, KeyEqual, KeyDash, KeySpace, KeyReturn,            #/< The Return key
+    KeyBack, KeyTab, KeyPageUp, KeyPageDown, KeyEnd,               #/< The End key
+    KeyHome, KeyInsert, KeyDelete, KeyAdd, KeySubtract,          #/< -
+    KeyMultiply, KeyDivide, KeyLeft, KeyRight, KeyUp,                #/< Up arrow
+    KeyDown, KeyNumpad0, KeyNumpad1, KeyNumpad2,           #/< The numpad 2 key
+    KeyNumpad3,           #/< The numpad 3 key
+    KeyNumpad4,           #/< The numpad 4 key
+    KeyNumpad5,           #/< The numpad 5 key
+    KeyNumpad6,           #/< The numpad 6 key
+    KeyNumpad7,           #/< The numpad 7 key
+    KeyNumpad8,           #/< The numpad 8 key
+    KeyNumpad9,           #/< The numpad 9 key
+    KeyF1,                #/< The F1 key
+    KeyF2,                #/< The F2 key
+    KeyF3,                #/< The F3 key
+    KeyF4,                #/< The F4 key
+    KeyF5,                #/< The F5 key
+    KeyF6,                #/< The F6 key
+    KeyF7,                #/< The F7 key
+    KeyF8,                #/< The F8 key
+    KeyF9,                #/< The F8 key
+    KeyF10,               #/< The F10 key
+    KeyF11,               #/< The F11 key
+    KeyF12,               #/< The F12 key
+    KeyF13,               #/< The F13 key
+    KeyF14,               #/< The F14 key
+    KeyF15,               #/< The F15 key
+    KeyPause,             #/< The Pause key
+    KeyCount              #/< Keep last -- the total number of keyboard keys
+when defined(linux): #or defined(bsd) ??
+  type TWindowHandle* = clong
+#elif defined(mac):
+#  type TWindowHandle* = pointer ##typedef void* sfWindowHandle; <- whatever the hell that is
+#elif defined(windows):
+#  type TWindowHandle* = HWND__ ? windows is crazy. ##struct HWND__; typedef struct HWND__* sfWindowHandle;
+const
+  sfNone*         = 0
+  sfTitlebar*     = 1 shl 0
+  sfResize*       = 1 shl 1
+  sfClose*        = 1 shl 2
+  sfFullscreen*   = 1 shl 3
+  sfDefaultStyle* = sfTitlebar or sfResize or sfClose
+type
+  PRenderWindow* = ptr TRenderWindow
+  TRenderWindow* {.pf.} = object
+
+  PFont* = ptr TFont
+  TFont* {.pf.} = object
+  PImage* = ptr TImage
+  TImage* {.pf.} = object
+  PShader* = ptr TShader
+  TShader* {.pf.} = object
+  PSprite* = ptr TSprite
+  TSprite* {.pf.} = object
+  PText* = ptr TText
+  TText* {.pf.} = object
+  PTexture* = ptr TTexture
+  TTexture* {.pf.} = object
+  PVertexArray* = ptr TVertexArray
+  TVertexArray* {.pf.} = object
+  PView* = ptr TView
+  TView* {.pf.} = object
+  PRenderTexture* = ptr TRenderTexture
+  TRenderTexture* {.pf.} = object
+
+  PShape* = ptr TShape
+  TShape* {.pf.} = object
+  PCircleShape* = ptr TCircleShape
+  TCircleShape* {.pf.} = object
+  PRectangleShape* = ptr TRectangleShape
+  TRectangleShape* {.pf.} = object
+  PConvexShape* = ptr TConvexShape
+  TConvexShape* {.pf.} = object
+
+  TTextStyle*{.size: sizeof(cint).} = enum 
+    TextRegular = 0, TextBold = 1 shl 0, TextItalic = 1 shl 1, 
+    TextUnderlined = 1 shl 2
+
+  TBlendMode*{.size: sizeof(cint).} = enum 
+      BlendAlpha, BlendAdd, BlendMultiply, BlendNone
+  PRenderStates* = ptr TRenderStates
+  TRenderStates* {.pf.} = object
+    blendMode*: TBlendMode
+    transform*: TTransform
+    texture*: PTexture
+    shader*: PShader
+
+  PTransform* = ptr TTransform
+  TTransform* {.pf.} = object
+    matrix*: array[0..8, cfloat]
+  TColor* {.pf.} = object 
+    r*: Uint8
+    g*: Uint8
+    b*: Uint8
+    a*: Uint8
+  PFloatRect* = ptr TFloatRect
+  TFloatRect*{.pf.} = object 
+    left*: cfloat
+    top*: cfloat
+    width*: cfloat
+    height*: cfloat
+  PIntRect* = ptr TIntRect
+  TIntRect*{.pf.} = object 
+    left*: cint
+    top*: cint
+    width*: cint
+    height*: cint
+  TGlyph* {.pf.} = object
+    advance*: cint
+    bounds*: TIntRect
+    textureRect*: TIntRect
+  PVertex* = ptr TVertex
+  TVertex* {.pf.} = object
+    position*: TVector2f
+    color*: TColor
+    texCoords*: TVector2f
+  TPrimitiveType*{.size: sizeof(cint).} = enum 
+    Points,               #/< List of individual points
+    Lines,                #/< List of individual lines
+    LinesStrip,           #/< List of connected lines, a point uses the previous point to form a line
+    Triangles,            #/< List of individual triangles
+    TrianglesStrip,       #/< List of connected triangles, a point uses the two previous points to form a triangle
+    TrianglesFan,         #/< List of connected triangles, a point uses the common center and the previous point to form a triangle
+    Quads
+
+
+proc newWindow*(mode: TVideoMode, title: cstring, style: uint32, settings: PContextSettings = nil): PWindow {.
+  cdecl, importc: "sfWindow_create", dynlib: LibW.}
+
+proc close*(window: PWindow) {.
+  cdecl, importc: "sfWindow_close", dynlib: LibW.}
+proc isOpen*(window: PWindow): bool {.cdecl, importc: "sfWindow_isOpen", dynlib: LibW.}
+
+proc pollEvent*(window: PWindow, event: PEvent): bool {.
+  cdecl, importc: "sfWindow_pollEvent", dynlib: LibW.}
+proc waitEvent*(window: PWindow, event: PEvent): bool {.
+  cdecl, importc: "sfWindow_waitEvent", dynlib: LibW.}
+
+proc getDesktopMode*(): TVideoMode {.
+  cdecl, importc: "sfVideoMode_getDesktopMode", dynlib: LibW.}
+proc isKeyPressed*(key: TKeyCode): bool {.
+  cdecl, importc: "sfKeyboard_isKeyPressed", dynlib: LibW.}
+
+proc mouseIsButtonPressed*(button: TMouseButton): bool {.
+  cdecl, importc: "sfMouse_isButtonPressed", dynlib: LibW.}
+proc mouseGetPosition*(relativeTo: PWindow): TVector2i {.
+  cdecl, importc: "sfMouse_getPosition", dynlib: LibW.}
+proc mouseSetPosition*(position: TVector2i, relativeTo: PWindow) {.
+  cdecl, importc: "sfMouse_setPosition", dynlib: LibW.}
+
+proc joystickIsConnected*(joystick: cint): bool {.
+  cdecl, importc: "sfJoystick_isConnected", dynlib: LibW.}
+proc joystickGetButtonCount*(joystick: cint): cint {.
+  cdecl, importc: "sfJoystick_getButtonCount", dynlib: LibW.}
+proc joystickHasAxis*(joystick: cint, axis: TJoystickAxis): bool {.
+  cdecl, importc: "sfJoystick_hasAxis", dynlib: LibW.}
+proc joystickIsButtonPressed*(joystick: cint, button: cint): bool {.
+  cdecl, importc: "sfJoystick_isButtonPressed", dynlib: LibW.}
+proc joystickGetAxisPosition*(joystick: cint, axis: TJoystickAxis): float {.
+  cdecl, importc: "sfJoystick_getAxisPosition", dynlib: LibW.}
+proc joystickUpdate*(): void {.
+  cdecl, importc: "sfJoystick_update", dynlib: LibW.}
+
+
+proc newRenderWindow*(handle: TWindowHandle, settings: PContextSettings = nil): PRenderWindow{.
+  cdecl, importc: "sfRenderWindow_createFromHandle", dynlib: LibG.}
+proc newRenderWindow*(mode: TVideoMode, title: cstring, style: int32, settings: PContextSettings = nil): PRenderWindow {.
+  cdecl, importc: "sfRenderWindow_create", dynlib: LibG.}
+
+proc destroy*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_destroy", dynlib: LibG.}
+proc close*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_close", dynlib: LibG.}
+proc isOpen*(window: PRenderWindow): bool {.
+  cdecl, importc: "sfRenderWindow_isOpen", dynlib: LibG.}
+
+#void sfRenderWindow_setIcon(sfRenderWindow* renderWindow, unsigned int width, unsigned int height, const sfUint8* pixels);
+#proc setIcon*(window: PRenderWindow, width, height: cint, pixels: seq[uint8]) {.
+#  cdecl, importc: "sfRenderWindow_setIcon", dynlib: LibG.}
+
+proc getSettings*(window: PRenderWindow): TContextSettings {.
+  cdecl, importc: "sfRenderWindow_getSettings", dynlib: LibG.}
+
+proc pollEvent*(window: PRenderWindow, event: PEvent): bool {.
+  cdecl, importc: "sfRenderWindow_pollEvent", dynlib: LibG.}
+proc pollEvent*(window: PRenderWindow; event: var TEvent): bool {.
+  cdecl, importc: "sfRenderWindow_pollEvent", dynlib: LibG.}
+proc waitEvent*(window: PRenderWindow, event: PEvent): bool {.
+  cdecl, importc: "sfRenderWindow_waitEvent", dynlib: LibG.}
+proc waitEvent*(window: PRenderWindow, event: var TEvent): bool {.
+  cdecl, importc: "sfRenderWindow_waitEvent", dynlib: LibG.}
+proc getPosition*(window: PRenderWindow): TVector2i {.
+  cdecl, importc: "sfRenderWindow_getPosition", dynlib: LibG.}
+proc setPosition*(window: PRenderWindow, position: TVector2i) {.
+  cdecl, importc: "sfRenderWindow_setPosition", dynlib: LibG.}
+proc getSize*(window: PRenderWindow): TVector2i {.
+  cdecl, importc: "sfRenderWindow_getSize", dynlib: LibG.}
+proc setSize*(window: PRenderWindow, size: TVector2i): void {.
+  cdecl, importc: "sfRenderWindow_setSize", dynlib: LibG.}
+proc setTitle*(window: PRenderWindow, title: cstring): void {.
+  cdecl, importc: "sfRenderWindow_setTitle", dynlib: LibG.}
+
+proc setVisible*(window: PRenderWindow, visible: bool) {.
+  cdecl, importc: "sfRenderWindow_setVisible", dynlib: LibG.}
+proc setMouseCursorVisible*(window: PRenderWindow, show: bool) {.
+  cdecl, importc: "sfRenderWindow_setMouseCursorVisible", dynlib: LibG.}
+proc setVerticalSyncEnabled*(window: PRenderWindow, enabled: bool) {.
+  cdecl, importc: "sfRenderWindow_setVerticalSyncEnabled", dynlib: LibG.}
+proc setKeyRepeatEnabled*(window: PRenderWindow, enabled: bool) {.
+  cdecl, importc: "sfRenderWindow_setKeyRepeatEnabled", dynlib: LibG.}
+proc setActive*(window: PRenderWindow, active: bool): bool {.
+  cdecl, importc: "sfRenderWindow_setActive", dynlib: LibG.}
+proc display*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_display", dynlib: LibG.}
+proc setFramerateLimit*(window: PRenderWindow, limit: uint) {.
+  cdecl, importc: "sfRenderWindow_setFramerateLimit", dynlib: LibG.}
+proc setJoystickThreshold*(window: PRenderWindow, threshold: float) {.
+  cdecl, importc: "sfRenderWindow_setJoystickThreshold", dynlib: LibG.}
+proc getSystemHandle*(window: PRenderWindow): TWindowHandle {.
+  cdecl, importc: "sfRenderWindow_getSystemHandle", dynlib: LibG.}
+
+proc clear*(window: PRenderWindow, color: TColor) {.
+  cdecl, importc: "sfRenderWindow_clear", dynlib: LibG.}
+
+proc setView*(window: PRenderWindow, view: PView) {.
+  cdecl, importc: "sfRenderWindow_setView", dynlib: LibG.}
+proc getView*(window: PRenderWindow): PView {.
+  cdecl, importc: "sfRenderWindow_getView", dynlib: LibG.}
+proc getDefaultView*(window: PRenderWindow): PView {.
+  cdecl, importc: "sfRenderWindow_getDefaultView", dynlib: LibG.}
+proc getViewport*(window: PRenderWindow, view: PView): TIntRect {.
+  cdecl, importc: "sfRenderWindow_getViewport", dynlib: LibG.}
+
+proc convertCoords*(window: PRenderWindow, point: TVector2i, targetView: PView): TVector2f {.
+  cdecl, importc: "sfRenderWindow_convertCoords", dynlib: LibG.}
+
+proc draw*(window: PRenderWindow, sprite: PSprite, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawSprite", dynlib: LibG.}
+proc draw*(window: PRenderWindow, text: PText, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawText", dynlib: LibG.}
+proc draw*(window: PRenderWindow, shape: PShape, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawShape", dynlib: LibG.}
+proc draw*(window: PRenderWindow, shape: PCircleShape, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawCircleShape", dynlib: LibG.}
+proc draw*(window: PRenderWindow, shape: PRectangleShape, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawRectangleShape", dynlib: LibG.}
+
+proc draw*(window: PRenderWindow, shape: PConvexShape, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawConvexShape", dynlib: LibG.}
+proc draw*(window: PRenderWindow, shape: PVertexArray, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawVertexArray", dynlib: LibG.}
+proc draw*(window: PRenderWindow, vertices: PVertex, vertexCount: cint, 
+           vertexType: TPrimitiveType, states: PRenderStates = nil) {.
+  cdecl, importc: "sfRenderWindow_drawPrimitives", dynlib: LibG.}
+
+proc pushGlStates*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_pushGLStates", dynlib: LibG.}
+proc popGlStates*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_popGLStates", dynlib: LibG.}
+proc resetGlStates*(window: PRenderWindow) {.
+  cdecl, importc: "sfRenderWindow_resetGLStates", dynlib: LibG.}
+proc capture*(window: PRenderWindow): PImage {.
+  cdecl, importc: "sfRenderWindow_capture", dynlib: LibG.}
+
+#Construct a new render texture
+proc newRenderTexture*(width, height: cint; depthBuffer: Bool): PRenderTexture {.
+  cdecl, importc: "sfRenderTexture_create", dynlib: LibG.}
+#Destroy an existing render texture
+proc destroy*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_destroy", dynlib: LibG.}
+#Get the size of the rendering region of a render texture
+proc getSize*(renderTexture: PRenderTexture): TVector2i {.
+  cdecl, importc: "sfRenderTexture_getSize", dynlib: LibG.}
+#Activate or deactivate a render texture as the current target for rendering
+proc setActive*(renderTexture: PRenderTexture; active: bool): bool{.
+  cdecl, importc: "sfRenderTexture_setActive", dynlib: LibG.}
+#Update the contents of the target texture
+proc display*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_display", dynlib: LibG.}
+#Clear the rendertexture with the given color
+proc clear*(renderTexture: PRenderTexture; color: TColor){.
+  cdecl, importc: "sfRenderTexture_clear", dynlib: LibG.}
+#Change the current active view of a render texture
+proc setView*(renderTexture: PRenderTexture; view: PView){.
+  cdecl, importc: "sfRenderTexture_setView", dynlib: LibG.}
+#Get the current active view of a render texture
+proc getView*(renderTexture: PRenderTexture): PView{.
+  cdecl, importc: "sfRenderTexture_getView", dynlib: LibG.}
+#Get the default view of a render texture
+proc getDefaultView*(renderTexture: PRenderTexture): PView{.
+  cdecl, importc: "sfRenderTexture_getDefaultView", dynlib: LibG.}
+#Get the viewport of a view applied to this target
+proc getViewport*(renderTexture: PRenderTexture; view: PView): TIntRect{.
+  cdecl, importc: "sfRenderTexture_getViewport", dynlib: LibG.}
+#Convert a point in texture coordinates into view coordinates
+proc convertCoords*(renderTexture: PRenderTexture; point: TVector2i; targetView: PView): TVector2f{.
+  cdecl, importc: "sfRenderTexture_convertCoords", dynlib: LibG.}
+#Draw a drawable object to the render-target
+proc draw*(renderTexture: PRenderTexture; sprite: PSprite; states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawSprite", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; text: PText; states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawText", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; shape: PShape; states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawShape", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; shape: PCircleShape; 
+            states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawCircleShape", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; shape: PConvexShape; 
+            states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawConvexShape", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; shape: PRectangleShape; 
+            states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawRectangleShape", dynlib: LibG.}
+proc draw*(renderTexture: PRenderTexture; va: PVertexArray; 
+            states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawVertexArray", dynlib: LibG.}
+#Draw primitives defined by an array of vertices to a render texture
+proc draw*(renderTexture: PRenderTexture; vertices: PVertex; vertexCount: cint; 
+            primitiveType: TPrimitiveType; states: PRenderStates){.
+  cdecl, importc: "sfRenderTexture_drawPrimitives", dynlib: LibG.}
+#Save the current OpenGL render states and matrices
+#/
+#/ This function can be used when you mix SFML drawing
+#/ and direct OpenGL rendering. Combined with popGLStates,
+#/ it ensures that:
+#/ * SFML's internal states are not messed up by your OpenGL code
+#/ * your OpenGL states are not modified by a call to a SFML function
+#/
+#/ Note that this function is quite expensive: it saves all the
+#/ possible OpenGL states and matrices, even the ones you
+#/ don't care about. Therefore it should be used wisely.
+#/ It is provided for convenience, but the best results will
+#/ be achieved if you handle OpenGL states yourself (because
+#/ you know which states have really changed, and need to be
+#/ saved and restored). Take a look at the resetGLStates
+#/ function if you do so.
+proc pushGLStates*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_pushGLStates", dynlib: LibG.}
+#Restore the previously saved OpenGL render states and matrices
+#/
+#/ See the description of pushGLStates to get a detailed
+#/ description of these functions.
+proc popGLStates*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_popGLStates", dynlib: LibG.}
+#Reset the internal OpenGL states so that the target is ready for drawing
+#/
+#/ This function can be used when you mix SFML drawing
+#/ and direct OpenGL rendering, if you choose not to use
+#/ pushGLStates/popGLStates. It makes sure that all OpenGL
+#/ states needed by SFML are set, so that subsequent sfRenderTexture_draw*()
+#/ calls will work as expected.
+proc resetGLStates*(renderTexture: PRenderTexture){.
+  cdecl, importc: "sfRenderTexture_resetGLStates", dynlib: LibG.}
+#Get the target texture of a render texture
+proc getTexture*(renderTexture: PRenderTexture): PTexture{.
+  cdecl, importc: "sfRenderTexture_getTexture", dynlib: LibG.}
+#Enable or disable the smooth filter on a render texture
+proc setSmooth*(renderTexture: PRenderTexture; smooth: bool){.
+  cdecl, importc: "sfRenderTexture_setSmooth", dynlib: LibG.}
+#Tell whether the smooth filter is enabled or not for a render texture
+proc isSmooth*(renderTexture: PRenderTexture): bool {.
+  cdecl, importc: "sfRenderTexture_isSmooth", dynlib: LibG.}
+
+proc intRect*(left, top, width, height: cint): TIntRect =
+  result.left   = left
+  result.top    = top
+  result.width  = width
+  result.height = height
+proc floatRect*(left, top, width, height: cfloat): TFloatRect =
+  result.left   = left
+  result.top    = top 
+  result.width  = width
+  result.height = height
+proc contains*(rect: PFloatRect, x, y: cfloat): bool {.
+  cdecl, importc: "sfFloatRect_contains", dynlib: LibG.}
+proc contains*(rect: PIntRect, x: cint, y: cint): bool{.cdecl, 
+  importc: "sfIntRect_contains", dynlib: LibG.}
+proc intersects*(rect1, rect2, intersection: PFloatRect): bool {.
+  cdecl, importc: "sfFloatRect_intersects", dynlib: LibG.}
+proc intersects*(rect1, rect2, intersection: PIntRect): bool {.
+  cdecl, importc: "sfIntRect_intersects", dynlib: LibG.}
+
+proc newFont*(filename: cstring): PFont {.
+  cdecl, importc: "sfFont_createFromFile", dynlib: LibG.}
+proc newFont*(data: pointer, sizeInBytes: cint): PFont {.
+  cdecl, importc: "sfFont_createFromMemory", dynlib: LibG.}
+proc newFont*(stream: PInputStream): PFont {.
+  cdecl, importc: "sfFont_createFromStream", dynlib: LibG.}
+proc copy*(font: PFont): PFont {.
+  cdecl, importc: "sfFont_copy", dynlib: LibG.}
+proc destroy*(font: PFont) {.
+  cdecl, importc: "sfFont_destroy", dynlib: LibG.}
+proc getGlyph*(font: PFont, codePoint: Uint32, characterSize: cint, bold: bool): TGlyph{.
+  cdecl, importc: "sfFont_getGlyph", dynlib: LibG.}
+proc getKerning*(font: PFont, first: Uint32, second: Uint32, characterSize: cint): cint {.
+  cdecl, importc: "sfFont_getKerning", dynlib: LibG.}
+proc getLineSpacing*(font: PFont, characterSize: cint): cint {.
+  cdecl, importc: "sfFont_getLineSpacing", dynlib: LibG.}
+proc getTexture*(font: PFont, characterSize: cint): PTexture {.
+  cdecl, importc: "sfFont_getTexture", dynlib: LibG.}
+#getDefaultFont() has been removed from CSFML
+proc getDefaultFont*(): PFont {.
+  error, cdecl, importc: "sfFont_getDefaultFont", dynlib: LibG.}
+
+proc newCircleShape*(): PCircleShape {.
+  cdecl, importc: "sfCircleShape_create", dynlib: LibG.}
+proc copy*(shape: PCircleShape): PCircleShape {.
+  cdecl, importc: "sfCircleShape_copy", dynlib: LibG.}
+proc destroy*(shape: PCircleShape) {.
+  cdecl, importc: "sfCircleShape_destroy", dynlib: LibG.}
+proc setPosition*(shape: PCircleShape, position: TVector2f) {.
+  cdecl, importc: "sfCircleShape_setPosition", dynlib: LibG.}
+proc setRotation*(shape: PCircleShape, angle: cfloat) {.
+  cdecl, importc: "sfCircleShape_setRotation", dynlib: LibG.}
+proc setScale*(shape: PCircleShape, scale: TVector2f) {.
+  cdecl, importc: "sfCircleShape_setScale", dynlib: LibG.}
+proc setOrigin*(shape: PCircleShape, origin: TVector2f) {.
+  cdecl, importc: "sfCircleShape_setOrigin", dynlib: LibG.}
+proc getPosition*(shape: PCircleShape): TVector2f {.
+  cdecl, importc: "sfCircleShape_getPosition", dynlib: LibG.}
+proc getRotation*(shape: PCircleShape): cfloat {.
+  cdecl, importc: "sfCircleShape_getRotation", dynlib: LibG.}
+proc getScale*(shape: PCircleShape): TVector2f {.
+  cdecl, importc: "sfCircleShape_getScale", dynlib: LibG.}
+proc getOrigin*(shape: PCircleShape): TVector2f {.
+  cdecl, importc: "sfCircleShape_getOrigin", dynlib: LibG.}
+proc move*(shape: PCircleShape, offset: TVector2f) {.
+  cdecl, importc: "sfCircleShape_move", dynlib: LibG.}
+proc rotate*(shape: PCircleShape, angle: cfloat){.
+  cdecl, importc: "sfCircleShape_rotate", dynlib: LibG.}
+proc scale*(shape: PCircleShape, factors: TVector2f) {.
+  cdecl, importc: "sfCircleShape_scale", dynlib: LibG.}
+proc getTransform*(shape: PCircleShape): TTransform {.
+  cdecl, importc: "sfCircleShape_getTransform", dynlib: LibG.}
+proc getInverseTransform*(shape: PCircleShape): TTransform {.
+  cdecl, importc: "sfCircleShape_getInverseTransform", dynlib: LibG.}
+proc setTexture*(shape: PCircleShape, texture: PTexture, resetRect: bool) {.
+  cdecl, importc: "sfCircleShape_setTexture", dynlib: LibG.}
+proc setTextureRect*(shape: PCircleShape, rect: TIntRect) {.
+  cdecl, importc: "sfCircleShape_setTextureRect", dynlib: LibG.}
+proc setFillColor*(shape: PCircleShape, color: TColor) {.
+  cdecl, importc: "sfCircleShape_setFillColor", dynlib: LibG.}
+proc setOutlineColor*(shape: PCircleShape, color: TColor) {.
+  cdecl, importc: "sfCircleShape_setOutlineColor", dynlib: LibG.}
+proc setOutlineThickness*(shape: PCircleShape, thickness: cfloat) {.
+  cdecl, importc: "sfCircleShape_setOutlineThickness", dynlib: LibG.}
+proc getTexture*(shape: PCircleShape): PTexture {.
+  cdecl, importc: "sfCircleShape_getTexture", dynlib: LibG.}
+proc getTextureRect*(shape: PCircleShape): TIntRect {.
+  cdecl, importc: "sfCircleShape_getTextureRect", dynlib: LibG.}
+proc getFillColor*(shape: PCircleShape): TColor {.
+  cdecl, importc: "sfCircleShape_getFillColor", dynlib: LibG.}
+proc getOutlineColor*(shape: PCircleShape): TColor {.
+  cdecl, importc: "sfCircleShape_getOutlineColor", dynlib: LibG.}
+proc getOutlineThickness*(shape: PCircleShape): cfloat {.
+  cdecl, importc: "sfCircleShape_getOutlineThickness", dynlib: LibG.}
+proc getPointCount*(shape: PCircleShape): cint {.
+  cdecl, importc: "sfCircleShape_getPointCount", dynlib: LibG.}
+proc getPoint*(shape: PCircleShape, index: cint): TVector2f {.
+  cdecl, importc: "sfCircleShape_getPoint", dynlib: LibG.}
+proc setRadius*(shape: PCircleShape, radius: cfloat) {.
+  cdecl, importc: "sfCircleShape_setRadius", dynlib: LibG.}
+proc getRadius*(shape: PCircleShape): cfloat {.
+  cdecl, importc: "sfCircleShape_getRadius", dynlib: LibG.}
+proc setPointCount*(shape: PCircleShape, count: cint) {.
+  cdecl, importc: "sfCircleShape_setPointCount", dynlib: LibG.}
+proc getLocalBounds*(shape: PCircleShape): TFloatRect {.
+  cdecl, importc: "sfCircleShape_getLocalBounds", dynlib: LibG.}
+proc getGlobalBounds*(shape: PCircleShape): TFloatRect {.
+  cdecl, importc: "sfCircleShape_getGlobalBounds", dynlib: LibG.}
+
+proc newRectangleShape*(): PRectangleShape {.
+  cdecl, importc: "sfRectangleShape_create", dynlib: LibG.}
+proc copy*(shape: PRectangleShape): PRectangleShape {.
+  cdecl, importc: "sfRectangleShape_copy", dynlib: LibG.}
+proc destroy*(shape: PRectangleShape){.
+  cdecl, importc: "sfRectangleShape_destroy", dynlib: LibG.}
+proc setPosition*(shape: PRectangleShape, position: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_setPosition", dynlib: LibG.}
+proc setRotation*(shape: PRectangleShape, angle: cfloat) {.
+  cdecl, importc: "sfRectangleShape_setRotation", dynlib: LibG.}
+proc setScale*(shape: PRectangleShape, scale: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_setScale", dynlib: LibG.}
+proc setOrigin*(shape: PRectangleShape, origin: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_setOrigin", dynlib: LibG.}
+proc getPosition*(shape: PRectangleShape): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getPosition", dynlib: LibG.}
+proc getRotation*(shape: PRectangleShape): cfloat {.
+  cdecl, importc: "sfRectangleShape_getRotation", dynlib: LibG.}
+proc getScale*(shape: PRectangleShape): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getScale", dynlib: LibG.}
+proc getOrigin*(shape: PRectangleShape): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getOrigin", dynlib: LibG.}
+proc move*(shape: PRectangleShape, offset: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_move", dynlib: LibG.}
+proc rotate*(shape: PRectangleShape, angle: cfloat) {.
+  cdecl, importc: "sfRectangleShape_rotate", dynlib: LibG.}
+proc scale*(shape: PRectangleShape, factors: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_scale", dynlib: LibG.}
+proc getTransform*(shape: PRectangleShape): TTransform {.
+  cdecl, importc: "sfRectangleShape_getTransform", dynlib: LibG.}
+proc getInverseTransform*(shape: PRectangleShape): TTransform {.
+  cdecl, importc: "sfRectangleShape_getInverseTransform", dynlib: LibG.}
+proc setTexture*(shape: PRectangleShape, texture: PTexture, resetRect: bool) {.
+  cdecl, importc: "sfRectangleShape_setTexture", dynlib: LibG.}
+proc setTextureRect*(shape: PRectangleShape, rect: TIntRect) {.
+  cdecl, importc: "sfRectangleShape_setTextureRect", dynlib: LibG.}
+proc setFillColor*(shape: PRectangleShape, color: TColor) {.
+  cdecl, importc: "sfRectangleShape_setFillColor", dynlib: LibG.}
+proc setOutlineColor*(shape: PRectangleShape, color: TColor) {.
+  cdecl, importc: "sfRectangleShape_setOutlineColor", dynlib: LibG.}
+proc setOutlineThickness*(shape: PRectangleShape, thickness: cfloat) {.
+  cdecl, importc: "sfRectangleShape_setOutlineThickness", dynlib: LibG.}
+proc getTexture*(shape: PRectangleShape): PTexture {.
+  cdecl, importc: "sfRectangleShape_getTexture", dynlib: LibG.}
+proc getTextureRect*(shape: PRectangleShape): TIntRect {.
+  cdecl, importc: "sfRectangleShape_getTextureRect", dynlib: LibG.}
+proc getFillColor*(shape: PRectangleShape): TColor {.
+  cdecl, importc: "sfRectangleShape_getFillColor", dynlib: LibG.}
+proc getOutlineColor*(shape: PRectangleShape): TColor {.
+  cdecl, importc: "sfRectangleShape_getOutlineColor", dynlib: LibG.}
+proc getOutlineThickness*(shape: PRectangleShape): cfloat {.
+  cdecl, importc: "sfRectangleShape_getOutlineThickness", dynlib: LibG.}
+proc getPointCount*(shape: PRectangleShape): cint {.
+  cdecl, importc: "sfRectangleShape_getPointCount", dynlib: LibG.}
+proc getPoint*(shape: PRectangleShape, index: cint): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getPoint", dynlib: LibG.}
+proc setSize*(shape: PRectangleShape, size: TVector2f) {.
+  cdecl, importc: "sfRectangleShape_setSize", dynlib: LibG.}
+proc getSize*(shape: PRectangleShape): TVector2f {.
+  cdecl, importc: "sfRectangleShape_getSize", dynlib: LibG.}
+proc getLocalBounds*(shape: PRectangleShape): TFloatRect {.
+  cdecl, importc: "sfRectangleShape_getLocalBounds", dynlib: LibG.}
+proc getGlobalBounds*(shape: PRectangleShape): TFloatRect {.
+  cdecl, importc: "sfRectangleShape_getGlobalBounds", dynlib: LibG.}
+
+
+proc newView*(): PView {.
+  cdecl, importc: "sfView_create", dynlib: LibG.}
+proc viewFromRect*(rectangle: TFloatRect): PView{.
+  cdecl, importc: "sfView_createFromRect", dynlib: LibG.}
+proc copy*(view: PView): PView {.
+  cdecl, importc: "sfView_copy", dynlib: LibG.}
+proc destroy*(view: PView) {.
+  cdecl, importc: "sfView_destroy", dynlib: LibG.}
+proc setCenter*(view: PView, center: TVector2f) {.
+  cdecl, importc: "sfView_setCenter", dynlib: LibG.}
+proc setSize*(view: PView, size: TVector2f) {.
+  cdecl, importc: "sfView_setSize", dynlib: LibG.}
+proc setRotation*(view: PView, angle: cfloat) {.
+  cdecl, importc: "sfView_setRotation", dynlib: LibG.}
+proc setViewport*(view: PView, viewport: TFloatRect) {.
+  cdecl, importc: "sfView_setViewport", dynlib: LibG.}
+proc reset*(view: PView, rectangle: TFloatRect) {.
+  cdecl, importc: "sfView_reset", dynlib: LibG.}
+proc getCenter*(view: PView): TVector2f {.
+  cdecl, importc: "sfView_getCenter", dynlib: LibG.}
+proc getSize*(view: PView): TVector2f {.
+  cdecl, importc: "sfView_getSize", dynlib: LibG.}
+proc getRotation*(view: PView): cfloat {.
+  cdecl, importc: "sfView_getRotation", dynlib: LibG.}
+proc getViewport*(view: PView): TFloatRect {.
+  cdecl, importc: "sfView_getViewport", dynlib: LibG.}
+proc move*(view: PView, offset: TVector2f) {.
+  cdecl, importc: "sfView_move", dynlib: LibG.}
+proc rotate*(view: PView, angle: cfloat) {.
+  cdecl, importc: "sfView_rotate", dynlib: LibG.}
+proc zoom*(view: PView, factor: cfloat) {.
+  cdecl, importc: "sfView_zoom", dynlib: LibG.}
+
+proc newImage*(width, height: cint): PImage {.
+  cdecl, importc: "sfImage_create", dynlib: LibG.}
+proc newImage*(width, height: cint, color: TColor): PImage {.
+  cdecl, importc: "sfImage_createFromColor", dynlib: LibG.}
+proc newImage*(width, height: cint, pixels: pointer): PImage {. ##same deal as setIcon()
+  cdecl, importc: "sfImage_createFromPixels", dynlib: LibG.}
+proc newImage*(filename: cstring): PImage {.
+  cdecl, importc: "sfImage_createFromFile", dynlib: LibG.}
+proc newImage*(data: pointer, size: cint): PImage {.
+  cdecl, importc: "sfImage_createFromMemory", dynlib: LibG.}
+proc newImage*(stream: PInputStream): PImage {.
+  cdecl, importc: "sfImage_createFromStream", dynlib: LibG.}
+proc copy*(image: PImage): PImage {.
+  cdecl, importc: "sfImage_copy", dynlib: LibG.}
+proc destroy*(image: PImage) {.
+  cdecl, importc: "sfImage_destroy", dynlib: LibG.}
+proc save*(image: PImage, filename: cstring): bool {.
+  cdecl, importc: "sfImage_saveToFile", dynlib: LibG.}
+proc getSize*(image: PImage): TVector2i {.
+  cdecl, importc: "sfImage_getSize", dynlib: LibG.}
+proc createMask*(image: PImage, color: TColor, alpha: cchar) {.
+  cdecl, importc: "sfImage_createMaskFromColor", dynlib: LibG.}
+proc copy*(destination, source: PImage, destX, destY: cint;
+            sourceRect: TIntRect, applyAlpha: bool) {.
+  cdecl, importc: "sfImage_copyImage", dynlib: LibG.}
+proc setPixel*(image: PImage, x, y: cint, color: TColor) {.
+  cdecl, importc: "sfImage_setPixel", dynlib: LibG.}
+proc getPixel*(image: PImage, x, y: cint): TColor {.
+  cdecl, importc: "sfImage_getPixel", dynlib: LibG.}
+proc getPixels*(image: PImage): pointer {.
+  cdecl, importc: "sfImage_getPixelsPtr", dynlib: LibG.}
+proc flipHorizontally*(image: PImage) {.
+  cdecl, importc: "sfImage_flipHorizontally", dynlib: LibG.}
+proc flipVertically*(image: PImage) {.
+  cdecl, importc: "sfImage_flipVertically", dynlib: LibG.}
+
+proc newSprite*(): PSprite {.
+  cdecl, importc: "sfSprite_create", dynlib: LibG.}
+proc copy*(sprite: PSprite): PSprite {.
+  cdecl, importc: "sfSprite_copy", dynlib: LibG.}
+proc destroy*(sprite: PSprite) {.
+  cdecl, importc: "sfSprite_destroy", dynlib: LibG.}
+proc setPosition*(sprite: PSprite, position: TVector2f) {.
+  cdecl, importc: "sfSprite_setPosition", dynlib: LibG.}
+proc setRotation*(sprite: PSprite, angle: cfloat) {.
+  cdecl, importc: "sfSprite_setRotation", dynlib: LibG.}
+proc setScale*(sprite: PSprite, scale: TVector2f) {.
+  cdecl, importc: "sfSprite_setScale", dynlib: LibG.}
+proc setOrigin*(sprite: PSprite, origin: TVector2f) {.
+  cdecl, importc: "sfSprite_setOrigin", dynlib: LibG.}
+proc getPosition*(sprite: PSprite): TVector2f {.
+  cdecl, importc: "sfSprite_getPosition", dynlib: LibG.}
+proc getRotation*(sprite: PSprite): cfloat {.
+  cdecl, importc: "sfSprite_getRotation", dynlib: LibG.}
+proc getScale*(sprite: PSprite): TVector2f {.
+  cdecl, importc: "sfSprite_getScale", dynlib: LibG.}
+proc getOrigin*(sprite: PSprite): TVector2f {.
+  cdecl, importc: "sfSprite_getOrigin", dynlib: LibG.}
+proc move*(sprite: PSprite, offset: TVector2f) {.
+  cdecl, importc: "sfSprite_move", dynlib: LibG.}
+proc rotate*(sprite: PSprite, angle: cfloat) {.
+  cdecl, importc: "sfSprite_rotate", dynlib: LibG.}
+proc scale*(sprite: PSprite, factor: TVector2f) {.
+  cdecl, importc: "sfSprite_scale", dynlib: LibG.}
+proc getTransform*(sprite: PSprite): TTransform {.
+  cdecl, importc: "sfSprite_getTransform", dynlib: LibG.}
+proc getInverseTransform*(sprite: PSprite): TTransform {.
+  cdecl, importc: "sfSprite_getInverseTransform", dynlib: LibG.}
+proc setTexture*(sprite: PSprite, texture: PTexture, resetRect: bool) {.
+  cdecl, importc: "sfSprite_setTexture", dynlib: LibG.}
+proc setTextureRect*(sprite: PSprite, rectangle: TIntRect) {.
+  cdecl, importc: "sfSprite_setTextureRect", dynlib: LibG.}
+proc setColor*(sprite: PSprite, color: TColor) {.
+  cdecl, importc: "sfSprite_setColor", dynlib: LibG.}
+proc getTexture*(sprite: PSprite): TTexture {.
+  cdecl, importc: "sfSprite_getTexture", dynlib: LibG.}
+proc getTextureRect*(sprite: PSprite): TIntRect {.
+  cdecl, importc: "sfSprite_getTextureRect", dynlib: LibG.}
+proc getColor*(sprite: PSprite): TColor {.
+  cdecl, importc: "sfSprite_getColor", dynlib: LibG.}
+proc getLocalBounds*(sprite: PSprite): TFloatRect {.
+  cdecl, importc: "sfSprite_getLocalBounds", dynlib: LibG.}
+proc getGlobalBounds*(sprite: PSprite): TFloatRect {.
+  cdecl, importc: "sfSprite_getGlobalBounds", dynlib: LibG.}
+
+proc newTexture*(width, height: cint): PTexture {.
+  cdecl, importc: "sfTexture_create", dynlib: LibG.}
+proc newTexture*(filename: cstring): PTexture {.
+  cdecl, importc: "sfTexture_createFromFile", dynlib: LibG.}
+proc newTexture*(data: pointer, size: cint, area: PIntRect): PTexture {.
+  cdecl, importc: "sfTexture_createFromMemory", dynlib: LibG.}
+proc newTexture*(stream: PInputStream, area: PIntRect): PTexture {.
+  cdecl, importc: "sfTexture_createFromStream", dynlib: LibG.}
+proc newTexture*(image: PImage, area: PIntRect = nil): PTexture {.
+  cdecl, importc: "sfTexture_createFromImage", dynlib: LibG.}
+proc copy*(texture: PTexture): PTexture {.
+  cdecl, importc: "sfTexture_copy", dynlib: LibG.}
+proc destroy*(texture: PTexture) {.
+  cdecl, importc: "sfTexture_destroy", dynlib: LibG.}
+proc getSize*(texture: PTexture): TVector2i {.
+  cdecl, importc: "sfTexture_getSize", dynlib: LibG.}
+proc copyToImage*(texture: PTexture): PImage {.
+  cdecl, importc: "sfTexture_copyToImage", dynlib: LibG.}
+proc updateFromPixels*(texture: PTexture, pixels: pointer, width, height, x, y: cint) {.
+  cdecl, importc: "sfTexture_updateFromPixels", dynlib: LibG.}
+proc updateFromImage*(texture: PTexture, image: PImage, x, y: cint) {.
+  cdecl, importc: "sfTexture_updateFromImage", dynlib: LibG.}
+proc updateFromWindow*(texture: PTexture, window: PWindow, x, y: cint) {.
+  cdecl, importc: "sfTexture_updateFromWindow", dynlib: LibG.}
+proc updateFromWindow*(texture: PTexture, window: PRenderWindow, x, y: cint) {.
+  cdecl, importc: "sfTexture_updateFromRenderWindow", dynlib: LibG.}
+proc bindGL*(texture: PTexture) {.
+  cdecl, importc: "sfTexture_bind", dynlib: LibG.}
+proc setSmooth*(texture: PTexture, smooth: bool) {.
+  cdecl, importc: "sfTexture_setSmooth", dynlib: LibG.}
+proc isSmooth*(texture: PTexture): bool {.
+  cdecl, importc: "sfTexture_isSmooth", dynlib: LibG.}
+proc setRepeated*(texture: PTexture, repeated: bool) {.
+  cdecl, importc: "sfTexture_setRepeated", dynlib: LibG.}
+proc isRepeated*(texture: PTexture): bool {.
+  cdecl, importc: "sfTexture_isRepeated", dynlib: LibG.}
+proc textureMaxSize*(): cint {.
+  cdecl, importc: "sfTexture_getMaximumSize", dynlib: LibG.}
+
+proc newVertexArray*(): PVertexArray {.
+  cdecl, importc: "sfVertexArray_create", dynlib: LibG.}
+proc copy*(vertexArray: PVertexArray): PVertexArray {.
+  cdecl, importc: "sfVertexArray_copy", dynlib: LibG.}
+proc destroy*(va: PVertexArray) {.
+  cdecl, importc: "sfVertexArray_destroy", dynlib: LibG.}
+proc getVertexCount*(va: PVertexArray): cint {.
+  cdecl, importc: "sfVertexArray_getVertexCount", dynlib: LibG.}
+proc getVertex*(va: PVertexArray, index: cint): PVertex {.
+  cdecl, importc: "sfVertexArray_getVertex", dynlib: LibG.}
+proc clear*(va: PVertexArray) {.
+  cdecl, importc: "sfVertexArray_clear", dynlib: LibG.}
+proc resize*(va: PVertexArray, size: cint) {.
+  cdecl, importc: "sfVertexArray_resize", dynlib: LibG.}
+proc append*(va: PVertexArray, vertex: TVertex) {.
+  cdecl, importc: "sfVertexArray_append", dynlib: LibG.}
+proc setPrimitiveType*(va: PVertexArray, primitiveType: TPrimitiveType) {.
+  cdecl, importc: "sfVertexArray_setPrimitiveType", dynlib: LibG.}
+proc getPrimitiveType*(va: PVertexArray): TPrimitiveType {.
+  cdecl, importc: "sfVertexArray_getPrimitiveType", dynlib: LibG.}
+proc getBounds*(va: PVertexArray): TFloatRect {.
+  cdecl, importc: "sfVertexArray_getBounds", dynlib: LibG.}
+
+
+proc newText*(): PText {.
+  cdecl, importc: "sfText_create", dynlib: LibG.}
+proc copy*(text: PText): PText {.
+  cdecl, importc: "sfText_copy", dynlib: LibG.}
+proc destroy*(text: PText) {.
+  cdecl, importc: "sfText_destroy", dynlib: LibG.}
+proc setPosition*(text: PText, position: TVector2f) {.
+  cdecl, importc: "sfText_setPosition", dynlib: LibG.}
+proc setRotation*(text: PText, angle: cfloat) {.
+  cdecl, importc: "sfText_setRotation", dynlib: LibG.}
+proc setScale*(text: PText, scale: TVector2f) {.
+  cdecl, importc: "sfText_setScale", dynlib: LibG.}
+proc setOrigin*(text: PText, origin: TVector2f) {.
+  cdecl, importc: "sfText_setOrigin", dynlib: LibG.}
+proc getPosition*(text: PText): TVector2f {.
+  cdecl, importc: "sfText_getPosition", dynlib: LibG.}
+proc getRotation*(text: PText): cfloat {.
+  cdecl, importc: "sfText_getRotation", dynlib: LibG.}
+proc getScale*(text: PText): TVector2f {.
+  cdecl, importc: "sfText_getScale", dynlib: LibG.}
+proc getOrigin*(text: PText): TVector2f {.
+  cdecl, importc: "sfText_getOrigin", dynlib: LibG.}
+proc move*(text: PText, offset: TVector2f) {.
+  cdecl, importc: "sfText_move", dynlib: LibG.}
+proc rotate*(text: PText, angle: cfloat) {.
+  cdecl, importc: "sfText_rotate", dynlib: LibG.}
+proc scale*(text: PText, factors: TVector2f) {.
+  cdecl, importc: "sfText_scale", dynlib: LibG.}
+proc getTransform*(text: PText): TTransform {.
+  cdecl, importc: "sfText_getTransform", dynlib: LibG.}
+proc getInverseTransform*(text: PText): TTransform {.
+  cdecl, importc: "sfText_getInverseTransform", dynlib: LibG.}
+proc setString*(text: PText, string: cstring) {.
+  cdecl, importc: "sfText_setString", dynlib: LibG.}
+proc setUnicodeString*(text: PText, string: ptr Uint32) {.
+  cdecl, importc: "sfText_setUnicodeString", dynlib: LibG.}
+proc setFont*(text: PText, font: PFont) {.
+  cdecl, importc: "sfText_setFont", dynlib: LibG.}
+proc setCharacterSize*(text: PText, size: cint) {.
+  cdecl, importc: "sfText_setCharacterSize", dynlib: LibG.}
+proc setStyle*(text: PText, style: TTextStyle) {.
+  cdecl, importc: "sfText_setStyle", dynlib: LibG.}
+proc setColor*(text: PText, color: TColor) {.
+  cdecl, importc: "sfText_setColor", dynlib: LibG.}
+proc getString*(text: PText): cstring {.
+  cdecl, importc: "sfText_getString", dynlib: LibG.}
+proc getUnicodeString*(text: PText): ptr Uint32 {.cdecl, 
+  importc: "sfText_getUnicodeString", dynlib: LibG.}
+proc getFont*(text: PText): PFont {.
+  cdecl, importc: "sfText_getFont", dynlib: LibG.}
+proc getCharacterSize*(text: PText): cint {.
+  cdecl, importc: "sfText_getCharacterSize", dynlib: LibG.}
+proc getStyle*(text: PText): Uint32 {.
+  cdecl, importc: "sfText_getStyle", dynlib: LibG.}
+proc getColor*(text: PText): TColor {.
+  cdecl, importc: "sfText_getColor", dynlib: LibG.}
+proc findCharacterPos*(text: PText, index: cint): TVector2f {.
+  cdecl, importc: "sfText_findCharacterPos", dynlib: LibG.}
+proc getLocalBounds*(text: PText): TFloatRect {.
+  cdecl, importc: "sfText_getLocalBounds", dynlib: LibG.}
+proc getGlobalBounds*(text: PText): TFloatRect {.
+  cdecl, importc: "sfText_getGlobalBounds", dynlib: LibG.}
+
+proc transformFromMatrix*(a00, a01, a02, a10, a11, a12, a20, a21, a22: cfloat): TTransform {.
+  cdecl, importc: "sfTransform_fromMatrix", dynlib: LibG.}
+proc getMatrix*(transform: PTransform, matrix: ptr cfloat) {.
+  cdecl, importc: "sfTransform_getMatrix", dynlib: LibG.}
+proc getInverse*(transform: PTransform): TTransform {.
+  cdecl, importc: "sfTransform_getInverse", dynlib: LibG.}
+proc transformPoint*(transform: PTransform, point: TVector2f): TVector2f {.
+  cdecl, importc: "sfTransform_transformPoint", dynlib: LibG.}
+proc transformRect*(transform: PTransform, rectangle: TFloatRect): TFloatRect {.
+  cdecl, importc: "sfTransform_transformRect", dynlib: LibG.}
+proc combine*(transform: PTransform, other: PTransform) {.
+  cdecl, importc: "sfTransform_combine", dynlib: LibG.}
+proc translate*(transform: PTransform, x, y: cfloat) {.
+  cdecl, importc: "sfTransform_translate", dynlib: LibG.}
+proc rotate*(transform: PTransform, angle: cfloat) {.
+  cdecl, importc: "sfTransform_rotate", dynlib: LibG.}
+proc rotateWithCenter*(transform: PTransform, angle, centerX, centerY: cfloat){.
+  cdecl, importc: "sfTransform_rotateWithCenter", dynlib: LibG.}
+proc scale*(transform: PTransform, scaleX, scaleY: cfloat) {.
+  cdecl, importc: "sfTransform_scale", dynlib: LibG.}
+proc scaleWithCenter*(transform: PTransform, scaleX, scaleY, centerX, centerY: cfloat) {.
+  cdecl, importc: "sfTransform_scaleWithCenter", dynlib: LibG.}
+let IdentityMatrix*: TTransform = transformFromMatrix(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0)
+
+
+proc newShader*(VSfilename: cstring, fragmentShaderFilename: cstring): PShader {.
+  cdecl, importc: "sfShader_createFromFile", dynlib: LibG.}
+proc newShaderFromStr*(vertexShader: cstring, fragmentShader: cstring): PShader {.
+  cdecl, importc: "sfShader_createFromMemory", dynlib: LibG.}
+proc newShader*(vertexShaderStream: PInputStream, fragmentShaderStream: PInputStream): PShader {.
+  cdecl, importc: "sfShader_createFromStream", dynlib: LibG.}
+proc destroy*(shader: PShader) {.
+  cdecl, importc: "sfShader_destroy", dynlib: LibG.}
+proc setFloatParameter*(shader: PShader, name: cstring, x: cfloat) {.
+  cdecl, importc: "sfShader_setFloatParameter", dynlib: LibG.}
+proc setFloat2Parameter*(shader: PShader, name: cstring, x, y: cfloat) {.
+  cdecl, importc: "sfShader_setFloat2Parameter", dynlib: LibG.}
+proc setFloat3Parameter*(shader: PShader, name: cstring, x, y, z: cfloat) {.
+  cdecl, importc: "sfShader_setFloat3Parameter", dynlib: LibG.}
+proc setFloat4Parameter*(shader: PShader, name: cstring, x, y, z, w: cfloat) {.
+  cdecl, importc: "sfShader_setFloat4Parameter", dynlib: LibG.}
+proc setVector2Parameter*(shader: PShader, name: cstring, vector: TVector2f) {.
+  cdecl, importc: "sfShader_setVector2Parameter", dynlib: LibG.}
+proc setVector3Parameter*(shader: PShader, name: cstring, vector: TVector3f) {.
+  cdecl, importc: "sfShader_setVector3Parameter", dynlib: LibG.}
+proc setColorParameter*(shader: PShader, name: cstring, color: TColor) {.
+  cdecl, importc: "sfShader_setColorParameter", dynlib: LibG.}
+proc setTransformParameter*(shader: PShader, name: cstring, transform: TTransform) {.
+  cdecl, importc: "sfShader_setTransformParameter", dynlib: LibG.}
+proc setTextureParameter*(shader: PShader, name: cstring, texture: PTexture) {.
+  cdecl, importc: "sfShader_setTextureParameter", dynlib: LibG.}
+proc setCurrentTextureParameter*(shader: PShader, name: cstring) {.
+  cdecl, importc: "sfShader_setCurrentTextureParameter", dynlib: LibG.}
+proc bindGL*(shader: PShader) {.
+  cdecl, importc: "sfShader_bind", dynlib: LibG.}
+proc unbindGL*(shader: PShader) {.
+  cdecl, importc: "sfShader_unbind", dynlib: LibG.}
+proc shaderIsAvailable*(): bool {.
+  cdecl, importc: "sfShader_isAvailable", dynlib: LibG.}
+
+proc color*(red, green, blue: cchar): TColor {.
+  cdecl, importc: "sfColor_fromRGB", dynlib: LibG.}
+proc color*(red, green, blue: int): TColor {.inline.} =
+  return color(red.cchar, green.cchar, blue.cchar)
+proc color*(red, green, blue, alpha: cchar): TColor {.
+  cdecl, importc: "sfColor_fromRGBA", dynlib: LibG.}
+proc color*(red, green, blue, alpha: int): TColor {.inline.} =
+  return color(red.cchar, green.cchar, blue.cchar, alpha.cchar)
+proc `+`*(color1, color2: TColor): TColor {.
+  cdecl, importc: "sfColor_add", dynlib: LibG.}
+proc `*`*(color1, color2: TColor): TColor {.
+  cdecl, importc: "sfColor_modulate", dynlib: LibG.}
+proc newColor*(r,g,b: int): TColor {.inline.} =
+  return color(r,g,b)
+proc newColor*(r,g,b,a: int): TColor {.inline.} = 
+  return color(r,g,b,a)
+
+proc newClock*(): PClock {.
+  cdecl, importc: "sfClock_create", dynlib: LibS.}
+proc copy*(clocK: PClock): PClock {.
+  cdecl, importc: "sfClock_copy", dynlib: LibS.}
+proc destroy*(clock: PClock): PClock {.
+  cdecl, importc: "sfClock_destroy", dynlib: LibS.}
+proc getElapsedTime*(clock: PClock): TTime {.
+  cdecl, importc: "sfClock_getElapsedTime", dynlib: LibS.}
+proc restart*(clock: PClock): TTime {.
+  cdecl, importc: "sfClock_restart", dynlib: LibS, discardable.}
+proc asSeconds*(time: TTime): cfloat {.
+  cdecl, importc: "sfTime_asSeconds", dynlib: LibS.}
+proc asMilliseconds*(time: TTime): int32 {.
+  cdecl, importc: "sfTime_asMilliseconds", dynlib: LibS.}
+proc asMicroseconds*(time: TTime): int64 {.
+  cdecl, importc: "sfTime_asMicroseconds", dynlib: LibS.}
+proc seconds*(seconds: cfloat): TTime {.
+  cdecl, importc: "sfSeconds", dynlib: LibS.}
+proc milliseconds*(ms: int32): TTime {.
+  cdecl, importc: "sfMilliseconds", dynlib: LibS.}
+proc microseconds*(us: int64): TTime {.
+  cdecl, importc: "sfMicroseconds", dynlib: LibS.}
+
+proc newContextSettings*(depthBits: cint = 0,
+                         stencilBits: cint = 0,
+                         antialiasingLevel: cint = 0,
+                         majorVersion: cint = 0,
+                         minorVersion: cint = 0): TContextSettings =
+  result.depthBits = depthBits
+  result.stencilBits = stencilBits
+  result.antialiasingLevel = antialiasingLevel
+  result.majorVersion = majorVersion
+  result.minorVersion = minorVersion
+
+proc newCircleShape*(radius: cfloat; pointCount: cint = 30): PCircleShape = 
+  result = newCircleShape()
+  result.setRadius radius
+  result.setPointCount pointCount
+proc newText*(str: string, font: PFont, size: int): PText =
+  result = newText()
+  result.setString(str)
+  result.setFont(font)
+  result.setCharacterSize(size.cint)
+proc newVertexArray*(primitiveType: TPrimitiveType, vertexCount: cint = 0): PVertexArray =
+  result = newVertexArray()
+  result.setPrimitiveType(primitiveType)
+  if vertexCount != 0:
+    result.resize(vertexCount)
+proc videoMode*(width, height, bpp: cint): TVideoMode =
+  result.width = width
+  result.height = height
+  result.bitsPerPixel = bpp
+
+proc `[]`*(a: PVertexArray, index: int): PVertex =
+  return getVertex(a, index.cint)
+
+proc `$` *(a: TContextSettings): string =
+  return "<TContextSettings stencil=$1 aa=$2 major=$3 minor=$4 depth=$5>" % [
+    $a.stencilBits, $a.antialiasingLevel, $a.majorVersion, $a.minorVersion, $a.depthBits]
+proc `$` *(a: TVideoMode): string = 
+  return "<TVideoMode $1x$2 $3bpp>" % [$a.width, $a.height, $a.bitsPerPixel]
+proc `$` *(a: TFloatRect): string = 
+  return "<TFloatRect $1,$2 $3x$4>" % [$a.left, $a.top, $a.width, $a.height]
+proc `$` *(a: PView): string = 
+  return $a.getViewport()
+proc `$` *(a: TVector2f): string = 
+  return "<TVector2f $1,$2>" % [$a.x, $a.y]
+
+proc vec2i*(x, y: int): TVector2i =
+  result.x = x.cint
+  result.y = y.cint
+proc vec2f*(x, y: float): TVector2f =
+  result.x = x.cfloat
+  result.y = y.cfloat
+
+proc `+`*(a, b: TVector2f): TVector2f {.inline.} =
+  result.x = a.x + b.x
+  result.y = a.y + b.y
+proc `-`*(a: TVector2f): TVector2f {.inline.} =
+  result.x = -a.x
+  result.y = -a.y
+proc `-`*(a, b: TVector2f): TVector2f {.inline.}=
+  result.x = a.x - b.x
+  result.y = a.y - b.y
+proc `*`*(a: TVector2f, b: cfloat): TVector2f {.inline.} =
+  result.x = a.x * b
+  result.y = a.y * b
+proc `*`*(a, b: TVector2f): TVector2f {.inline.} =
+  result.x = a.x * b.x
+  result.y = a.y * b.y
+proc `/`*(a: TVector2f, b: cfloat): TVector2f {.inline.} =
+  result.x = a.x / b
+  result.y = a.y / b
+proc `+=` *(a: var TVector2f, b: TVector2f) {.inline, noSideEffect.} =
+  a = a + b
+proc `-=` *(a: var TVector2f, b: TVector2f) {.inline, noSideEffect.} =
+  a = a - b
+proc `*=` *(a: var TVector2f, b: float) {.inline, noSideEffect.} =
+  a = a * b
+proc `*=` *(a: var TVector2f, b: TVector2f) {.inline, noSideEffect.} =
+  a = a * b
+proc `/=` *(a: var TVector2f, b: float) {.inline, noSideEffect.} =
+  a = a / b
+proc `<` *(a, b: TVector2f): bool {.inline, noSideEffect.} =
+  return a.x < b.x or (a.x == b.x and a.y < b.y)
+proc `<=` *(a, b: TVector2f): bool {.inline, noSideEffect.} =
+  return a.x <= b.x and a.y <= b.y
+proc `==` *(a, b: TVector2f): bool {.inline, noSideEffect.} =
+  return a.x == b.x and a.y == b.y
+proc length*(a: TVector2f): float {.inline.} =
+  return sqrt(pow(a.x, 2.0) + pow(a.y, 2.0))
+proc lengthSq*(a: TVector2f): float {.inline.} =
+  return pow(a.x, 2.0) + pow(a.y, 2.0)
+proc distanceSq*(a, b: TVector2f): float {.inline.} =
+  return pow(a.x - b.x, 2.0) + pow(a.y - b.y, 2.0)
+proc distance*(a, b: TVector2f): float {.inline.} =
+  return sqrt(pow(a.x - b.x, 2.0) + pow(a.y - b.y, 2.0))
+proc permul*(a, b: TVector2f): TVector2f =
+  result.x = a.x * b.x
+  result.y = a.y * b.y
+proc rotate*(a: TVector2f, phi: float): TVector2f =
+  var c = cos(phi)
+  var s = sin(phi)
+  result.x = a.x * c - a.y * s
+  result.y = a.x * s + a.y * c
+proc perpendicular(a: TVector2f): TVector2f =
+  result.x = -a.x
+  result.y =  a.y
+proc cross(a, b: TVector2f): float =
+  return a.x * b.y - a.y * b.x
+
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim
new file mode 100644
index 000000000..3cfd33c02
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_audio.nim
@@ -0,0 +1,899 @@
+import
+  sfml
+const
+  Lib = "libcsfml-audio.so.2.0"
+type
+  PMusic* = ptr TMusic
+  TMusic* {.pure, final.} = object
+  PSound* = ptr TSound
+  TSound* {.pure, final.} = object
+  PSoundBuffer* = ptr TSoundBuffer
+  TSoundBuffer* {.pure, final.} = object
+  PSoundBufferRecorder* = ptr TSoundBufferRecorder
+  TSoundBufferRecorder* {.pure, final.} = object
+  PSoundRecorder* = ptr TSoundRecorder
+  TSoundRecorder* {.pure, final.} = object
+  PSoundStream* = ptr TSoundStream
+  TSoundStream* {.pure, final.} = object
+  TSoundStatus* {.size: sizeof(cint).} = enum
+    Stopped, Paused, Playing
+
+proc newMusic*(filename: cstring): PMusic {.
+  cdecl, importc: "sfMusic_createFromFile", dynlib: Lib.}
+proc newMusic*(data: pointer, size: cint): PMusic {.
+  cdecl, importc: "sfMusic_createFromMemory", dynlib: Lib.}
+proc newMusic*(stream: PInputStream): PMusic {.
+  cdecl, importc: "sfMusic_createFromStream", dynlib: Lib.}
+proc destroy*(music: PMusic) {.
+  cdecl, importc: "sfMusic_destroy", dynlib: Lib.}
+proc setLoop*(music: PMusic, loop: bool) {.
+  cdecl, importc: "sfMusic_setLoop", dynlib: Lib.}
+proc getLoop*(music: PMusic): bool {.
+  cdecl, importc: "sfMusic_getLoop", dynlib: Lib.}
+proc getDuration*(music: PMusic): TTime {.
+  cdecl, importc: "sfMusic_getDuration", dynlib: Lib.}
+proc play*(music: PMusic) {.
+  cdecl, importc: "sfMusic_play", dynlib: Lib.}
+proc pause*(music: PMusic) {.
+  cdecl, importc: "sfMusic_pause", dynlib: Lib.}
+proc stop*(music: PMusic) {.
+  cdecl, importc: "sfMusic_stop", dynlib: Lib.}
+proc getChannelCount*(music: PMusic): cint {.
+  cdecl, importc: "sfMusic_getChannelCount", dynlib: Lib.}
+proc getSampleRate*(music: PMusic): cint {.
+  cdecl, importc: "sfMusic_getSampleRate", dynlib: Lib.}
+proc getStatus*(music: PMusic): TSoundStatus {.
+  cdecl, importc: "sfMusic_getStatus", dynlib: Lib.}
+proc getPlayingOffset*(music: PMusic): TTime {.
+  cdecl, importc: "sfMusic_getPlayingOffset", dynlib: Lib.}
+proc setPitch*(music: PMusic, pitch: cfloat) {.
+  cdecl, importc: "sfMusic_setPitch", dynlib: Lib.}
+proc setVolume*(music: PMusic, volume: float) {.
+  cdecl, importc: "sfMusic_setVolume", dynlib: Lib.}
+proc setPosition*(music: PMusic, position: TVector3f) {.
+  cdecl, importc: "sfMusic_setPosition", dynlib: Lib.}
+proc setRelativeToListener*(music: PMusic, relative: bool) {.
+  cdecl, importc: "sfMusic_setRelativeToListener", dynlib: Lib.}
+proc setMinDistance*(music: PMusic, distance: cfloat) {.
+  cdecl, importc: "sfMusic_setMinDistance", dynlib: Lib.}
+proc setAttenuation*(music: PMusic, attenuation: cfloat) {.
+  cdecl, importc: "sfMusic_setAttenuation", dynlib: Lib.}
+proc setPlayingOffset*(music: PMusic, time: TTime) {.
+  cdecl, importc: "sfMusic_setPlayingOffset", dynlib: Lib.}
+proc getPitch*(music: PMusic): cfloat {.
+  cdecl, importc: "sfMusic_getPitch", dynlib: Lib.}
+proc getVolume*(music: PMusic): cfloat {.
+  cdecl, importc: "sfMusic_getVolume", dynlib: Lib.}
+proc getPosition*(music: PMusic): TVector3f {.
+  cdecl, importc: "sfMusic_getPosition", dynlib: Lib.}
+proc isRelativeToListener*(music: PMusic): bool {.
+  cdecl, importc: "sfMusic_isRelativeToListener", dynlib: Lib.}
+proc getMinDistance*(music: PMusic): cfloat {.
+  cdecl, importc: "sfMusic_isRelativeToListener", dynlib: Lib.}
+proc getAttenuation*(music: PMusic): cfloat {.
+  cdecl, importc: "sfMusic_isRelativeToListener", dynlib: Lib.}
+
+#/ \brief Create a new sound
+proc newSound*(): PSound{.
+  cdecl, importc: "sfSound_create", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound by copying an existing one
+#/
+#/ \param sound Sound to copy
+#/
+#/ \return A new sfSound object which is a copy of \a sound
+#/
+#//////////////////////////////////////////////////////////
+proc copy*(sound: PSound): PSound{.
+  cdecl, importc: "sfSound_copy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound
+proc destroy*(sound: PSound){.
+  cdecl, importc: "sfSound_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Start or resume playing a sound
+#/
+#/ This function starts the sound if it was stopped, resumes
+#/ it if it was paused, and restarts it from beginning if it
+#/ was it already playing.
+#/ This function uses its own thread so that it doesn't block
+#/ the rest of the program while the sound is played.
+proc play*(sound: PSound){.
+  cdecl, importc: "sfSound_play", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ This function pauses the sound if it was playing,
+#/ otherwise (sound already paused or stopped) it has no effect.
+proc pause*(sound: PSound){.
+  cdecl, importc: "sfSound_pause", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ This function stops the sound if it was playing or paused,
+#/ and does nothing if it was already stopped.
+#/ It also resets the playing position (unlike sfSound_pause).
+proc stop*(sound: PSound){.
+  cdecl, importc: "sfSound_stop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ It is important to note that the sound buffer is not copied,
+#/ thus the sfSoundBuffer object must remain alive as long
+#/ as it is attached to the sound.
+proc setBuffer*(sound: PSound; buffer: PSoundBuffer){.
+  cdecl, importc: "sfSound_setBuffer", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the audio buffer attached to a sound
+proc getBuffer*(sound: PSound): PSoundBuffer{.
+  cdecl, importc: "sfSound_getBuffer", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set whether or not a sound should loop after reaching the end
+#/
+#/ If set, the sound will restart from beginning after
+#/ reaching the end and so on, until it is stopped or
+#/ sfSound_setLoop(sound, sfFalse) is called.
+#/ The default looping state for sounds is false.
+proc setLoop*(sound: PSound; loop: bool){.
+  cdecl, importc: "sfSound_setLoop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Tell whether or not a soud is in loop mode
+proc getLoop*(sound: PSound): bool {.
+  cdecl, importc: "sfSound_getLoop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current status of a sound (stopped, paused, playing)
+proc getStatus*(sound: PSound): TSoundStatus{.
+  cdecl, importc: "sfSound_getStatus", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the pitch of a sound
+#/
+#/ The pitch represents the perceived fundamental frequency
+#/ of a sound; thus you can make a sound more acute or grave
+#/ by changing its pitch. A side effect of changing the pitch
+#/ is to modify the playing speed of the sound as well.
+#/ The default value for the pitch is 1.
+proc setPitch*(sound: PSound; pitch: cfloat){.
+  cdecl, importc: "sfSound_setPitch", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the volume of a sound
+#/
+#/ The volume is a value between 0 (mute) and 100 (full volume).
+#/ The default value for the volume is 100.
+proc setVolume*(sound: PSound; volume: cfloat){.
+  cdecl, importc: "sfSound_setVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the 3D position of a sound in the audio scene
+#/
+#/ Only sounds with one channel (mono sounds) can be
+#/ spatialized.
+#/ The default position of a sound is (0, 0, 0).
+proc setPosition*(sound: PSound; position: TVector3f){.
+  cdecl, importc: "sfSound_setPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Make the sound's position relative to the listener or absolute
+#/
+#/ Making a sound relative to the listener will ensure that it will always
+#/ be played the same way regardless the position of the listener.
+#/ This can be useful for non-spatialized sounds, sounds that are
+#/ produced by the listener, or sounds attached to it.
+#/ The default value is false (position is absolute).
+proc setRelativeToListener*(sound: PSound; relative: bool){.
+  cdecl, importc: "sfSound_setRelativeToListener", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the minimum distance of a sound
+#/
+#/ The "minimum distance" of a sound is the maximum
+#/ distance at which it is heard at its maximum volume. Further
+#/ than the minimum distance, it will start to fade out according
+#/ to its attenuation factor. A value of 0 ("inside the head
+#/ of the listener") is an invalid value and is forbidden.
+#/ The default value of the minimum distance is 1.
+proc setMinDistance*(sound: PSound; distance: cfloat){.
+  cdecl, importc: "sfSound_setMinDistance", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the attenuation factor of a sound
+#/
+#/ The attenuation is a multiplicative factor which makes
+#/ the sound more or less loud according to its distance
+#/ from the listener. An attenuation of 0 will produce a
+#/ non-attenuated sound, i.e. its volume will always be the same
+#/ whether it is heard from near or from far. On the other hand,
+#/ an attenuation value such as 100 will make the sound fade out
+#/ very quickly as it gets further from the listener.
+#/ The default value of the attenuation is 1.
+proc setAttenuation*(sound: PSound; attenuation: cfloat){.
+  cdecl, importc: "sfSound_setAttenuation", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Change the current playing position of a sound
+#/
+#/ The playing position can be changed when the sound is
+#/ either paused or playing.
+proc setPlayingOffset*(sound: PSound; timeOffset: sfml.TTime){.
+  cdecl, importc: "sfSound_setPlayingOffset", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the pitch of a sound
+proc getPitch*(sound: PSound): cfloat{.
+  cdecl, importc: "sfSound_getPitch", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the volume of a sound
+proc getVolume*(sound: PSound): cfloat{.
+  cdecl, importc: "sfSound_getVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the 3D position of a sound in the audio scene
+proc getPosition*(sound: PSound): TVector3f{.
+  cdecl, importc: "sfSound_getPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Tell whether a sound's position is relative to the
+#/        listener or is absolute
+proc isRelativeToListener*(sound: PSound): bool{.
+  cdecl, importc: "sfSound_isRelativeToListener", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the minimum distance of a sound
+proc getMinDistance*(sound: PSound): cfloat{.
+  cdecl, importc: "sfSound_getMinDistance", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the attenuation factor of a sound
+proc getAttenuation*(sound: PSound): cfloat{.
+  cdecl, importc: "sfSound_getAttenuation", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current playing position of a sound
+proc getPlayingOffset*(sound: PSound): TTime{.
+  cdecl, importc: "sfSound_getPlayingOffset", dynlib: Lib.}
+
+#//////////////////////////////////////////////////////////
+# Headers
+#//////////////////////////////////////////////////////////
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer and load it from a file
+#/
+#/ Here is a complete list of all the supported audio formats:
+#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
+#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
+#/
+#/ \param filename Path of the sound file to load
+#/
+#/ \return A new sfSoundBuffer object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundBuffer*(filename: cstring): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_createFromFile", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer and load it from a file in memory
+#/
+#/ Here is a complete list of all the supported audio formats:
+#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
+#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
+#/
+#/ \param data        Pointer to the file data in memory
+#/ \param sizeInBytes Size of the data to load, in bytes
+#/
+#/ \return A new sfSoundBuffer object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundBuffer*(data: pointer; sizeInBytes: cint): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_createFromMemory", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer and load it from a custom stream
+#/
+#/ Here is a complete list of all the supported audio formats:
+#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
+#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
+#/
+#/ \param stream Source stream to read from
+#/
+#/ \return A new sfSoundBuffer object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundBuffer*(stream: PInputStream): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_createFromStream", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer and load it from an array of samples in memory
+#/
+#/ The assumed format of the audio samples is 16 bits signed integer
+#/ (sfInt16).
+#/
+#/ \param samples      Pointer to the array of samples in memory
+#/ \param sampleCount  Number of samples in the array
+#/ \param channelCount Number of channels (1 = mono, 2 = stereo, ...)
+#/ \param sampleRate   Sample rate (number of samples to play per second)
+#/
+#/ \return A new sfSoundBuffer object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc createFromSamples*(samples: ptr int16; sampleCount: cuint; 
+                         channelCount: cuint; sampleRate: cuint): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_createFromSamples", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer by copying an existing one
+#/
+#/ \param soundBuffer Sound buffer to copy
+#/
+#/ \return A new sfSoundBuffer object which is a copy of \a soundBuffer
+#/
+#//////////////////////////////////////////////////////////
+proc copy*(soundBuffer: PSoundBuffer): PSoundBuffer{.
+  cdecl, importc: "sfSoundBuffer_copy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound buffer
+#/
+#/ \param soundBuffer Sound buffer to destroy
+#/
+#//////////////////////////////////////////////////////////
+proc destroy*(soundBuffer: PSoundBuffer){.
+  cdecl, importc: "sfSoundBuffer_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Save a sound buffer to an audio file
+#/
+#/ Here is a complete list of all the supported audio formats:
+#/ ogg, wav, flac, aiff, au, raw, paf, svx, nist, voc, ircam,
+#/ w64, mat4, mat5 pvf, htk, sds, avr, sd2, caf, wve, mpc2k, rf64.
+#/
+#/ \param soundBuffer Sound buffer object
+#/ \param filename    Path of the sound file to write
+#/
+#/ \return sfTrue if saving succeeded, sfFalse if it failed
+#/
+#//////////////////////////////////////////////////////////
+proc saveToFile*(soundBuffer: PSoundBuffer; filename: cstring): bool {.
+  cdecl, importc: "sfSoundBuffer_saveToFile", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the array of audio samples stored in a sound buffer
+#/
+#/ The format of the returned samples is 16 bits signed integer
+#/ (sfInt16). The total number of samples in this array
+#/ is given by the sfSoundBuffer_getSampleCount function.
+#/
+#/ \param soundBuffer Sound buffer object
+#/
+#/ \return Read-only pointer to the array of sound samples
+#/
+#//////////////////////////////////////////////////////////
+proc sfSoundBuffer_getSamples*(soundBuffer: PSoundBuffer): ptr Int16{.
+  cdecl, importc: "sfSoundBuffer_getSamples", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the number of samples stored in a sound buffer
+#/
+#/ The array of samples can be accessed with the
+#/ sfSoundBuffer_getSamples function.
+proc getSampleCount*(soundBuffer: PSoundBuffer): cint{.
+  cdecl, importc: "sfSoundBuffer_getSampleCount", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sample rate of a sound buffer
+#/
+#/ The sample rate is the number of samples played per second.
+#/ The higher, the better the quality (for example, 44100
+#/ samples/s is CD quality).
+proc getSampleRate*(soundBuffer: PSoundBuffer): cuint{.
+  cdecl, importc: "sfSoundBuffer_getSampleRate", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the number of channels used by a sound buffer
+#/
+#/ If the sound is mono then the number of channels will
+#/ be 1, 2 for stereo, etc.
+proc getChannelCount*(soundBuffer: PSoundBuffer): cuint{.
+  cdecl, importc: "sfSoundBuffer_getChannelCount", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the total duration of a sound buffer
+#/
+#/ \param soundBuffer Sound buffer object
+#/
+#/ \return Sound duration
+#/
+#//////////////////////////////////////////////////////////
+proc getDuration*(soundBuffer: PSoundBuffer): TTime{.
+  cdecl, importc: "sfSoundBuffer_getDuration", dynlib: Lib.}
+
+#//////////////////////////////////////////////////////////
+#/ \brief Change the global volume of all the sounds and musics
+#/
+#/ The volume is a number between 0 and 100; it is combined with
+#/ the individual volume of each sound / music.
+#/ The default value for the volume is 100 (maximum).
+#/
+#/ \param volume New global volume, in the range [0, 100]
+#/
+#//////////////////////////////////////////////////////////
+proc listenerSetGlobalVolume*(volume: cfloat){.
+  cdecl, importc: "sfListener_setGlobalVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current value of the global volume
+#/
+#/ \return Current global volume, in the range [0, 100]
+#/
+#//////////////////////////////////////////////////////////
+proc listenerGetGlobalVolume*(): cfloat{.
+  cdecl, importc: "sfListener_getGlobalVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the position of the listener in the scene
+#/
+#/ The default listener's position is (0, 0, 0).
+#/
+#/ \param position New position of the listener
+#/
+#//////////////////////////////////////////////////////////
+proc listenerSetPosition*(position: TVector3f){.
+  cdecl, importc: "sfListener_setPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current position of the listener in the scene
+#/
+#/ \return The listener's position
+#/
+#//////////////////////////////////////////////////////////
+proc listenerGetPosition*(): TVector3f{.
+  cdecl, importc: "sfListener_getPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the orientation of the listener in the scene
+#/
+#/ The orientation defines the 3D axes of the listener
+#/ (left, up, front) in the scene. The orientation vector
+#/ doesn't have to be normalized.
+#/ The default listener's orientation is (0, 0, -1).
+#/
+#/ \param position New direction of the listener
+#/
+#//////////////////////////////////////////////////////////
+proc listenerSetDirection*(orientation: TVector3f){.
+  cdecl, importc: "sfListener_setDirection", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current orientation of the listener in the scene
+#/
+#/ \return The listener's direction
+#/
+#//////////////////////////////////////////////////////////
+proc listenerGetDirection*(): TVector3f{.
+  cdecl, importc: "sfListener_getDirection", dynlib: Lib.}
+
+type 
+  TSoundRecorderStartCallback* = proc (a2: pointer): bool {.cdecl.}
+  #/< Type of the callback used when starting a capture 
+  TSoundRecorderProcessCallback* = proc(a2: ptr int16; a3: cuint; 
+    a4: pointer): bool {.cdecl.}
+  #/< Type of the callback used to process audio data
+  TSoundRecorderStopCallback* = proc (a2: pointer){.cdecl.}
+  #/< Type of the callback used when stopping a capture
+#//////////////////////////////////////////////////////////
+#/ \brief Construct a new sound recorder from callback functions
+#/
+#/ \param onStart   Callback function which will be called when a new capture starts (can be NULL)
+#/ \param onProcess Callback function which will be called each time there's audio data to process
+#/ \param onStop    Callback function which will be called when the current capture stops (can be NULL)
+#/ \param userData  Data to pass to the callback function (can be NULL)
+#/
+#/ \return A new sfSoundRecorder object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundRecorder*(onStart: TSoundRecorderStartCallback; 
+                        onProcess: TSoundRecorderProcessCallback; 
+                        onStop: TSoundRecorderStopCallback; 
+                        userData: pointer = nil): PSoundRecorder{.
+  cdecl, importc: "sfSoundRecorder_create", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound recorder
+#/
+#/ \param soundRecorder Sound recorder to destroy
+#/
+#//////////////////////////////////////////////////////////
+proc destroy*(soundRecorder: PSoundRecorder){.
+  cdecl, importc: "sfSoundRecorder_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Start the capture of a sound recorder
+#/
+#/ The \a sampleRate parameter defines the number of audio samples
+#/ captured per second. The higher, the better the quality
+#/ (for example, 44100 samples/sec is CD quality).
+#/ This function uses its own thread so that it doesn't block
+#/ the rest of the program while the capture runs.
+#/ Please note that only one capture can happen at the same time.
+#/
+#/ \param soundRecorder Sound recorder object
+#/ \param sampleRate    Desired capture rate, in number of samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc start*(soundRecorder: PSoundRecorder; sampleRate: cuint){.
+  cdecl, importc: "sfSoundRecorder_start", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Stop the capture of a sound recorder
+#/
+#/ \param soundRecorder Sound recorder object
+#/
+#//////////////////////////////////////////////////////////
+proc stop*(soundRecorder: PSoundRecorder){.
+  cdecl, importc: "sfSoundRecorder_stop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sample rate of a sound recorder
+#/
+#/ The sample rate defines the number of audio samples
+#/ captured per second. The higher, the better the quality
+#/ (for example, 44100 samples/sec is CD quality).
+#/
+#/ \param soundRecorder Sound recorder object
+#/
+#/ \return Sample rate, in samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc getSampleRate*(soundRecorder: PSoundRecorder): cuint{.
+  cdecl, importc: "sfSoundRecorder_getSampleRate", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Check if the system supports audio capture
+#/
+#/ This function should always be called before using
+#/ the audio capture features. If it returns false, then
+#/ any attempt to use sfSoundRecorder will fail.
+#/
+#/ \return sfTrue if audio capture is supported, sfFalse otherwise
+#/
+#//////////////////////////////////////////////////////////
+proc soundRecorderIsAvailable*(): bool {.
+  cdecl, importc: "sfSoundRecorder_isAvailable", dynlib: Lib.}
+
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound buffer recorder
+#/
+#/ \return A new sfSoundBufferRecorder object (NULL if failed)
+#/
+#//////////////////////////////////////////////////////////
+proc newSoundBufferRecorder*(): PSoundBufferRecorder{.
+  cdecl, importc: "sfSoundBufferRecorder_create", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound buffer recorder
+#/
+#/ \param soundBufferRecorder Sound buffer recorder to destroy
+#/
+#//////////////////////////////////////////////////////////
+proc destroy*(soundBufferRecorder: PSoundBufferRecorder){.
+  cdecl, importc: "sfSoundBufferRecorder_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Start the capture of a sound recorder recorder
+#/
+#/ The \a sampleRate parameter defines the number of audio samples
+#/ captured per second. The higher, the better the quality
+#/ (for example, 44100 samples/sec is CD quality).
+#/ This function uses its own thread so that it doesn't block
+#/ the rest of the program while the capture runs.
+#/ Please note that only one capture can happen at the same time.
+#/
+#/ \param soundBufferRecorder Sound buffer recorder object
+#/ \param sampleRate          Desired capture rate, in number of samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc start*(soundBufferRecorder: PSoundBufferRecorder; sampleRate: cuint){.
+  cdecl, importc: "sfSoundBufferRecorder_start", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Stop the capture of a sound recorder
+#/
+#/ \param soundBufferRecorder Sound buffer recorder object
+#/
+#//////////////////////////////////////////////////////////
+proc stop*(soundBufferRecorder: PSoundBufferRecorder){.
+  cdecl, importc: "sfSoundBufferRecorder_stop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sample rate of a sound buffer recorder
+#/
+#/ The sample rate defines the number of audio samples
+#/ captured per second. The higher, the better the quality
+#/ (for example, 44100 samples/sec is CD quality).
+#/
+#/ \param soundBufferRecorder Sound buffer recorder object
+#/
+#/ \return Sample rate, in samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc getSampleRate*(soundBufferRecorder: PSoundBufferRecorder): cuint{.
+  cdecl, importc: "sfSoundBufferRecorder_getSampleRate", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sound buffer containing the captured audio data
+#/
+#/ The sound buffer is valid only after the capture has ended.
+#/ This function provides a read-only access to the internal
+#/ sound buffer, but it can be copied if you need to
+#/ make any modification to it.
+#/
+#/ \param soundBufferRecorder Sound buffer recorder object
+#/
+#/ \return Read-only access to the sound buffer
+#/
+#//////////////////////////////////////////////////////////
+proc getBuffer*(soundBufferRecorder: PSoundBufferRecorder): PSoundBuffer{.
+  cdecl, importc: "sfSoundBufferRecorder_getBuffer", dynlib: Lib.}
+
+
+#//////////////////////////////////////////////////////////
+#/ \brief defines the data to fill by the OnGetData callback
+#/
+#//////////////////////////////////////////////////////////
+type 
+  PSoundStreamChunk* = ptr TSoundStreamChunk
+  TSoundStreamChunk*{.pure, final.} = object 
+    samples*: ptr int16   #/< Pointer to the audio samples
+    sampleCount*: cuint     #/< Number of samples pointed by Samples
+  
+  TSoundStreamGetDataCallback* = proc (a2: PSoundStreamChunk; 
+      a3: pointer): bool{.cdecl.}
+  #/< Type of the callback used to get a sound stream data
+  TSoundStreamSeekCallback* = proc (a2: TTime; a3: pointer){.cdecl.}
+  #/< Type of the callback used to seek in a sound stream
+#//////////////////////////////////////////////////////////
+#/ \brief Create a new sound stream
+#/
+#/ \param onGetData    Function called when the stream needs more data (can't be NULL)
+#/ \param onSeek       Function called when the stream seeks (can't be NULL)
+#/ \param channelCount Number of channels to use (1 = mono, 2 = stereo)
+#/ \param sampleRate   Sample rate of the sound (44100 = CD quality)
+#/ \param userData     Data to pass to the callback functions
+#/
+#/ \return A new sfSoundStream object
+#/
+#//////////////////////////////////////////////////////////
+proc create*(onGetData: TSoundStreamGetDataCallback; onSeek: TSoundStreamSeekCallback; 
+              channelCount: cuint; sampleRate: cuint; userData: pointer): PSoundStream{.
+  cdecl, importc: "sfSoundStream_create", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Destroy a sound stream
+#/
+#/ \param soundStream Sound stream to destroy
+#/
+#//////////////////////////////////////////////////////////
+proc destroy*(soundStream: PSoundStream){.
+  cdecl, importc: "sfSoundStream_destroy", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Start or resume playing a sound stream
+#/
+#/ This function starts the stream if it was stopped, resumes
+#/ it if it was paused, and restarts it from beginning if it
+#/ was it already playing.
+#/ This function uses its own thread so that it doesn't block
+#/ the rest of the program while the music is played.
+#/
+#/ \param soundStream Sound stream object
+#/
+#//////////////////////////////////////////////////////////
+proc play*(soundStream: PSoundStream){.
+  cdecl, importc: "sfSoundStream_play", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Pause a sound stream
+#/
+#/ This function pauses the stream if it was playing,
+#/ otherwise (stream already paused or stopped) it has no effect.
+#/
+#/ \param soundStream Sound stream object
+#/
+#//////////////////////////////////////////////////////////
+proc pause*(soundStream: PSoundStream){.
+  cdecl, importc: "sfSoundStream_pause", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Stop playing a sound stream
+#/
+#/ This function stops the stream if it was playing or paused,
+#/ and does nothing if it was already stopped.
+#/ It also resets the playing position (unlike sfSoundStream_pause).
+#/
+#/ \param soundStream Sound stream object
+#/
+#//////////////////////////////////////////////////////////
+proc stop*(soundStream: PSoundStream){.
+  cdecl, importc: "sfSoundStream_stop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current status of a sound stream (stopped, paused, playing)
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Current status
+#/
+#//////////////////////////////////////////////////////////
+proc getStatus*(soundStream: PSoundStream): TSoundStatus{.
+  cdecl, importc: "sfSoundStream_getStatus", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Return the number of channels of a sound stream
+#/
+#/ 1 channel means a mono sound, 2 means stereo, etc.
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Number of channels
+#/
+#//////////////////////////////////////////////////////////
+proc getChannelCount*(soundStream: PSoundStream): cuint{.
+  cdecl, importc: "sfSoundStream_getChannelCount", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the sample rate of a sound stream
+#/
+#/ The sample rate is the number of audio samples played per
+#/ second. The higher, the better the quality.
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Sample rate, in number of samples per second
+#/
+#//////////////////////////////////////////////////////////
+proc getSampleRate*(soundStream: PSoundStream): cuint{.
+  cdecl, importc: "sfSoundStream_getSampleRate", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the pitch of a sound stream
+#/
+#/ The pitch represents the perceived fundamental frequency
+#/ of a sound; thus you can make a stream more acute or grave
+#/ by changing its pitch. A side effect of changing the pitch
+#/ is to modify the playing speed of the stream as well.
+#/ The default value for the pitch is 1.
+#/
+#/ \param soundStream Sound stream object
+#/ \param pitch       New pitch to apply to the stream
+#/
+#//////////////////////////////////////////////////////////
+proc setPitch*(soundStream: PSoundStream; pitch: cfloat){.
+  cdecl, importc: "sfSoundStream_setPitch", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the volume of a sound stream
+#/
+#/ The volume is a value between 0 (mute) and 100 (full volume).
+#/ The default value for the volume is 100.
+#/
+#/ \param soundStream Sound stream object
+#/ \param volume      Volume of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc setVolume*(soundStream: PSoundStream; volume: cfloat){.
+  cdecl, importc: "sfSoundStream_setVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the 3D position of a sound stream in the audio scene
+#/
+#/ Only streams with one channel (mono streams) can be
+#/ spatialized.
+#/ The default position of a stream is (0, 0, 0).
+#/
+#/ \param soundStream Sound stream object
+#/ \param position    Position of the stream in the scene
+#/
+#//////////////////////////////////////////////////////////
+proc setPosition*(soundStream: PSoundStream; position: TVector3f){.
+  cdecl, importc: "sfSoundStream_setPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Make a sound stream's position relative to the listener or absolute
+#/
+#/ Making a stream relative to the listener will ensure that it will always
+#/ be played the same way regardless the position of the listener.
+#/ This can be useful for non-spatialized streams, streams that are
+#/ produced by the listener, or streams attached to it.
+#/ The default value is false (position is absolute).
+#/
+#/ \param soundStream Sound stream object
+#/ \param relative    sfTrue to set the position relative, sfFalse to set it absolute
+#/
+#//////////////////////////////////////////////////////////
+proc setRelativeToListener*(soundStream: PSoundStream; relative: bool){.
+  cdecl, importc: "sfSoundStream_setRelativeToListener", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the minimum distance of a sound stream
+#/
+#/ The "minimum distance" of a stream is the maximum
+#/ distance at which it is heard at its maximum volume. Further
+#/ than the minimum distance, it will start to fade out according
+#/ to its attenuation factor. A value of 0 ("inside the head
+#/ of the listener") is an invalid value and is forbidden.
+#/ The default value of the minimum distance is 1.
+#/
+#/ \param soundStream Sound stream object
+#/ \param distance    New minimum distance of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc setMinDistance*(soundStream: PSoundStream; distance: cfloat){.
+  cdecl, importc: "sfSoundStream_setMinDistance", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set the attenuation factor of a sound stream
+#/
+#/ The attenuation is a multiplicative factor which makes
+#/ the stream more or less loud according to its distance
+#/ from the listener. An attenuation of 0 will produce a
+#/ non-attenuated stream, i.e. its volume will always be the same
+#/ whether it is heard from near or from far. On the other hand,
+#/ an attenuation value such as 100 will make the stream fade out
+#/ very quickly as it gets further from the listener.
+#/ The default value of the attenuation is 1.
+#/
+#/ \param soundStream Sound stream object
+#/ \param attenuation New attenuation factor of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc setAttenuation*(soundStream: PSoundStream; attenuation: cfloat){.
+  cdecl, importc: "sfSoundStream_setAttenuation", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Change the current playing position of a sound stream
+#/
+#/ The playing position can be changed when the stream is
+#/ either paused or playing.
+#/
+#/ \param soundStream Sound stream object
+#/ \param timeOffset  New playing position
+#/
+#//////////////////////////////////////////////////////////
+proc setPlayingOffset*(soundStream: PSoundStream; timeOffset: TTime){.
+  cdecl, importc: "sfSoundStream_setPlayingOffset", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Set whether or not a sound stream should loop after reaching the end
+#/
+#/ If set, the stream will restart from beginning after
+#/ reaching the end and so on, until it is stopped or
+#/ sfSoundStream_setLoop(stream, sfFalse) is called.
+#/ The default looping state for sound streams is false.
+#/
+#/ \param soundStream Sound stream object
+#/ \param loop        sfTrue to play in loop, sfFalse to play once
+#/
+#//////////////////////////////////////////////////////////
+proc setLoop*(soundStream: PSoundStream; loop: bool){.
+  cdecl, importc: "sfSoundStream_setLoop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the pitch of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Pitch of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc getPitch*(soundStream: PSoundStream): cfloat{.
+  cdecl, importc: "sfSoundStream_getPitch", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the volume of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Volume of the stream, in the range [0, 100]
+#/
+#//////////////////////////////////////////////////////////
+proc getVolume*(soundStream: PSoundStream): cfloat{.
+  cdecl, importc: "sfSoundStream_getVolume", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the 3D position of a sound stream in the audio scene
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Position of the stream in the world
+#/
+#//////////////////////////////////////////////////////////
+proc getPosition*(soundStream: PSoundStream): TVector3f{.
+  cdecl, importc: "sfSoundStream_getPosition", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Tell whether a sound stream's position is relative to the
+#/        listener or is absolute
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return sfTrue if the position is relative, sfFalse if it's absolute
+#/
+#//////////////////////////////////////////////////////////
+proc isRelativeToListener*(soundStream: PSoundStream): bool{.
+  cdecl, importc: "sfSoundStream_isRelativeToListener", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the minimum distance of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Minimum distance of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc getMinDistance*(soundStream: PSoundStream): cfloat{.
+  cdecl, importc: "sfSoundStream_getMinDistance", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the attenuation factor of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Attenuation factor of the stream
+#/
+#//////////////////////////////////////////////////////////
+proc getAttenuation*(soundStream: PSoundStream): cfloat{.
+  cdecl, importc: "sfSoundStream_getAttenuation", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Tell whether or not a sound stream is in loop mode
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return sfTrue if the music is looping, sfFalse otherwise
+#/
+#//////////////////////////////////////////////////////////
+proc getLoop*(soundStream: PSoundStream): bool{.
+  cdecl, importc: "sfSoundStream_getLoop", dynlib: Lib.}
+#//////////////////////////////////////////////////////////
+#/ \brief Get the current playing position of a sound stream
+#/
+#/ \param soundStream Sound stream object
+#/
+#/ \return Current playing position
+#/
+#//////////////////////////////////////////////////////////
+proc getPlayingOffset*(soundStream: PSoundStream): TTime{.
+  cdecl, importc: "sfSoundStream_getPlayingOffset", dynlib: Lib.}
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim
new file mode 100644
index 000000000..31473b17a
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_colors.nim
@@ -0,0 +1,15 @@
+import sfml
+{.deadCodeElim: on.}
+let
+  Black*: TColor = color(0, 0, 0)
+  White*: TColor = color(255, 255, 255)
+  Red*: TColor = color(255, 0, 0)
+  Green*: TColor = color(0, 255, 0)
+  Blue*: TColor = color(0, 0, 255)
+  Yellow*: TColor = color(255, 255, 0)
+  Magenta*: TColor = color(255, 0, 255)
+  Cyan*: TColor = color(0, 255, 255)
+  Transparent*: TColor = color(0, 0, 0, 0)
+  Gray* = color(84, 84, 84)
+  RoyalBlue* = color(65, 105, 225)
+##todo: define more colors lul
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim b/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim
new file mode 100644
index 000000000..474d249aa
--- /dev/null
+++ b/tests/manyloc/keineschweine/dependencies/sfml/sfml_vector.nim
@@ -0,0 +1,2 @@
+import sfml, math, strutils
+{.deadCodeElim: on.}
diff --git a/tests/manyloc/keineschweine/enet_server/enet_client.nim b/tests/manyloc/keineschweine/enet_server/enet_client.nim
new file mode 100644
index 000000000..f4c8732e3
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/enet_client.nim
@@ -0,0 +1,228 @@
+import enet, strutils,
+  sfml, sfml_colors, sg_gui, input_helpers,
+  math_helpers, sg_packets, estreams, tables,
+  json, sg_assets, client_helpers
+if enetInit() != 0:
+  quit "Could not initialize ENet"
+type
+  TClientSettings = object
+    resolution*: TVideoMode
+    offlineFile: string
+    dirserver: tuple[host: string, port: int16]
+    website*: string
+var
+  clientSettings: TClientSettings
+  event: enet.TEvent
+  bConnected = false
+  runServer = true
+  gui = newGuiContainer()
+  zonelist = newGuiContainer()
+  kc = newKeyClient(setActive = true)
+  clock = newClock()
+  chatBox: PMessageArea
+  chatInput: PTextEntry
+  loginBtn, playBtn: PButton
+  fpsText = newText("", guiFont, 18)
+  connectionButtons: seq[PButton]
+  connectButton: PButton
+  u_alias, u_passwd: PTextEntry
+  dirServer: PServer
+  zone: PServer
+  showZoneList = false
+  myCreds = newScLogin(0, "", "") ##my session token
+
+proc handleChat(server: PServer; buf: PBuffer) =
+  let msg = readScChat(buf)
+  chatBox.add msg
+proc handlePlayerLogin(server: PServer; buf: PBuffer) =
+  let login = readScLogin(buf)
+  myCreds = login
+  echo("I am ", $myCreds)
+
+
+kc.registerHandler MouseLeft, down, proc() =
+  gui.click(input_helpers.getMousePos())
+
+block:
+  var pos = vec2f(15, 550)
+  chatBox = gui.newMessageArea(pos)
+  pos.y += 20
+  chatInput = gui.newTextEntry("...", pos, proc() =
+    sendPubChat dirServer, chatInput.getText()
+    chatInput.clearText())
+
+gui.setActive(chatInput)
+
+proc dispMessage(args: varargs[string, `$`]) =
+  var s = ""
+  for it in items(args):
+    s.add it
+  chatbox.add(s)
+proc dispMessage(text: string) {.inline.} =
+  chatbox.add(text)
+proc dispError(text: string) {.inline.} =
+  chatBox.add(newScChat(kind = CError, text = text))
+
+proc updateButtons() =
+  let conn = dirServer.connected
+  for b in connectionButtons: setEnabled(b, conn)
+  if conn:
+    connectButton.setString "Disconnect"
+  else:
+    connectButton.setString "Connect"
+
+proc poll(serv: PServer; timeout: cuint = 30) =
+  if serv.isNil or serv.host.isNil: return
+  if serv.connected:
+    while serv.host.hostService(event, timeout) > 0:
+      case event.kind
+      of EvtReceive:
+        var buf = newBuffer(event.packet)
+        
+        serv.handlePackets(buf)
+        
+        event.packet.destroy()
+      of EvtDisconnect:        
+        dispMessage "Disconnected"
+        serv.connected = false
+        event.peer.data = nil
+        updateButtons()
+      of EvtNone: discard
+      else:
+        echo repr(event)
+  else:
+    if serv.host.hostService(event, timeout) > 0 and event.kind == EvtConnect:
+      dispMessage "Connected"
+      serv.connected = true
+      if serv.peer != event.peer:
+        serv.peer = event.peer
+      event.peer.data = serv
+      updateButtons()
+
+proc tryLogin*(b: PButton) =
+  var login = newCsLogin(
+    alias = u_alias.getText(),
+    passwd = u_passwd.getText())
+  dirServer.send HLogin, login
+proc tryTransition*(b: PButton) =
+  #zone.writePkt HZoneJoinReq, myCreds
+proc tryConnect*(b: PButton) =
+  if not dirServer.connected:
+    var error: string
+    if not dirServer.connect(
+            clientSettings.dirServer.host, 
+            clientSettings.dirServer.port, 
+            error):
+      dispError(error)
+  else:
+    dirServer.peer.disconnect(1)
+
+proc playOffline*(b: PButton) =
+  var errors: seq[string] = @[]
+  if loadSettingsFromFile(clientSettings.offlineFile, errors):
+    transition()
+  else:
+    dispMessage "Errors reading the file (", clientSettings.offlineFile, "):"
+    for e in errors: dispError(e)
+
+proc getClientSettings*(): TClientSettings =
+  result = clientSettings
+
+
+proc lobbyInit*() =
+  var s = json.parseFile("./client_settings.json")
+  clientSettings.offlineFile = "data/"
+  clientSettings.offlineFile.add s["default-file"].str
+  let dirserv = s["directory-server"]
+  clientSettings.dirserver.host = dirserv["host"].str
+  clientSettings.dirserver.port = dirserv["port"].num.int16
+  clientSettings.resolution.width = s["resolution"][0].num.cint
+  clientSettings.resolution.height= s["resolution"][1].num.cint
+  clientSettings.resolution.bitsPerPixel = s["resolution"][2].num.cint
+  clientSettings.website = s["website"].str
+  zonelist.setPosition(vec2f(200.0, 100.0))
+  connectionButtons = @[]
+  
+  var pos = vec2f(10, 10)
+  u_alias = gui.newTextEntry(
+    if s.existsKey("alias"): s["alias"].str else: "alias", 
+    pos)
+  pos.y += 20
+  u_passwd = gui.newTextEntry("buzz", pos)
+  pos.y += 20
+  connectionButtons.add(gui.newButton(
+    text = "Login", 
+    position = pos,
+    onClick = tryLogin,
+    startEnabled = false))
+  pos.y += 20
+  fpsText.setPosition pos
+  pos.y += 20
+  connectButton = gui.newButton(
+    text = "Connect",
+    position = pos,
+    onClick = tryConnect)
+  pos.y += 20
+  gui.newButton("Test Files", position = pos, onClick = proc(b: PButton) =
+    var req = newCsZoneJoinReq(myCreds)
+    dirServer.send HZoneJoinReq, req)
+  pos.y += 20
+  connectionButtons.add(gui.newButton(
+    text = "Test Chat",
+    position = pos,
+    onClick = (proc(b: PButton) = 
+      var pkt = newCsChat(text = "ohai")
+      dirServer.send HChat, pkt),
+    startEnabled = false))
+  pos.y += 20
+  downloadProgress.setPosition(pos) 
+  downloadProgress.bg.setFillColor(color(34, 139, 34))
+  downloadProgress.bg.setSize(vec2f(0, 0))
+  gui.add(downloadProgress)
+  
+  playBtn = gui.newButton(
+    text = "Play",
+    position = vec2f(680.0, 8.0),
+    onClick = tryTransition,
+    startEnabled = false)
+  gui.newButton(
+    text = "Play Offline",
+    position = vec2f(680.0, 28.0),
+    onClick = playOffline)
+  discard """gui.newButton(text = "Scrollback + 1", position = vec2f(185, 10), onClick = proc(b: PButton) =
+    messageArea.scrollBack += 1
+    update(messageArea))
+  gui.newButton(text = "Scrollback - 1", position = vec2f(185+160, 10), onClick = proc(b: PButton) = 
+    messageArea.scrollBack -= 1
+    update(messageArea))
+  gui.newButton(text = "Flood msg area", position = vec2f(185, 30), onClick = proc(b: PButton) =
+    for i in 0.. <30: 
+      dispMessage($i))"""
+  dirServer = newServer() 
+  dirServer.addHandler HChat, handleChat
+  dirServer.addHandler HLogin, handlePlayerLogin
+  dirServer.addHandler HFileTransfer, client_helpers.handleFilePartRecv
+  dirServer.addHandler HChallengeResult, client_helpers.handleFileChallengeResult
+  dirServer.addHandler HFileChallenge, client_helpers.handleFileChallenge
+
+proc lobbyReady*() = 
+  kc.setActive()
+  gui.setActive(u_alias)
+
+var i = 0
+proc lobbyUpdate*(dt: float) =
+  dirServer.poll()
+  #let res = disp.poll()
+  gui.update(dt)
+  i = (i + 1) mod 60
+  if i == 0:
+    fpsText.setString("FPS: "& ff(1.0/dt))
+
+proc lobbyDraw*(window: PRenderWindow) =
+  window.clear(Black)
+  window.draw chatBox
+  window.draw gui
+  window.draw fpsText
+  if showZonelist: window.draw zonelist
+  window.display()
+
diff --git a/tests/manyloc/keineschweine/enet_server/enet_server.nim b/tests/manyloc/keineschweine/enet_server/enet_server.nim
new file mode 100644
index 000000000..6dd1a6a7f
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/enet_server.nim
@@ -0,0 +1,294 @@
+import enet, strutils, idgen, tables, math_helpers, 
+  estreams, sg_packets, server_utils, sg_assets, client_helpers
+when appType == "gui":
+  import sfml, sfml_colors, sg_gui,
+    input_helpers, sfml_stuff
+else:
+  import times
+type
+  TCallback = proc(client: PClient; buffer: PBuffer)
+var
+  server: PHost
+  dirServer: PServer
+  standAloneMode = true
+  event: enet.TEvent
+  clientID = newIDGen[int32]()
+  clients = initTable[int32, PClient](64)
+  handlers = initTable[char, TCallback](32) 
+
+when appType == "gui":
+  var
+    gui = newGuiContainer()
+    chatBox = gui.newMessageArea(vec2f(15, 550))
+    window = newRenderWindow(videoMode(800, 600, 32), "Sup yo", sfDefaultSTyle)
+    mousepos = newText("", guiFont, 16)
+    fpsText = mousePos.copy()
+    inputClient = newKeyClient(setActive = true)
+  chatBox.sizeVisible = 30
+  mousePos.setColor(Green)
+  fpsText.setposition(vec2f(0, 20))
+  inputClient.registerHandler MouseLeft, down, proc() =
+    gui.click(input_helpers.getMousePos())
+  inputClient.registerHandler MouseMiddle, down, proc() =
+    let pos = input_helpers.getMousePos()
+    mousePos.setString("($1,$2)".format(ff(pos.x), ff(pos.y)))
+    mousePos.setPosition(pos)
+  proc dispMessage(args: varargs[string, `$`]) =
+    var s = ""
+    for it in items(args):
+      s.add it
+    chatbox.add(s)
+  proc dispError(args: varargs[string, `$`]) =
+    var s = ""
+    for it in items(args): s.add(it)
+    chatBox.add(newScChat(kind = CError, text = s))
+else:
+  proc dispMessage(args: varargs[string, `$`]) =
+    var m = ""
+    for it in items(args): m.add(it)
+    echo "<msg> ", m
+  proc dispError(args: varargs[string, `$`]) =
+    var m = ""
+    for it in items(args): m.add(it)
+    echo "**", m
+
+
+var pubChatQueue = newBuffer(1024)
+proc queuePub(sender: PClient, msg: CsChat) =
+  var chat = newScChat(kind = CPub, fromPlayer = sender.alias, text = msg.text)
+  pubChatQueue.write(HChat)
+  pubChatQueue.pack(chat)
+proc flushPubChat() =
+  if pubChatQueue.isDirty:
+    let packet = pubChatQueue.toPacket(FlagReliable)
+    for id, client in pairs(clients):
+      discard client.peer.send(0.cuchar, packet)
+    pubChatQueue.flush()
+
+handlers[HChat] = proc(client: PClient; buffer: PBuffer) =
+  var chat = readCsChat(buffer)
+  
+  if not client.auth:
+    client.sendError("You are not logged in.")
+    return
+  #if chat.target != "": ##private
+  #  if alias2client.hasKey(chat.target):
+  #    alias2client[chat.target].forwardPrivate(client, chat.text)
+  #else:
+  
+  dispmessage("<", client.alias, "> ", chat.text)
+  queuePub(client, chat)
+
+handlers[HLogin] = proc(client: PClient; buffer: PBuffer) =
+  var info = readCsLogin(buffer)
+  if client.auth:
+    client.sendError "You are already logged in."
+    return
+  client.alias = info.alias
+  client.auth = true
+  var resp = newScLogin(client.id, client.alias, "sessionkeylulz")
+  client.send HLogin, resp
+  client.sendMessage "welcome"
+  dispMessage("Client logged in: ", client)
+
+
+handlers[HFileTransfer] = server_utils.handleFilePartAck
+handlers[HFileChallenge] = server_utils.handleFileChallengeResp
+
+handlers[HZoneJoinReq] = proc(client: PClient; buffer: PBuffer) =
+  var info = readCsZoneJoinReq(buffer)
+  dispmessage "Got zone join request"
+  client.startVerifyingFiles()
+
+
+
+when isMainModule:
+  import parseopt, matchers, os, json
+  
+  
+  if enetInit() != 0:
+    quit "Could not initialize ENet"
+  
+  var address: enet.TAddress
+  
+  block:
+    var zoneCfgFile = "./server_settings.json"
+    for kind, key, val in getOpt():
+      case kind
+      of cmdShortOption, cmdLongOption:
+        case key
+        of "f", "file": 
+          if existsFile(val):
+            zoneCfgFile = val
+          else:
+            echo("File does not exist: ", val)
+        else:
+          echo("Unknown option: ", key," ", val)
+      else:
+        echo("Unknown option: ", key, " ", val)
+    var jsonSettings = parseFile(zoneCfgFile)
+    let 
+      port = uint16(jsonSettings["port"].num)
+      zoneFile = jsonSettings["settings"].str
+      dirServerInfo = jsonSettings["dirserver"]
+    
+    address.host = EnetHostAny
+    address.port = port
+    
+    var path = getAppDir()/../"data"/zoneFile
+    if not existsFile(path):
+      echo("Zone settings file does not exist: ../data/", zoneFile)
+      echo(path)
+      quit(1)
+    
+    discard """block:
+      var 
+        TestFile: FileChallengePair
+        contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz")
+      testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32) 
+      testFile.file = checksumStr(contents)
+      myAssets.add testFile"""
+    
+    setCurrentDir getAppDir().parentDir()
+    let zonesettings = readFile(path)
+    var 
+      errors: seq[string] = @[]
+    if not loadSettings(zoneSettings, errors):
+      echo("You have errors in your zone settings:")
+      for e in errors: echo("**", e)
+      quit(1)
+    errors.setLen 0
+    
+    var pair: FileChallengePair
+    pair.challenge.file = zoneFile
+    pair.challenge.assetType = FZoneCfg
+    pair.challenge.fullLen = zoneSettings.len.int32
+    pair.file = checksumStr(zoneSettings)
+    myAssets.add pair
+    
+    allAssets:
+      if not load(asset):
+        echo "Invalid or missing file ", file
+      else:
+        var pair: FileChallengePair
+        pair.challenge.file = file
+        pair.challenge.assetType = assetType
+        pair.challenge.fullLen = getFileSize(
+          expandPath(assetType, file)).int32
+        pair.file = asset.contents
+        myAssets.add pair
+    
+    echo "Zone has ", myAssets.len, " associated assets"
+    
+    dirServer = newServer()
+    
+    dirServer.addHandler HDsMsg, proc(serv: PServer; buffer: PBuffer) =
+      var m = readDsMsg(buffer)
+      dispMessage("<DirServer> ", m.msg)
+    dirServer.addHandler HZoneLogin, proc(serv: PServer; buffer: PBuffer) =
+      let loggedIn = readDsZoneLogin(buffer).status
+      if loggedIn:
+        #dirServerConnected = true
+    
+    if dirServerInfo.kind == JArray:
+      var error: string
+      if not dirServer.connect(dirServerInfo[0].str, dirServerInfo[1].num.int16, error):
+        dispError("<DirServer> "&error)
+    
+  
+  server = enet.createHost(address, 32, 2,  0,  0)
+  if server == nil:
+    quit "Could not create the server!"
+  
+  dispMessage("Listening on port ", address.port)
+  
+  var 
+    serverRunning = true
+  when appType == "gui":
+    var frameRate = newClock()
+    var pubChatDelay = newClock()
+  else:
+    var frameRate = epochTime()
+    var pubChatDelay = frameRate
+  
+  while serverRunning:
+    when appType == "gui":
+      let dt = frameRate.restart.asMilliseconds().float / 1000.0
+      
+      for event in window.filterEvents():
+        case event.kind
+        of sfml.EvtClosed:
+          window.close()
+          serverRunning = false
+        else:
+          discard
+    else:
+      let dt = epochTime() - frameRate ##is this right? probably not
+      frameRate = epochTime()
+    
+    while server.hostService(event, 10) > 0:
+      case event.kind
+      of EvtConnect:
+        var client = newClient()
+        clients[client.id] = client
+
+        event.peer.data = addr client.id
+        client.peer = event.peer
+        
+        dispMessage("New client connected ", client)
+        
+        var
+          msg = "hello" 
+          resp = createPacket(cstring(msg), msg.len + 1, FlagReliable)
+          
+        if event.peer.send(0.cuchar, resp) < 0:
+          echo "FAILED"
+        else:
+          echo "Replied"
+      of EvtReceive:
+        let client = clients[cast[ptr int32](event.peer.data)[]] 
+        
+        var buf = newBuffer(event.packet)
+        let k = buf.readChar()
+        if handlers.hasKey(k):
+          handlers[k](client, buf)
+        else:
+          dispError("Unknown packet from ", client)
+        
+        destroy(event.packet)
+      of EvtDisconnect:
+        var
+          id = cast[ptr int32](event.peer.data)[]
+          client = clients[id]
+        if client.isNil:
+          disperror("CLIENT IS NIL!")
+          dispmessage(event.peer.data.isNil)
+        else:
+          dispMessage(clients[id], " disconnected")
+          GCUnref(clients[id])
+          clients.del id
+        
+        event.peer.data = nil
+      else:
+        discard
+    
+    when appType == "gui":
+      fpsText.setString(ff(1.0/dt))
+      if pubChatDelay.getElapsedTime.asSeconds > 0.25:
+        pubChatDelay.restart()
+        flushPubChat()
+    else:
+      pubChatDelay -= dt
+      if frameRate - pubChatDelay > 0.25:
+        flushPubChat()
+    
+    when appType == "gui":
+      window.clear(Black)
+      window.draw(GUI)
+      window.draw chatbox
+      window.draw mousePos
+      window.draw fpstext
+      window.display()  
+
+  server.destroy()
+  enetDeinit()
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/enet_server/nakefile.nim b/tests/manyloc/keineschweine/enet_server/nakefile.nim
new file mode 100644
index 000000000..1ca93a340
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/nakefile.nim
@@ -0,0 +1,13 @@
+import nake
+nakeimports
+
+const
+  ServerDefines = "-d:NoSFML --forceBuild"
+
+task "server", "build the server":
+  if shell("nimrod", ServerDefines, "-r", "compile", "enet_server") != 0:
+    quit "Failed to build"
+task "gui", "build the server GUI mode":
+  if shell("nimrod", "--app:gui", ServerDefines, "-r", "compile", "enet_server") != 0:
+    quit "Failed to build"
+
diff --git a/tests/manyloc/keineschweine/enet_server/nimrod.cfg b/tests/manyloc/keineschweine/enet_server/nimrod.cfg
new file mode 100644
index 000000000..72ef47ee0
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/nimrod.cfg
@@ -0,0 +1,9 @@
+path = ".."
+path = "../dependencies/sfml"
+path = "../dependencies/enet"
+path = "../dependencies/nake"
+path = "../dependencies/genpacket"
+path = "../lib"
+define = "noChipmunk"
+define = "noSFML"
+
diff --git a/tests/manyloc/keineschweine/enet_server/server_settings.json b/tests/manyloc/keineschweine/enet_server/server_settings.json
new file mode 100644
index 000000000..7d2f1d822
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/server_settings.json
@@ -0,0 +1,8 @@
+{
+ "name": "Alpha Zone",
+ "desc": "Beta Testing",
+ "host": "localhost",
+ "port": 8024,
+ "settings": "alphazone.json",
+ "dirserver":["localhost",2049,"alphazone","skittles"]
+}
diff --git a/tests/manyloc/keineschweine/enet_server/server_utils.nim b/tests/manyloc/keineschweine/enet_server/server_utils.nim
new file mode 100644
index 000000000..8e8141075
--- /dev/null
+++ b/tests/manyloc/keineschweine/enet_server/server_utils.nim
@@ -0,0 +1,120 @@
+import enet, sg_packets, estreams, md5, zlib_helpers, client_helpers, strutils,
+  idgen, sg_assets, tables, os
+type
+  PClient* = ref object
+    id*: int32
+    auth*: bool
+    alias*: string
+    peer*: PPeer
+  
+  FileChallengePair* = tuple[challenge: ScFileChallenge; file: TChecksumFile]
+  PFileChallengeSequence* = ref TFileChallengeSequence 
+  TFileChallengeSequence = object
+    index: int  #which file is active
+    transfer: ScFileTransfer
+    file: ptr FileChallengePair
+var
+  clientID = newIdGen[int32]()
+  myAssets*: seq[FileChallengePair] = @[]
+  fileChallenges = initTable[int32, PFileChallengeSequence](32)
+const FileChunkSize = 256
+
+proc free(client: PClient) =
+  if client.id != 0:
+    fileChallenges.del client.id
+    clientID.del client.id
+proc newClient*(): PClient =
+  new(result, free)
+  result.id = clientID.next()
+  result.alias = "billy"
+
+proc `$`*(client: PClient): string =
+  result = "$1:$2".format(client.id, client.alias)
+
+proc send*[T](client: PClient; pktType: char; pkt: var T) =
+  var buf = newBuffer(128)
+  buf.write pktType
+  buf.pack pkt
+  discard client.peer.send(0.cuchar, buf, flagReliable)
+
+proc sendMessage*(client: PClient; txt: string) =
+  var m = newScChat(CSystem, text = txt)
+  client.send HChat, m
+proc sendError*(client: PClient; error: string) =
+  var m = newScChat(CError, text = error)
+  client.send HChat, m
+
+
+
+
+proc next*(challenge: PFileChallengeSequence, client: PClient)
+proc sendChunk*(challenge: PFileChallengeSequence, client: PClient)
+
+proc startVerifyingFiles*(client: PClient) =
+  var fcs: PFileChallengeSequence
+  new(fcs)
+  fcs.index = -1
+  fileChallenges[client.id] = fcs
+  next(fcs, client)
+
+proc next*(challenge: PFileChallengeSequence, client: PClient) =
+  inc(challenge.index)
+  if challenge.index >= myAssets.len:
+    client.sendMessage "You are cleared to enter"
+    fileChallenges.del client.id
+    return
+  else:
+    echo myAssets.len, "assets"
+  challenge.file = addr myAssets[challenge.index]
+  client.send HFileChallenge, challenge.file.challenge # :rolleyes:
+  echo "sent challenge"
+
+proc sendChunk*(challenge: PFileChallengeSequence, client: PClient) =
+  let size = min(FileChunkSize, challenge.transfer.fileSize - challenge.transfer.pos)
+  challenge.transfer.data.setLen size
+  copyMem(
+    addr challenge.transfer.data[0], 
+    addr challenge.file.file.compressed[challenge.transfer.pos],
+    size)
+  client.send HFileTransfer, challenge.transfer
+  echo "chunk sent"
+
+proc startSend*(challenge: PFileChallengeSequence, client: PClient) =
+  challenge.transfer.fileSize = challenge.file.file.compressed.len().int32
+  challenge.transfer.pos = 0
+  challenge.transfer.data = ""
+  challenge.transfer.data.setLen FileChunkSize
+  challenge.sendChunk(client)
+  echo "starting xfer"
+
+## HFileTransfer
+proc handleFilePartAck*(client: PClient; buffer: PBuffer) =
+  echo "got filepartack"
+  var 
+    ftrans = readCsFilepartAck(buffer)
+    fcSeq = fileChallenges[client.id]
+  fcSeq.transfer.pos = ftrans.lastPos
+  fcSeq.sendChunk client
+
+## HFileCHallenge
+proc handleFileChallengeResp*(client: PClient; buffer: PBuffer) =
+  echo "got file challenge resp"
+  var 
+    fcResp = readCsFileChallenge(buffer)
+    fcSeq = fileChallenges[client.id]
+  let index = $(fcSeq.index + 1) / $(myAssets.len)
+  if fcResp.needFile:
+    client.sendMessage "Sending file... "&index
+    fcSeq.startSend(client)
+  else:
+    var resp = newScChallengeResult(false)
+    if fcResp.checksum == fcSeq.file.file.sum: ##client is good
+      client.sendMessage "Checksum is good. "&index
+      resp.status = true
+      client.send HChallengeResult, resp
+      fcSeq.next(client)
+    else:
+      client.sendMessage "Checksum is bad, sending file... "&index
+      client.send HChallengeResult, resp
+      fcSeq.startSend(client)
+
diff --git a/tests/manyloc/keineschweine/keineschweine.nim b/tests/manyloc/keineschweine/keineschweine.nim
new file mode 100644
index 000000000..e868b96a5
--- /dev/null
+++ b/tests/manyloc/keineschweine/keineschweine.nim
@@ -0,0 +1,725 @@
+import 
+  os, math, strutils, gl, tables,
+  sfml, sfml_audio, sfml_colors, chipmunk, math_helpers,
+  input_helpers, animations, game_objects, sfml_stuff, map_filter,
+  sg_gui, sg_assets, sound_buffer, enet_client
+when defined(profiler):
+  import nimprof
+{.deadCodeElim: on.}
+type
+  PPlayer* = ref TPlayer
+  TPlayer* = object
+    id: uint16
+    vehicle: PVehicle
+    spectator: bool
+    alias: string
+    nameTag: PText
+    items: seq[PItem]
+  PVehicle* = ref TVehicle
+  TVehicle* = object
+    body*:      chipmunk.PBody
+    shape*:     chipmunk.PShape
+    record*:   PVehicleRecord
+    sprite*:   PSprite
+    spriteRect*: TIntRect
+    occupant: PPlayer
+    when false:
+      position*: TVector2f
+      velocity*: TVector2f
+      angle*:    float
+  PItem* = ref object
+    record: PItemRecord
+    cooldown: float 
+  PLiveBullet* = ref TLiveBullet ##represents a live bullet in the arena
+  TLiveBullet* = object
+    lifetime*: float
+    dead: bool
+    anim*: PAnimation
+    record*: PBulletRecord
+    fromPlayer*: PPlayer
+    trailDelay*: float
+    body: chipmunk.PBody
+    shape: chipmunk.PShape
+import vehicles
+const
+  LGrabbable*  = (1 shl 0).TLayers
+  LBorders*    = (1 shl 1).TLayers
+  LPlayer*     = ((1 shl 2) and LBorders.int).TLayers
+  LEnemy*      = ((1 shl 4) and LBorders.int).TLayers
+  LEnemyFire*  = (LPlayer).TLayers
+  LPlayerFire* = (LEnemy).TLayers
+  CTBullet = 1.TCollisionType
+  CTVehicle= 2.TCollisionType
+  ##temporary constants
+  W_LIMIT = 2.3
+  V_LIMIT = 35
+  MaxLocalBots = 3
+var
+  localPlayer: PPlayer
+  localBots: seq[PPlayer] = @[]
+  activeVehicle: PVehicle
+  myVehicles: seq[PVehicle] = @[]
+  objects: seq[PGameObject] = @[]
+  liveBullets: seq[PLiveBullet] = @[]
+  explosions: seq[PAnimation] = @[]
+  gameRunning = true
+  frameRate = newClock()
+  showStars = off
+  levelArea: TIntRect
+  videoMode: TVideoMode
+  window: PRenderWindow
+  worldView: PView
+  guiView: PView
+  space = newSpace()
+  ingameClient = newKeyClient("ingame")
+  specInputClient = newKeyClient("spec")
+  specGui = newGuiContainer()
+  stars: seq[PSpriteSheet] = @[]
+  playBtn: PButton
+  shipSelect = newGuiContainer()
+  delObjects: seq[int] = @[]
+  showShipSelect = false
+  myPosition: array[0..1, TVector3f] ##for audio positioning
+let 
+  nameTagOffset = vec2f(0.0, 1.0)
+when defined(escapeMenuTest):
+  import browsers
+  var
+    escMenu = newGuiContainer(vec2f(100, 100))
+    escMenuOpen = false
+    pos = vec2f(0, 0)
+  escMenu.newButton("Some Website", pos, proc(b: PButton) =
+    openDefaultBrowser(getClientSettings().website))
+  pos.y += 20.0
+  escMenu.newButton("Back to Lobby", pos, proc(b: PButton) =
+    echo "herro")
+  proc toggleEscape() =
+    escMenuOpen = not escMenuOpen
+  ingameClient.registerHandler(KeyEscape, down, toggleEscape)
+  specInputClient.registerHandler(KeyEscape, down, toggleEscape)
+when defined(foo):
+  var mouseSprite: sfml.PCircleShape
+when defined(recordMode):
+  var 
+    snapshots: seq[PImage] = @[]
+    isRecording = false
+  proc startRecording() = 
+    if snapshots.len > 100: return
+    echo "Started recording"
+    isRecording = true
+  proc stopRecording() =
+    if isRecording:
+      echo "Stopped recording. ", snapshots.len, " images."
+    isRecording = false
+  proc zeroPad*(s: string; minLen: int): string =
+    if s.len < minLen:
+      result = repeatChar(minLen - s.len, '0')
+      result.add s
+    else:
+      result = s
+  var
+    recordButton = newButton(
+      nil, text = "Record", position = vec2f(680, 50),
+      onClick = proc(b: PButton) = startRecording())
+
+proc newNameTag*(text: string): PText =
+  result = newText()
+  result.setFont(guiFont)
+  result.setCharacterSize(14)
+  result.setColor(Red)
+  result.setString(text)
+
+var debugText = newNameTag("Loading...")
+debugText.setPosition(vec2f(0.0, 600.0 - 50.0))
+
+when defined(showFPS):
+  var fpsText = newNameTag("0")
+  #fpsText.setCharacterSize(16)
+  fpsText.setPosition(vec2f(300.0, (800 - 50).float))
+
+proc mouseToSpace*(): TVector =
+  result = window.convertCoords(vec2i(getMousePos()), worldView).sfml2cp()
+
+proc explode*(b: PLiveBullet)
+## TCollisionBeginFunc
+proc collisionBulletPlayer(arb: PArbiter; space: PSpace; 
+                            data: pointer): Bool{.cdecl.} =
+  var 
+    bullet = cast[PLiveBullet](arb.a.data)
+    target = cast[PVehicle](arb.b.data)
+  if target.occupant.isNil or target.occupant == bullet.fromPlayer: return
+  bullet.explode()
+
+proc angularDampingSim(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} =
+  body.w -= (body.w * 0.98 * dt) 
+  body.updateVelocity(gravity, damping, dt)
+
+proc initLevel() =
+  loadAllAssets()
+  
+  if not space.isNil: space.destroy()
+  space = newSpace()
+  space.addCollisionHandler CTBullet, CTVehicle, collisionBulletPlayer,
+    nil, nil, nil, nil
+  
+  let levelSettings = getLevelSettings()
+  levelArea.width = levelSettings.size.x
+  levelArea.height= levelSettings.size.y
+  let borderSeq = @[
+    vector(0, 0), vector(levelArea.width.float, 0.0),
+    vector(levelArea.width.float, levelArea.height.float), vector(0.0, levelArea.height.float)]
+  for i in 0..3:
+    var seg = space.addShape(
+      newSegmentShape(
+        space.staticBody, 
+        borderSeq[i], 
+        borderSeq[(i + 1) mod 4],
+        8.0))
+    seg.setElasticity 0.96
+    seg.setLayers(LBorders)
+  if levelSettings.starfield.len > 0:
+    showStars = true
+    for sprite in levelSettings.starfield:
+      sprite.tex.setRepeated(true)
+      sprite.sprite.setTextureRect(levelArea)
+      sprite.sprite.setOrigin(vec2f(0, 0))
+      stars.add(sprite)
+  var pos = vec2f(0.0, 0.0)
+  for veh in playableVehicles():
+    shipSelect.newButton(
+      veh.name,
+      position = pos, 
+      onClick = proc(b: PButton) = 
+        echo "-__-")
+    pos.y += 18.0
+
+
+proc newItem*(record: PItemRecord): PItem =
+  new(result)
+  result.record = record
+proc newItem*(name: string): PItem {.inline.} =
+  return newItem(fetchItm(name))
+proc canUse*(itm: PItem): bool = 
+  if itm.cooldown > 0.0: return
+  return true
+proc update*(itm: PItem; dt: float) =
+  if itm.cooldown > 0:
+    itm.cooldown -= dt
+
+proc free(obj: PLiveBullet) =
+  obj.shape.free
+  obj.body.free
+  obj.record = nil
+
+
+template newExplosion(obj, animation): stmt =
+  explosions.add(newAnimation(animation, AnimOnce, obj.body.getPos.cp2sfml, obj.body.getAngle))
+template newExplosion(obj, animation, angle): stmt =
+  explosions.add(newAnimation(animation, AnimOnce, obj.body.getPos.cp2sfml, angle))
+
+proc explode*(b: PLiveBullet) =
+  if b.dead: return
+  b.dead = true
+  space.removeShape b.shape
+  space.removeBody b.body
+  if not b.record.explosion.anim.isNil:
+    newExplosion(b, b.record.explosion.anim)
+  playSound(b.record.explosion.sound, b.body.getPos())
+
+proc bulletUpdate(body: PBody, gravity: TVector, damping, dt: CpFloat){.cdecl.} =
+  body.updateVelocity(gravity, damping, dt)
+
+template getPhysical() {.immediate.} =
+  result.body = space.addBody(newBody(
+    record.physics.mass,
+    record.physics.moment))
+  result.shape = space.addShape(
+    chipmunk.newCircleShape(
+      result.body,
+      record.physics.radius,
+      vectorZero))
+
+proc newBullet*(record: PBulletRecord; fromPlayer: PPlayer): PLiveBullet =
+  new(result, free)
+  result.anim = newAnimation(record.anim, AnimLoop)
+  result.fromPlayer = fromPlayer
+  result.lifetime = record.lifetime
+  result.record = record
+  getPhysical()
+  if fromPlayer == localPlayer:
+    result.shape.setLayers(LPlayerFire)
+  else:
+    result.shape.setLayers(LEnemyFire)
+  result.shape.setCollisionType CTBullet
+  result.shape.setUserData(cast[ptr TLiveBullet](result))
+  let 
+    fireAngle = fromPlayer.vehicle.body.getAngle()
+    fireAngleV = vectorForAngle(fireAngle)
+  result.body.setAngle fireAngle
+  result.body.setPos(fromPlayer.vehicle.body.getPos() + (fireAngleV * fromPlayer.vehicle.shape.getCircleRadius()))
+  #result.body.velocityFunc = bulletUpdate
+  result.body.setVel((fromPlayer.vehicle.body.getVel() * record.inheritVelocity) + (fireAngleV * record.baseVelocity))
+
+proc update*(b: PLiveBullet; dt: float): bool =
+  if b.dead: return true
+  b.lifetime -= dt
+  b.anim.next(dt)
+  #b.anim.sprite.setPosition(b.body.getPos.floor())
+  b.anim.setPos(b.body.getPos)
+  b.anim.setAngle(b.body.getAngle())
+  if b.lifetime <= 0.0:
+    b.explode()
+    return true
+  b.trailDelay -= dt
+  if b.trailDelay <= 0.0:
+    b.trailDelay += b.record.trail.timer
+    if b.record.trail.anim.isNil: return
+    newExplosion(b, b.record.trail.anim)
+proc draw*(window: PRenderWindow; b: PLiveBullet) {.inline.} =
+  draw(window, b.anim.sprite)
+
+
+proc free*(veh: PVehicle) =
+  ("Destroying vehicle "& veh.record.name).echo
+  destroy(veh.sprite)
+  if veh.shape.isNil: "Free'd vehicle's shape was NIL!".echo
+  else: space.removeShape(veh.shape)
+  if veh.body.isNil: "Free'd vehicle's BODY was NIL!".echo
+  else: space.removeBody(veh.body)
+  veh.body.free()
+  veh.shape.free()
+  veh.sprite = nil
+  veh.body   = nil
+  veh.shape  = nil
+
+
+proc newVehicle*(record: PVehicleRecord): PVehicle =
+  echo("Creating "& record.name)
+  new(result, free)
+  result.record = record
+  result.sprite = result.record.anim.spriteSheet.sprite.copy()
+  result.spriteRect = result.sprite.getTextureRect()
+  getPhysical()
+  result.body.setAngVelLimit W_LIMIT
+  result.body.setVelLimit result.record.handling.topSpeed
+  result.body.velocityFunc = angularDampingSim
+  result.shape.setCollisionType CTVehicle
+  result.shape.setUserData(cast[ptr TVehicle](result))
+proc newVehicle*(name: string): PVehicle =
+  result = newVehicle(fetchVeh(name))
+
+proc update*(obj: PVehicle) =
+  obj.sprite.setPosition(obj.body.getPos.floor)
+  obj.spriteRect.left = (((-obj.body.getAngVel + W_LIMIT) / (W_LIMIT*2.0) * (obj.record.anim.spriteSheet.cols - 1).float).floor.int * obj.record.anim.spriteSheet.framew).cint
+  obj.spriteRect.top = ((obj.offsetAngle.wmod(TAU) / TAU) * obj.record.anim.spriteSheet.rows.float).floor.cint * obj.record.anim.spriteSheet.frameh.cint
+  obj.sprite.setTextureRect(obj.spriteRect)
+
+
+proc newPlayer*(alias: string = "poo"): PPlayer =
+  new(result)
+  result.spectator = true
+  result.alias     = alias
+  result.nameTag   = newNameTag(result.alias)
+  result.items     = @[]
+proc updateItems*(player: PPlayer, dt: float) =
+  for i in items(player.items):
+    update(i, dt)
+proc addItem*(player: PPlayer; name: string) =
+  player.items.add newItem(name)
+proc useItem*(player: PPlayer; slot: int) =
+  if slot > player.items.len - 1: return
+  let item = player.items[slot]
+  if item.canUse:
+    item.cooldown += item.record.cooldown
+    let b = newBullet(item.record.bullet, player)
+    liveBullets.add(b)
+    sound_buffer.playSound(item.record.useSound, b.body.getPos)
+
+proc update*(obj: PPlayer) =
+  if not obj.spectator:
+    obj.vehicle.update()
+    obj.nameTag.setPosition(obj.vehicle.body.getPos.floor + (nameTagOffset * (obj.vehicle.record.physics.radius + 5).cfloat))
+
+proc draw(window: PRenderWindow, player: PPlayer) {.inline.} =
+  if not player.spectator: 
+    if player.vehicle != nil:
+      window.draw(player.vehicle.sprite)
+    window.draw(player.nameTag)
+
+proc setVehicle(p: PPlayer; v: PVehicle) = 
+  p.vehicle = v  #sorry mom, this is just how things worked out ;(
+  if not v.isNil: 
+    v.occupant = p
+
+proc createBot() =
+  if localBots.len < MaxLocalBots:
+    var bot = newPlayer("Dodo Brown")
+    bot.setVehicle(newVehicle("Turret0"))
+    if bot.isNil:
+      echo "BOT IS NIL"
+      return
+    elif bot.vehicle.isNil:
+      echo "BOT VEH IS NIL"
+      return
+    localBots.add(bot)
+    bot.vehicle.body.setPos(vector(100, 100))
+    echo "new bot at ", $bot.vehicle.body.getPos()
+
+var inputCursor = newVertexArray(sfml.Lines, 2)
+inputCursor[0].position = vec2f(10.0, 10.0)
+inputCursor[1].position = vec2f(50.0, 90.0)
+
+proc hasVehicle(p: PPlayer): bool {.inline.} = 
+  result = not p.spectator and not p.vehicle.isNil
+
+proc setMyVehicle(v: PVehicle) {.inline.} =
+  activeVehicle = v
+  localPlayer.setVehicle v
+
+proc unspec() =
+  var veh = newVehicle("Turret0")
+  if not veh.isNil:
+    setMyVehicle veh
+    localPlayer.spectator = false
+    ingameClient.setActive
+    veh.body.setPos vector(100, 100)
+    veh.shape.setLayers(LPlayer)
+    when defined(debugWeps):
+      localPlayer.addItem("Mass Driver")
+      localPlayer.addItem("Neutron Bomb")
+      localPlayer.additem("Dem Lasers")
+      localPlayer.addItem("Mold Spore Beam")
+      localPlayer.addItem("Genericorp Mine")
+      localPlayer.addItem("Gravitic Bomb")
+proc spec() =
+  setMyVehicle nil
+  localPlayer.spectator = true
+  specInputClient.setActive
+
+var 
+  specLimiter = newClock()
+  timeBetweenSpeccing = 1.0 #seconds
+proc toggleSpec() {.inline.} =
+  if specLimiter.getElapsedTime.asSeconds < timeBetweenSpeccing:
+    return
+  specLimiter.restart()
+  if localPlayer.isNil: 
+    echo("OMG WTF PLAYER IS NILL!!")
+  elif localPlayer.spectator: unspec()
+  else: spec()
+
+proc addObject*(name: string) =
+  var o = newObject(name)
+  if not o.isNil: 
+    echo "Adding object ", o
+    discard space.addBody(o.body)
+    discard space.addShape(o.shape)
+    o.shape.setLayers(LGrabbable)
+    objects.add(o)
+proc explode(obj: PGameObject) = 
+  echo obj, " exploded"
+  let ind = objects.find(obj)
+  if ind != -1:
+    delObjects.add ind
+proc update(obj: PGameObject; dt: float) =
+  if not(obj.anim.next(dt)):
+    obj.explode()
+  else:
+    obj.anim.setPos(obj.body.getPos)
+    obj.anim.setAngle(obj.body.getAngle)
+
+proc toggleShipSelect() = 
+  showShipSelect = not showShipSelect
+proc handleLClick() =
+  let pos = input_helpers.getMousePos()
+  when defined(escapeMenuTest):
+    if escMenuOpen:
+      escMenu.click(pos)
+      return
+  if showShipSelect:
+    shipSelect.click(pos)
+  if localPlayer.spectator:
+    specGui.click(pos)
+
+ingameClient.registerHandler(KeyF12, down, proc() = toggleSpec())
+ingameClient.registerHandler(KeyF11, down, toggleShipSelect)
+ingameClient.registerHandler(MouseLeft, down, handleLClick)
+when defined(recordMode):
+  if not existsDir("data/snapshots"):
+    createDir("data/snapshots")
+  ingameClient.registerHandler(keynum9, down, proc() =
+    if not isRecording: startRecording()
+    else: stopRecording())
+  ingameClient.registerHandler(keynum0, down, proc() =
+    if snapshots.len > 0 and not isRecording:
+      echo "Saving images (LOL)"
+      for i in 0..high(snapshots):
+        if not(snapshots[i].save("data/snapshots/image"&(zeroPad($i, 3))&".jpg")):
+          echo "Could not save"
+        snapshots[i].destroy()
+      snapshots.setLen 0)
+when defined(DebugKeys):
+  ingameClient.registerHandler MouseRight, down, proc() = 
+    echo($activevehicle.body.getAngle.vectorForAngle())
+  ingameClient.registerHandler KeyBackslash, down, proc() = 
+    createBot()
+  ingameClient.registerHandler(KeyNum1, down, proc() =
+    if localPlayer.items.len == 0:
+      localPlayer.addItem("Mass Driver")
+      echo "Gave you a mass driverz")
+  ingameClient.registerHandler(KeyL, down, proc() =
+    echo("len(livebullets) = ", len(livebullets)))
+  ingameClient.registerHandler(KeyRShift, down, proc() =
+    if keyPressed(KeyR):
+      echo("Friction: ", ff(activeVehicle.shape.getFriction()))
+      echo("Damping: ", ff(space.getDamping()))
+    elif keypressed(KeyM):
+      echo("Mass: ", activeVehicle.body.getMass.ff())
+      echo("Moment: ", activeVehicle.body.getMoment.ff())
+    elif keypressed(KeyI):
+      echo(repr(activeVehicle.record))
+    elif keyPressed(KeyH):
+      activeVehicle.body.setPos(vector(100.0, 100.0))
+      activeVehicle.body.setVel(vectorZero)
+    elif keyPressed(KeyComma):
+      activeVehicle.body.setPos mouseToSpace())
+  ingameClient.registerHandler(KeyY, down, proc() =
+    const looloo = ["Asteroid1", "Asteroid2"]
+    addObject(looloo[random(looloo.len)]))
+  ingameClient.registerHandler(KeyO, down, proc() =
+    if objects.len == 0:
+      echo "Objects is empty"
+      return
+    for i, o in pairs(objects):
+      echo i, " ", o)
+  ingameClient.registerHandler(KeyLBracket, down, sound_buffer.report)
+  var 
+    mouseJoint: PConstraint
+    mouseBody = space.addBody(newBody(CpInfinity, CpInfinity))
+  ingameClient.registerHandler(MouseMiddle, down, proc() =
+    var point = mouseToSpace()
+    var shape = space.pointQueryFirst(point, LGrabbable, 0)
+    if not mouseJoint.isNil:
+      space.removeConstraint mouseJoint
+      mouseJoint.destroy()
+      mouseJoint = nil
+    if shape.isNil: 
+      return
+    let body = shape.getBody()
+    mouseJoint = space.addConstraint(
+      newPivotJoint(mouseBody, body, vectorZero, body.world2local(point)))
+    mouseJoint.maxForce = 50000.0
+    mouseJoint.errorBias = pow(1.0 - 0.15, 60))
+
+var specCameraSpeed = 5.0
+specInputClient.registerHandler(MouseLeft, down, handleLClick)
+specInputClient.registerHandler(KeyF11, down, toggleShipSelect)
+specInputClient.registerHandler(KeyF12, down, proc() = toggleSpec())
+specInputClient.registerHandler(KeyLShift, down, proc() = specCameraSpeed *= 2)
+specInputClient.registerHandler(KeyLShift, up, proc() = specCameraSpeed /= 2)
+
+specInputClient.registerHandler(KeyP, down, proc() =
+  echo("addObject(solar mold)")
+  addObject("Solar Mold"))
+
+proc resetForcesCB(body: PBody; data: pointer) {.cdecl.} =
+  body.resetForces()
+
+var frameCount= 0
+proc mainUpdate(dt: float) =
+  if localPlayer.spectator:
+    if keyPressed(KeyLeft):
+      worldView.move(vec2f(-1.0, 0.0) * specCameraSpeed)
+    elif keyPressed(KeyRight):
+      worldView.move(vec2f( 1.0, 0.0) * specCameraSpeed)
+    if keyPressed(KeyUp):
+      worldView.move(vec2f(0.0, -1.0) * specCameraSpeed)
+    elif keyPressed(KeyDown):
+      worldView.move(vec2f(0.0,  1.0) * specCameraSpeed)
+  elif not activeVehicle.isNil:
+    if keyPressed(KeyUp):
+      activeVehicle.accel(dt)
+    elif keyPressed(keyDown):
+      activeVehicle.reverse(dt)
+    if keyPressed(KeyRight):
+      activeVehicle.turn_right(dt)
+    elif keyPressed(KeyLeft):
+      activeVehicle.turn_left(dt)
+    if keyPressed(keyz):
+      activeVehicle.strafe_left(dt)
+    elif keyPressed(keyx):
+      activeVehicle.strafe_right(dt)
+    if keyPressed(KeyLControl):
+      localPlayer.useItem 0
+    if keyPressed(KeyTab):
+      localPlayer.useItem 1
+    if keyPressed(KeyQ):
+      localPlayer.useItem 2
+    if keyPressed(KeyW):
+      localPlayer.useItem 3
+    if Keypressed(keyA):
+      localPlayer.useItem 4
+    if keyPressed(sfml.KeyS):
+      localPlayer.useItem 5
+    if keyPressed(KeyD):
+      localPlayer.useItem 6
+    worldView.setCenter(activeVehicle.body.getPos.floor)#cp2sfml)
+  
+  if localPlayer != nil: 
+    localPlayer.update()
+    localPlayer.updateItems(dt)
+  for b in localBots:
+    b.update()
+  
+  for o in items(objects):
+    o.update(dt)
+  for i in countdown(high(delObjects), 0):
+    objects.del i
+  delObjects.setLen 0
+  
+  var i = 0
+  while i < len(liveBullets):
+    if liveBullets[i].update(dt):
+      liveBullets.del i
+    else: 
+      inc i
+  i = 0
+  while i < len(explosions):
+    if explosions[i].next(dt): inc i
+    else: explosions.del i
+  
+  when defined(DebugKeys):
+    mouseBody.setPos(mouseToSpace())
+  
+  space.step(dt)
+  space.eachBody(resetForcesCB, nil)
+  
+  when defined(foo):
+    var coords = window.convertCoords(vec2i(getMousePos()), worldView)
+    mouseSprite.setPosition(coords)
+  
+  if localPlayer != nil and localPlayer.vehicle != nil:
+    let 
+      pos = localPlayer.vehicle.body.getPos()
+      ang = localPlayer.vehicle.body.getAngle.vectorForAngle()
+    myPosition[0].x = pos.x
+    myPosition[0].z = pos.y
+    myPosition[1].x = ang.x
+    myPosition[1].z = ang.y
+    listenerSetPosition(myPosition[0])
+    listenerSetDirection(myPosition[1])
+  
+  inc frameCount
+  when defined(showFPS):
+    if frameCount mod 60 == 0:
+      fpsText.setString($(1.0/dt).round)
+  if frameCount mod 250 == 0:
+    updateSoundBuffer()
+    frameCount = 0
+
+proc mainRender() =
+  window.clear(Black)
+  window.setView(worldView)
+  
+  if showStars:
+    for star in stars:
+      window.draw(star.sprite)
+  window.draw(localPlayer)
+  
+  for b in localBots:
+    window.draw(b)
+  for o in objects:
+    window.draw(o)
+  
+  for b in explosions: window.draw(b)
+  for b in liveBullets: window.draw(b)
+  
+  when defined(Foo):
+    window.draw(mouseSprite)
+  
+  window.setView(guiView)
+  
+  when defined(EscapeMenuTest):
+    if escMenuOpen:
+      window.draw escMenu
+  when defined(showFPS):
+    window.draw(fpsText)
+  when defined(recordMode):
+    window.draw(recordButton)
+  
+  if localPlayer.spectator:
+    window.draw(specGui)
+  if showShipSelect: window.draw shipSelect
+  window.display()
+  
+  when defined(recordMode):
+    if isRecording:
+      if snapshots.len < 100:
+        if frameCount mod 5 == 0:
+          snapshots.add(window.capture())
+      else: stopRecording()
+
+proc readyMainState() =
+  specInputClient.setActive()
+
+when isMainModule:
+  import parseopt
+  
+  localPlayer = newPlayer()
+  LobbyInit()
+  
+  videoMode = getClientSettings().resolution
+  window = newRenderWindow(videoMode, "sup", sfDefaultStyle)
+  window.setFrameRateLimit 60
+  
+  worldView = window.getView.copy()
+  guiView = worldView.copy()
+  shipSelect.setPosition vec2f(665.0, 50.0)
+  
+  when defined(foo):
+    mouseSprite = sfml.newCircleShape(14)
+    mouseSprite.setFillColor Transparent
+    mouseSprite.setOutlineColor RoyalBlue
+    mouseSprite.setOutlineThickness 1.4
+    mouseSprite.setOrigin vec2f(14, 14)
+  
+  LobbyReady()
+  playBtn = specGui.newButton(
+    "Unspec - F12", position = vec2f(680.0, 8.0), onClick = proc(b: PButton) =
+      toggleSpec())
+  
+  block:
+    var bPlayOffline = false
+    for kind, key, val in getOpt():
+      case kind
+      of cmdArgument:
+        if key == "offline": bPlayOffline = true
+      else:
+        echo "Invalid argument ", key, " ", val
+    if bPlayOffline:
+      playoffline(nil)
+  
+  gameRunning = true
+  while gameRunning:
+    for event in window.filterEvents:
+      if event.kind == EvtClosed:
+        gameRunning = false
+        break
+      elif event.kind == EvtMouseWheelMoved and getActiveState() == Field:
+        if event.mouseWheel.delta == 1:
+          worldView.zoom(0.9)
+        else:
+          worldView.zoom(1.1)
+    let dt = frameRate.restart.asMilliSeconds().float / 1000.0
+    case getActiveState()
+    of Field:
+      mainUpdate(dt)
+      mainRender()
+    of Lobby:
+      lobbyUpdate(dt)
+      lobbyDraw(window)
+    else:
+      initLevel()
+      echo("Done? lol")
+      doneWithSaidTransition()
+      readyMainState()
diff --git a/tests/manyloc/keineschweine/keineschweine.nimrod.cfg b/tests/manyloc/keineschweine/keineschweine.nimrod.cfg
new file mode 100644
index 000000000..048285ad9
--- /dev/null
+++ b/tests/manyloc/keineschweine/keineschweine.nimrod.cfg
@@ -0,0 +1,8 @@
+path = "lib"
+path = "dependencies/sfml"
+path = "dependencies/chipmunk"
+path = "dependencies/nake"
+path = "dependencies/enet"
+path = "dependencies/genpacket"
+path = "enet_server"
+debugger = off
diff --git a/tests/manyloc/keineschweine/lib/animations.nim b/tests/manyloc/keineschweine/lib/animations.nim
new file mode 100644
index 000000000..a021005f0
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/animations.nim
@@ -0,0 +1,75 @@
+import
+  math,
+  sfml, chipmunk,
+  sg_assets, sfml_stuff, math_helpers
+type
+  PAnimation* = ref TAnimation
+  TAnimation* = object
+    sprite*: PSprite
+    record*: PAnimationRecord
+    delay*: float
+    index*: int
+    direction*: int
+    spriteRect*: TIntRect
+    style*: TAnimationStyle
+  TAnimationStyle* = enum
+    AnimLoop = 0'i8, AnimBounce, AnimOnce
+
+proc setPos*(obj: PAnimation; pos: TVector) {.inline.}
+proc setPos*(obj: PAnimation; pos: TVector2f) {.inline.}
+proc setAngle*(obj: PAnimation; radians: float) {.inline.}
+
+proc free*(obj: PAnimation) =
+  obj.sprite.destroy()
+  obj.record = nil
+
+proc newAnimation*(src: PAnimationRecord; style: TAnimationStyle): PAnimation =
+  new(result, free)
+  result.sprite = src.spriteSheet.sprite.copy()
+  result.record = src
+  result.delay = src.delay
+  result.index = 0
+  result.direction = 1
+  result.spriteRect = result.sprite.getTextureRect()
+  result.style = style
+proc newAnimation*(src: PAnimationRecord; style: TAnimationStyle;
+                    pos: TVector2f; angle: float): PAnimation =
+  result = newAnimation(src, style)
+  result.setPos pos
+  setAngle(result, angle)
+
+proc next*(obj: PAnimation; dt: float): bool {.discardable.} =
+  ## step the animation. Returns false if the object is out of frames
+  result = true
+  obj.delay -= dt
+  if obj.delay <= 0.0:
+    obj.delay += obj.record.delay
+    obj.index += obj.direction
+    #if obj.index > (obj.record.spriteSheet.cols - 1) or obj.index < 0:
+    if not(obj.index in 0..(obj.record.spriteSheet.cols - 1)):
+      case obj.style
+      of AnimOnce:
+        return false
+      of AnimBounce:
+        obj.direction *= -1
+        obj.index += obj.direction * 2
+      of AnimLoop:
+        obj.index = 0
+    obj.spriteRect.left = obj.index.cint * obj.record.spriteSheet.frameW.cint
+    obj.sprite.setTextureRect obj.spriteRect
+
+proc setPos*(obj: PAnimation; pos: TVector) =
+  setPosition(obj.sprite, pos.floor())
+proc setPos*(obj: PAnimation; pos: TVector2f) =
+  setPosition(obj.sprite, pos)
+proc setAngle*(obj: PAnimation; radians: float)  =
+  let rads = (radians + obj.record.angle).wmod(TAU)
+  if obj.record.spriteSheet.rows > 1:
+    ## (rotation percent * rows).floor * frameheight
+    obj.spriteRect.top = (rads / TAU * obj.record.spriteSheet.rows.float).floor.cint * obj.record.spriteSheet.frameh.cint
+    obj.sprite.setTextureRect obj.spriteRect
+  else:
+    setRotation(obj.sprite, degrees(rads)) #stupid sfml, who uses degrees these days? -__-
+
+proc draw*(window: PRenderWindow; obj: PAnimation) {.inline.} =
+  window.draw(obj.sprite)
diff --git a/tests/manyloc/keineschweine/lib/client_helpers.nim b/tests/manyloc/keineschweine/lib/client_helpers.nim
new file mode 100644
index 000000000..84e42b62e
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/client_helpers.nim
@@ -0,0 +1,142 @@
+import  
+  tables, sg_packets, enet, estreams, sg_gui, sfml,
+  zlib_helpers, md5, sg_assets, os
+type
+  PServer* = ptr TServer
+  TServer* = object
+    connected*: bool
+    addy: enet.TAddress
+    host*: PHost
+    peer*: PPeer
+    handlers*: TTable[char, TScPktHandler]
+  TScPktHandler* = proc(serv: PServer; buffer: PBuffer)
+  TFileTransfer = object
+    fileName: string
+    assetType: TAssetType
+    fullLen: int
+    pos: int32
+    data: string
+    readyToSave: bool
+var 
+  currentFileTransfer: TFileTransfer
+  downloadProgress* = newButton(nil, "", vec2f(0,0), nil)
+currentFileTransfer.data = ""
+
+proc addHandler*(serv: PServer; packetType: char; handler: TScPktHandler) =
+  serv.handlers[packetType] = handler
+
+proc newServer*(): PServer =
+  result = cast[PServer](alloc0(sizeof(TServer)))
+  result.connected = false
+  result.host = createHost(nil, 1, 2, 0, 0)
+  result.handlers = initTable[char, TScPktHandler](32)
+
+proc connect*(serv: PServer; host: string; port: int16; error: var string): bool =
+  if setHost(serv.addy, host) != 0:
+    error = "Could not resolve host "
+    error.add host
+    return false
+  serv.addy.port = port.cushort
+  serv.peer = serv.host.connect(serv.addy, 2, 0)
+  if serv.peer.isNil:
+    error = "Could not connect to host "
+    error.add host
+    return false
+  return true
+
+proc send*[T](serv: PServer; packetType: char; pkt: var T) =
+  if serv.connected:
+    var b = newBuffer(100)
+    b.write packetType
+    b.pack pkt
+    serv.peer.send(0.cuchar, b, FlagUnsequenced)
+
+proc sendPubChat*(server: PServer; msg: string) =
+  var chat = newCsChat("", msg)
+  server.send HChat, chat
+
+proc handlePackets*(server: PServer; buf: PBuffer) =
+  while not buf.atEnd():
+    let typ = readChar(buf)
+    if server.handlers.hasKey(typ):
+      server.handlers[typ](server, buf)
+    else:
+      break
+
+proc updateFileProgress*() =
+  let progress = currentFileTransfer.pos / currentFileTransfer.fullLen
+  downloadProgress.bg.setSize(vec2f(progress * 100, 20))
+  downloadProgress.setString($currentFileTransfer.pos &'/'& $currentFileTransfer.fullLen)
+
+## HFileTransfer
+proc handleFilePartRecv*(serv: PServer; buffer: PBuffer) {.procvar.} =
+  var
+    f = readScFileTransfer(buffer)
+  updateFileProgress()
+  if not(f.pos == currentFileTransfer.pos): 
+    echo "returning early from filepartrecv"
+    return ##issues, probably
+  if currentFileTransfer.data.len == 0:
+    echo "setting current file size"
+    currentFileTransfer.data.setLen f.fileSize
+  let len = f.data.len
+  copymem(
+    addr currentFileTransfer.data[f.pos],
+    addr f.data[0],
+    len)
+  currentFileTransfer.pos = f.pos + len.int32
+  if currentFileTransfer.pos == f.fileSize: #file should be done, rizzight
+    currentFileTransfer.data = uncompress(
+      currentFileTransfer.data, currentFileTransfer.fullLen)
+    currentFileTransfer.readyToSave = true
+    var resp: CsFileChallenge
+    resp.checksum = toMD5(currentFileTransfer.data)
+    serv.send HFileChallenge, resp
+    echo "responded with challenge (ready to save)"
+  else:
+    var resp = newCsFilepartAck(currentFileTransfer.pos)
+    serv.send HFileTransfer, resp
+    echo "responded for next part"
+
+proc saveCurrentFile() =
+  if not currentFileTransfer.readyToSave: return
+  let 
+    path = expandPath(currentFileTransfer.assetType, currentFileTransfer.fileName)
+    parent = parentDir(path)
+  if not existsDir(parent):
+    createDir(parent)
+    echo("Created dir")
+  writeFile path, currentFIleTransfer.data
+  echo "Write file"
+
+## HChallengeResult
+proc handleFileChallengeResult*(serv: PServer; buffer: PBuffer) {.procvar.} =
+  var res = readScChallengeResult(buffer).status
+  echo "got challnege result: ", res
+  if res and currentFileTransfer.readyToSave:
+    echo "saving"
+    saveCurrentFile()
+  else:
+    currentFileTransfer.readyToSave = false
+    currentFileTransfer.pos = 0
+    echo "REsetting current file"
+
+## HFileCHallenge
+proc handleFileChallenge*(serv: PServer; buffer: PBuffer) {.procvar.} =
+  var 
+    challenge = readScFileChallenge(buffer)
+    path = expandPath(challenge)
+    resp: CsFileChallenge
+  if not existsFile(path):
+    resp.needFile = true
+    echo "Got file challenge, need file."
+  else:
+    resp.checksum = toMD5(readFile(path))
+    echo "got file challenge, sending sum"
+  currentFileTransfer.fileName = challenge.file
+  currentFileTransfer.assetType = challenge.assetType
+  currentFileTransfer.fullLen = challenge.fullLen.int
+  currentFileTransfer.pos = 0
+  currentFileTransfer.data.setLen 0
+  currentFileTransfer.readyToSave = false
+  serv.send HFileChallenge, resp
diff --git a/tests/manyloc/keineschweine/lib/estreams.nim b/tests/manyloc/keineschweine/lib/estreams.nim
new file mode 100644
index 000000000..bd0a2c31a
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/estreams.nim
@@ -0,0 +1,126 @@
+import endians
+
+proc swapEndian16*(outp, inp: pointer) = 
+  ## copies `inp` to `outp` swapping bytes. Both buffers are supposed to
+  ## contain at least 2 bytes.
+  var i = cast[cstring](inp)
+  var o = cast[cstring](outp)
+  o[0] = i[1]
+  o[1] = i[0]
+when cpuEndian == bigEndian:
+  proc bigEndian16(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 2)
+else:
+  proc bigEndian16*(outp, inp: pointer) {.inline.} = swapEndian16(outp, inp)
+
+import enet
+
+type
+  PBuffer* = ref object
+    data*: string
+    pos: int
+
+proc free(b: PBuffer) =
+  GCunref b.data
+proc newBuffer*(len: int): PBuffer =
+  new result, free
+  result.data = newString(len)
+proc newBuffer*(pkt: PPacket): PBuffer =
+  new result, free
+  result.data = newString(pkt.dataLength)
+  copyMem(addr result.data[0], pkt.data, pkt.dataLength)
+proc toPacket*(buffer: PBuffer; flags: TPacketFlag): PPacket =
+  buffer.data.setLen buffer.pos
+  result = createPacket(cstring(buffer.data), buffer.pos, flags)
+
+proc isDirty*(buffer: PBuffer): bool {.inline.} =
+  result = (buffer.pos != 0)
+proc atEnd*(buffer: PBuffer): bool {.inline.} =
+  result = (buffer.pos == buffer.data.len)
+proc reset*(buffer: PBuffer) {.inline.} =
+  buffer.pos = 0
+
+proc flush*(buf: PBuffer) =
+  buf.pos = 0
+  buf.data.setLen(0)
+proc send*(peer: PPeer; channel: cuchar; buf: PBuffer; flags: TPacketFlag): cint {.discardable.} =
+  result = send(peer, channel, buf.toPacket(flags))
+
+proc read*[T: int16|uint16](buffer: PBuffer; outp: var T) =
+  bigEndian16(addr outp, addr buffer.data[buffer.pos])
+  inc buffer.pos, 2
+proc read*[T: float32|int32|uint32](buffer: PBuffer; outp: var T) =
+  bigEndian32(addr outp, addr buffer.data[buffer.pos])
+  inc buffer.pos, 4
+proc read*[T: float64|int64|uint64](buffer: PBuffer; outp: var T) =
+  bigEndian64(addr outp, addr buffer.data[buffer.pos])
+  inc buffer.pos, 8
+proc read*[T: int8|uint8|byte|bool|char](buffer: PBuffer; outp: var T) =
+  copyMem(addr outp, addr buffer.data[buffer.pos], 1)
+  inc buffer.pos, 1
+
+proc writeBE*[T: int16|uint16](buffer: PBuffer; val: var T) =
+  setLen buffer.data, buffer.pos + 2
+  bigEndian16(addr buffer.data[buffer.pos], addr val)
+  inc buffer.pos, 2
+proc writeBE*[T: int32|uint32|float32](buffer: PBuffer; val: var T) =
+  setLen buffer.data, buffer.pos + 4
+  bigEndian32(addr buffer.data[buffer.pos], addr val)
+  inc buffer.pos, 4
+proc writeBE*[T: int64|uint64|float64](buffer: PBuffer; val: var T) =
+  setLen buffer.data, buffer.pos + 8
+  bigEndian64(addr buffer.data[buffer.pos], addr val)
+  inc buffer.pos, 8
+proc writeBE*[T: char|int8|uint8|byte|bool](buffer: PBuffer; val: var T) =
+  setLen buffer.data, buffer.pos + 1
+  copyMem(addr buffer.data[buffer.pos], addr val, 1)
+  inc buffer.pos, 1
+
+
+proc write*(buffer: PBuffer; val: var string) =
+  var length = len(val).uint16
+  writeBE buffer, length
+  setLen buffer.data, buffer.pos + length.int
+  copyMem(addr buffer.data[buffer.pos], addr val[0], length.int)
+  inc buffer.pos, length.int
+proc write*[T: TNumber|bool|char|byte](buffer: PBuffer; val: T) =
+  var v: T
+  shallowCopy v, val
+  writeBE buffer, v
+
+proc readInt8*(buffer: PBuffer): int8 =
+  read buffer, result
+proc readInt16*(buffer: PBuffer): int16 =
+  read buffer, result
+proc readInt32*(buffer: PBuffer): int32 =
+  read buffer, result
+proc readInt64*(buffer: PBuffer): int64 =
+  read buffer, result
+proc readFloat32*(buffer: PBuffer): float32 =
+  read buffer, result
+proc readFloat64*(buffer: PBuffer): float64 =
+  read buffer, result
+proc readStr*(buffer: PBuffer): string =
+  let len = readInt16(buffer).int
+  result = ""
+  if len > 0:
+    result.setLen len
+    copyMem(addr result[0], addr buffer.data[buffer.pos], len)
+    inc buffer.pos, len
+proc readChar*(buffer: PBuffer): char {.inline.} = return readInt8(buffer).char
+proc readBool*(buffer: PBuffer): bool {.inline.} = return readInt8(buffer).bool
+
+
+when isMainModule:
+  var b = newBuffer(100)
+  var str = "hello there"
+  b.write str
+  echo(repr(b))
+  b.pos = 0
+  echo(repr(b.readStr()))
+  
+  b.flush()
+  echo "flushed"
+  b.writeC([1,2,3])
+  echo(repr(b))
+  
+  
diff --git a/tests/manyloc/keineschweine/lib/game_objects.nim b/tests/manyloc/keineschweine/lib/game_objects.nim
new file mode 100644
index 000000000..37019ebcb
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/game_objects.nim
@@ -0,0 +1,34 @@
+import chipmunk, sfml, animations, sg_assets
+type
+  PGameObject* = ref TGameObject
+  TGameObject = object
+    body*: chipmunk.PBody
+    shape*: chipmunk.PShape
+    record*: PObjectRecord
+    anim*: PAnimation
+
+
+proc `$`*(obj: PGameObject): string =
+  result = "<Object "
+  result.add obj.record.name
+  result.add ' '
+  result.add($obj.body.getpos())
+  result.add '>'
+proc free(obj: PGameObject) =
+  obj.record = nil
+  free(obj.anim)
+  obj.anim = nil
+proc newObject*(record: PObjectRecord): PGameObject =
+  if record.isNil: return nil
+  new(result, free)
+  result.record = record
+  result.anim = newAnimation(record.anim, AnimLoop)
+  when false:
+    result.sprite = record.anim.spriteSheet.sprite.copy()
+  result.body = newBody(result.record.physics.mass, 10.0)
+  result.shape = chipmunk.newCircleShape(result.body, result.record.physics.radius, vectorZero)
+  result.body.setPos(vector(100, 100))
+proc newObject*(name: string): PGameObject =
+  result = newObject(fetchObj(name))
+proc draw*(window: PRenderWindow, obj: PGameObject) {.inline.} =
+  window.draw(obj.anim.sprite)
diff --git a/tests/manyloc/keineschweine/lib/idgen.nim b/tests/manyloc/keineschweine/lib/idgen.nim
new file mode 100644
index 000000000..8124ba9bd
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/idgen.nim
@@ -0,0 +1,23 @@
+type
+  PIDGen*[T: Ordinal] = ref TIDGen[T]
+  TIDGen*[T: Ordinal] = object
+    max: T
+    freeIDs: seq[T]
+  EOutOfIDs* = object of EInvalidKey
+
+#proc free[T](idg: PIDgen[T]) = 
+#  result.freeIDs = nil
+proc newIDGen*[T: Ordinal](): PIDGen[T] =
+  new(result)#, free)
+  result.max = 0.T
+  result.freeIDs = @[]
+proc next*[T](idg: PIDGen[T]): T =
+  if idg.freeIDs.len > 0:
+    result = idg.freeIDs.pop
+  elif idg.max < high(T)-T(1):
+    inc idg.max
+    result = idg.max
+  else:
+    raise newException(EOutOfIDs, "ID generator hit max value")
+proc del*[T](idg: PIDGen[T]; id: T) =
+  idg.freeIDs.add id
diff --git a/tests/manyloc/keineschweine/lib/input_helpers.nim b/tests/manyloc/keineschweine/lib/input_helpers.nim
new file mode 100644
index 000000000..120576dfb
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/input_helpers.nim
@@ -0,0 +1,138 @@
+import
+  sfml, tables, hashes
+type
+  TKeyEventKind* = enum down, up
+  TInputFinishedProc* = proc() 
+  TKeyCallback = proc()
+  PKeyClient* = ref object
+    onKeyDown: TTable[int32, TKeyCallback]
+    onKeyUp: TTable[int32, TKeyCallback]
+    name: string
+  PTextInput* = ref object
+    text*: string
+    cursor: int
+    onEnter: TInputFinishedProc
+var
+  keyState:    array[-MouseButtonCount.int32 .. KeyCount.int32, bool]
+  mousePos: TVector2f
+  activeClient: PKeyClient = nil
+  activeInput: PTextInput  = nil
+
+proc setActive*(client: PKeyClient) = 
+  activeClient = client
+  echo("** set active client ", client.name)
+proc newKeyClient*(name: string = "unnamed", setactive = false): PKeyClient =
+  new(result)
+  result.onKeyDown = initTable[int32, TKeyCallback](16)
+  result.onKeyUp   = initTable[int32, TKeyCallback](16)
+  result.name = name
+  if setActive:
+    setActive(result)
+
+proc keyPressed*(key: TKeyCode): bool {.inline.} =
+  return keyState[key.int32]
+proc buttonPressed*(btn: TMouseButton): bool {.inline.} =
+  return keyState[-btn.int32]
+
+proc clearKey*(key: TKeyCode) {.inline.} =
+  keyState[key.int32]  = false
+proc clearButton*(btn: TMouseButton) {.inline.} =
+  keyState[-btn.int32] = false
+
+proc addKeyEvent*(key: TKeyCode, ev: TKeyEventKind) {.inline.} =
+  if activeClient.isNil: return
+  let k = key.int32
+  case ev
+  of down: 
+    keyState[k] = true
+    if activeClient.onKeyDown.hasKey(k):
+      activeClient.onKeyDown[k]()
+  else:    
+    keyState[k] = false
+    if activeClient.onKeyUp.hasKey(k):
+      activeClient.onKeyUp[k]()
+proc addButtonEvent*(btn: TMouseButton, ev: TKeyEventKind) {.inline.} =
+  if activeClient.isNil: return 
+  let b = -btn.int32
+  case ev
+  of down: 
+    keyState[b] = true 
+    if activeClient.onKeyDown.hasKey(b):
+      activeClient.onKeyDown[b]()
+  else: 
+    keyState[b] = false
+    if activeClient.onKeyUp.hasKey(b):
+      activeClient.onKeyUp[b]()
+proc registerHandler*(client: PKeyClient; key: TKeyCode;
+                       ev: TKeyEventKind; fn: TKeyCallback) = 
+  case ev
+  of down: client.onKeyDown[key.int32] = fn
+  of up:   client.onKeyUp[key.int32]   = fn
+proc registerHandler*(client: PKeyClient; btn: TMouseButton;
+                       ev: TKeyEventKind; fn: TKeyCallback) =
+  case ev
+  of down: client.onKeyDown[-btn.int32] = fn
+  of up:   client.onKeyUp[-btn.int32]   = fn
+
+proc newTextInput*(text = "", pos = 0, onEnter: TInputFinishedProc = nil): PTextInput =
+  new(result)
+  result.text = text
+  result.cursor = pos
+  result.onEnter = onEnter
+proc setActive*(i: PTextInput) =
+  activeInput = i
+proc stopCapturingText*() =
+  activeInput = nil
+proc clear*(i: PTextInput) =
+  i.text.setLen 0
+  i.cursor = 0
+proc recordText*(i: PTextInput; c: cint) =
+  if c > 127 or i.isNil: return
+  if c in 32..126: ##printable
+    if i.cursor == i.text.len: i.text.add(c.int.chr)
+    else: 
+      let rem = i.text.substr(i.cursor)
+      i.text.setLen(i.cursor)
+      i.text.add(chr(c.int))
+      i.text.add(rem)
+    inc(i.cursor)
+  elif c == 8: ## \b  backspace
+    if i.text.len > 0 and i.cursor > 0:
+      dec(i.cursor)
+      let rem = i.text.substr(i.cursor + 1)
+      i.text.setLen(i.cursor)
+      i.text.add(rem)
+  elif c == 10 or c == 13:## \n, \r  enter
+    if not i.onEnter.isNil: i.onEnter()
+proc recordText*(i: PTextInput; e: TTextEvent) {.inline.} = 
+  recordText(i, e.unicode)
+
+proc setMousePos*(x, y: cint) {.inline.} =
+  mousePos.x = x.float
+  mousePos.y = y.float
+proc getMousePos*(): TVector2f {.inline.} = result = mousePos
+
+var event: TEvent
+# Handle and filter input-related events
+iterator filterEvents*(window: PRenderWindow): PEvent =
+  while window.pollEvent(addr event):
+    case event.kind
+    of EvtKeyPressed: addKeyEvent(event.key.code, down)
+    of EvtKeyReleased: addKeyEvent(event.key.code, up)
+    of EvtMouseButtonPressed: addButtonEvent(event.mouseButton.button, down)
+    of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up)
+    of EvtTextEntered: recordText(activeInput, event.text)
+    of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y)
+    else: yield(addr event)
+# Handle and return input-related events
+iterator pollEvents*(window: PRenderWindow): PEvent =
+  while window.pollEvent(addr event):
+    case event.kind
+    of EvtKeyPressed: addKeyEvent(event.key.code, down)
+    of EvtKeyReleased: addKeyEvent(event.key.code, up)
+    of EvtMouseButtonPressed: addButtonEvent(event.mouseButton.button, down)
+    of EvtMouseButtonReleased: addButtonEvent(event.mouseButton.button, up)
+    of EvtTextEntered: recordText(activeInput, event.text)
+    of EvtMouseMoved: setMousePos(event.mouseMove.x, event.mouseMove.y)
+    else: nil
+    yield(addr event)
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/lib/map_filter.nim b/tests/manyloc/keineschweine/lib/map_filter.nim
new file mode 100644
index 000000000..54173fa61
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/map_filter.nim
@@ -0,0 +1,41 @@
+template filterIt2*(seq, pred: expr, body: stmt): stmt {.immediate, dirty.} =
+  ## sequtils defines a filterIt() that returns a new seq, but this one is called
+  ## with a statement body to iterate directly over it
+  for it in items(seq):
+    if pred: body
+
+proc map*[A, B](x: seq[A], func: proc(y: A): B {.closure.}): seq[B] =
+  result = @[]
+  for item in x.items:
+    result.add func(item)
+
+proc mapInPlace*[A](x: var seq[A], func: proc(y: A): A {.closure.}) =
+  for i in 0..x.len-1:
+    x[i] = func(x[i])
+
+template unless*(condition: expr; body: stmt): stmt {.dirty.} =
+  if not(condition):
+    body
+
+when isMainModule:
+  proc dumpSeq[T](x: seq[T]) =
+    for index, item in x.pairs: 
+      echo index, " ", item
+    echo "-------"
+
+  var t= @[1,2,3,4,5]
+  var res = t.map(proc(z: int): int = result = z * 10)
+  dumpSeq res
+
+  from strutils import toHex, repeatStr
+  var foocakes = t.map(proc(z: int): string = 
+    result = toHex((z * 23).biggestInt, 4))
+  dumpSeq foocakes
+
+  t.mapInPlace(proc(z: int): int = result = z * 30)
+  dumpSeq t
+  
+  var someSeq = @[9,8,7,6,5,4,3,2,1] ## numbers < 6 or even
+  filterIt2 someSeq, it < 6 or (it and 1) == 0:
+    echo(it)
+  echo "-----------"
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/lib/math_helpers.nim b/tests/manyloc/keineschweine/lib/math_helpers.nim
new file mode 100644
index 000000000..8af56d1ed
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/math_helpers.nim
@@ -0,0 +1,10 @@
+import strutils, math
+
+proc degrees*(rad: float): float =
+  return rad * 180.0 / PI
+proc radians*(deg: float): float =
+  return deg * PI / 180.0
+
+## V not math, sue me
+proc ff*(f: float, precision = 2): string {.inline.} = 
+  return formatFloat(f, ffDecimal, precision)
diff --git a/tests/manyloc/keineschweine/lib/sfml_stuff.nim b/tests/manyloc/keineschweine/lib/sfml_stuff.nim
new file mode 100644
index 000000000..a5ac91195
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sfml_stuff.nim
@@ -0,0 +1,37 @@
+import 
+  math, strutils,
+  sfml, input_helpers
+when not defined(NoChipmunk):
+  import chipmunk
+  proc floor*(a: TVector): TVector2f {.inline.} =
+    result.x = a.x.floor
+    result.y = a.y.floor
+  proc sfml2cp*(a: TVector2f): TVector {.inline.} =
+    result.x = a.x
+    result.y = a.y
+  proc cp2sfml*(a: TVector): TVector2f {.inline.} =
+    result.x = a.x
+    result.y = a.y
+
+proc vec2f*(a: TVector2i): TVector2f =
+  result.x = a.x.cfloat
+  result.y = a.y.cfloat
+proc vec2i*(a: TVector2f): TVector2i =
+  result.x = a.x.cint
+  result.y = a.y.cint
+proc vec3f*(x, y, z: float): TVector3f =
+  result.x = x.cfloat
+  result.y = y.cfloat
+  result.z = z.cfloat
+
+proc `$`*(a: var TIntRect): string =
+  result = "[TIntRect $1,$2 $3x$4]".format($a.left, $a.top, $a.width, $a.height)
+proc `$`*(a: TKeyEvent): string =
+  return "KeyEvent: code=$1 alt=$2 control=$3 shift=$4 system=$5".format(
+    $a.code, $a.alt, $a.control, $a.shift, $a.system)
+
+proc `wmod`*(x, y: float): float = return x - y * (x/y).floor
+proc move*(a: var TIntRect, left, top: cint): bool =
+  if a.left != left or a.top != top: result = true
+  a.left = left
+  a.top  = top
diff --git a/tests/manyloc/keineschweine/lib/sg_assets.nim b/tests/manyloc/keineschweine/lib/sg_assets.nim
new file mode 100644
index 000000000..766bf5d82
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sg_assets.nim
@@ -0,0 +1,609 @@
+import
+  re, json, strutils, tables, math, os, math_helpers, 
+  sg_packets, md5, zlib_helpers
+
+when defined(NoSFML):
+  import server_utils
+  type TVector2i = object
+    x*, y*: int32
+  proc vec2i(x, y: int32): TVector2i =
+    result.x = x
+    result.y = y
+else:
+  import sfml, sfml_audio, sfml_stuff
+when not defined(NoChipmunk):
+  import chipmunk
+
+type
+  TChecksumFile* = object
+    unpackedSize*: int
+    sum*: MD5Digest
+    compressed*: string
+  PZoneSettings* = ref TZoneSettings
+  TZoneSettings* = object
+    vehicles: seq[PVehicleRecord]
+    items: seq[PItemRecord]
+    objects: seq[PObjectRecord]
+    bullets: seq[PBulletRecord]
+    levelSettings: PLevelSettings
+  PLevelSettings* = ref TLevelSettings
+  TLevelSettings* = object
+    size*: TVector2i
+    starfield*: seq[PSpriteSheet]
+  PVehicleRecord* = ref TVehicleRecord
+  TVehicleRecord* = object
+    id*: int16
+    name*: string
+    playable*: bool
+    anim*: PAnimationRecord
+    physics*: TPhysicsRecord
+    handling*: THandlingRecord
+  TItemKind* = enum
+    Projectile, Utility, Ammo
+  PObjectRecord* = ref TObjectRecord
+  TObjectRecord* = object
+    id*: int16
+    name*: string
+    anim*: PAnimationRecord
+    physics*: TPhysicsRecord
+  PItemRecord* = ref TItemRecord
+  TItemRecord* = object
+    id*: int16
+    name*: string
+    anim*: PAnimationRecord
+    physics*: TPhysicsRecord ##apply when the item is dropped in the arena
+    cooldown*: float
+    energyCost*: float
+    useSound*: PSoundRecord
+    case kind*: TItemKind
+    of Projectile: 
+      bullet*: PBulletRecord
+    else: 
+      nil
+  PBulletRecord* = ref TBulletRecord
+  TBulletRecord* = object
+    id*: int16
+    name*: string
+    anim*: PAnimationRecord
+    physics*: TPhysicsRecord
+    lifetime*, inheritVelocity*, baseVelocity*: float
+    explosion*: TExplosionRecord
+    trail*: TTrailRecord
+  TTrailRecord* = object
+    anim*: PAnimationRecord
+    timer*: float ##how often it should be created
+  TPhysicsRecord* = object
+    mass*: float
+    radius*: float
+    moment*: float
+  THandlingRecord = object
+    thrust*, top_speed*: float
+    reverse*, strafe*, rotation*: float
+  TSoulRecord = object
+    energy*: int
+    health*: int
+  TExplosionRecord* = object
+    anim*: PAnimationRecord
+    sound*: PSoundRecord 
+  PAnimationRecord* = ref TAnimationRecord
+  TAnimationRecord* = object
+    spriteSheet*: PSpriteSheet
+    angle*: float
+    delay*: float  ##animation delay
+  PSoundRecord* = ref TSoundRecord
+  TSoundRecord* = object
+    file*: string
+    when defined(NoSFML):
+      contents*: TChecksumFile
+    else:
+      soundBuf*: PSoundBuffer 
+  PSpriteSheet* = ref TSpriteSheet
+  TSpriteSheet* = object 
+    file*: string
+    framew*,frameh*: int
+    rows*, cols*: int
+    when defined(NoSFML):
+      contents*: TChecksumFile
+    when not defined(NoSFML):
+      sprite*: PSprite
+      tex*: PTexture
+  TGameState* = enum
+    Lobby, Transitioning, Field
+const
+  TAU* = PI * 2.0
+  MomentMult* = 0.62 ## global moment of inertia multiplier
+var 
+  cfg: PZoneSettings
+  SpriteSheets* = initTable[string, PSpriteSheet](64)
+  SoundCache  * = initTable[string, PSoundRecord](64)
+  nameToVehID*: TTable[string, int]
+  nameToItemID*: TTable[string, int]
+  nameToObjID*: TTable[string, int]
+  nameToBulletID*: TTable[string, int]
+  activeState = Lobby
+
+proc newSprite(filename: string; errors: var seq[string]): PSpriteSheet
+proc load*(ss: PSpriteSheet): bool {.discardable.}
+proc newSound(filename: string; errors: var seq[string]): PSoundRecord
+proc load*(s: PSoundRecord): bool {.discardable.}
+
+proc validateSettings*(settings: PJsonNode; errors: var seq[string]): bool
+proc loadSettings*(rawJson: string, errors: var seq[string]): bool
+proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool
+
+proc fetchVeh*(name: string): PVehicleRecord
+proc fetchItm*(itm: string): PItemRecord
+proc fetchObj*(name: string): PObjectRecord
+proc fetchBullet(name: string): PBulletRecord
+
+proc importLevel(data: PJsonNode; errors: var seq[string]): PLevelSettings
+proc importVeh(data: PJsonNode; errors: var seq[string]): PVehicleRecord
+proc importObject(data: PJsonNode; errors: var seq[string]): PObjectRecord
+proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord
+proc importPhys(data: PJsonNode): TPhysicsRecord
+proc importAnim(data: PJsonNode; errors: var seq[string]): PAnimationRecord
+proc importHandling(data: PJsonNode): THandlingRecord
+proc importBullet(data: PJsonNode; errors: var seq[string]): PBulletRecord
+proc importSoul(data: PJsonNode): TSoulRecord
+proc importExplosion(data: PJsonNode; errors: var seq[string]): TExplosionRecord
+proc importSound(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord
+
+## this is the only pipe between lobby and main.nim
+proc getActiveState*(): TGameState =
+  result = activeState
+proc transition*() = 
+  assert activeState == Lobby, "Transition() called from a state other than lobby!"
+  activeState = Transitioning
+proc doneWithSaidTransition*() =
+  assert activeState == Transitioning, "Finished() called from a state other than transitioning!"
+  activeState = Field
+
+
+proc checksumFile*(filename: string): TChecksumFile =
+  let fullText = readFile(filename)
+  result.unpackedSize = fullText.len
+  result.sum = toMD5(fullText)
+  result.compressed = compress(fullText)
+proc checksumStr*(str: string): TChecksumFile =
+  result.unpackedSize = str.len
+  result.sum = toMD5(str)
+  result.compressed = compress(str)
+
+
+##at this point none of these should ever be freed
+proc free*(obj: PZoneSettings) =
+  echo "Free'd zone settings"
+proc free*(obj: PSpriteSheet) =
+  echo "Free'd ", obj.file
+proc free*(obj: PSoundRecord) =
+  echo "Free'd ", obj.file
+
+proc loadAllAssets*() =
+  var 
+    loaded = 0
+    failed = 0
+  for name, ss in SpriteSheets.pairs():
+    if load(ss):
+      inc loaded
+    else:
+      inc failed
+  echo loaded," sprites loaded. ", failed, " sprites failed."
+  loaded = 0
+  failed = 0
+  for name, s in SoundCache.pairs():
+    if load(s):
+      inc loaded
+    else:
+      inc failed
+  echo loaded, " sounds loaded. ", failed, " sounds failed."
+proc getLevelSettings*(): PLevelSettings =
+  result = cfg.levelSettings
+
+iterator playableVehicles*(): PVehicleRecord =
+  for v in cfg.vehicles.items():
+    if v.playable:
+      yield v
+
+template allAssets*(body: stmt) {.dirty.}=
+  block: 
+    var assetType = FGraphics
+    for file, asset in pairs(SpriteSheets):
+      body
+    assetType = FSound
+    for file, asset in pairs(SoundCache):
+      body
+
+template cacheImpl(procName, cacheName, resultType: expr; body: stmt) {.dirty, immediate.} =
+  proc procName*(filename: string; errors: var seq[string]): resulttype =
+    if hasKey(cacheName, filename):
+      return cacheName[filename]
+    new(result, free)
+    body
+    cacheName[filename] = result
+
+template checkFile(path: expr): stmt {.dirty, immediate.} =
+  if not existsFile(path):
+    errors.add("File missing: "& path)
+
+cacheImpl newSprite, SpriteSheets, PSpriteSheet:
+  result.file = filename
+  if not(filename =~ re"\S+_(\d+)x(\d+)\.\S\S\S"):
+    errors.add "Bad file: "&filename&" must be in format name_WxH.png"
+    return
+  result.framew = strutils.parseInt(matches[0])
+  result.frameh = strutils.parseInt(matches[1])
+  checkFile("data/gfx"/result.file)
+
+cacheImpl newSound, SoundCache, PSoundRecord:
+  result.file = filename
+  checkFile("data/sfx"/result.file)
+
+proc expandPath*(assetType: TAssetType; fileName: string): string =
+  result = "data/"
+  case assetType
+  of FGraphics: result.add "gfx/"
+  of FSound:    result.add "sfx/"
+  else: nil
+  result.add fileName
+proc expandPath*(fc: ScFileChallenge): string {.inline.} =
+  result = expandPath(fc.assetType, fc.file)
+
+when defined(NoSFML):
+  proc load*(ss: PSpriteSheet): bool =
+    if not ss.contents.unpackedSize == 0: return
+    ss.contents = checksumFile(expandPath(FGraphics, ss.file))
+    result = true
+  proc load*(s: PSoundRecord): bool =
+    if not s.contents.unpackedSize == 0: return
+    s.contents = checksumFile(expandPath(FSound, s.file))
+    result = true
+else:
+  proc load*(ss: PSpriteSheet): bool =
+    if not ss.sprite.isNil: 
+      return
+    var image = sfml.newImage("data/gfx/"/ss.file)
+    if image == nil:
+      echo "Image could not be loaded"
+      return
+    let size = image.getSize()
+    ss.rows = int(size.y / ss.frameh) #y is h
+    ss.cols = int(size.x / ss.framew) #x is w
+    ss.tex = newTexture(image)
+    image.destroy()
+    ss.sprite = newSprite()
+    ss.sprite.setTexture(ss.tex, true)
+    ss.sprite.setTextureRect(intrect(0, 0, ss.framew.cint, ss.frameh.cint))
+    ss.sprite.setOrigin(vec2f(ss.framew / 2, ss.frameh / 2))
+    result = true
+  proc load*(s: PSoundRecord): bool =
+    s.soundBuf = newSoundBuffer("data/sfx"/s.file)
+    if not s.soundBuf.isNil:
+      result = true
+
+template addError(e: expr): stmt {.immediate.} =
+  errors.add(e)
+  result = false
+proc validateSettings*(settings: PJsonNode, errors: var seq[string]): bool =
+  result = true
+  if settings.kind != JObject:
+    addError("Settings root must be an object")
+    return
+  if not settings.existsKey("vehicles"):
+    addError("Vehicles section missing")
+  if not settings.existsKey("objects"):
+    errors.add("Objects section is missing")
+    result = false
+  if not settings.existsKey("level"):
+    errors.add("Level settings section is missing")
+    result = false
+  else:
+    let lvl = settings["level"]
+    if lvl.kind != JObject or not lvl.existsKey("size"):
+      errors.add("Invalid level settings")
+      result = false
+    elif not lvl.existsKey("size") or lvl["size"].kind != JArray or lvl["size"].len != 2:
+      errors.add("Invalid/missing level size")
+      result = false
+  if not settings.existsKey("items"):
+    errors.add("Items section missing")
+    result = false
+  else:
+    let items = settings["items"]
+    if items.kind != JArray or items.len == 0:
+      errors.add "Invalid or empty item list"
+    else:
+      var id = 0
+      for i in items.items:
+        if i.kind != JArray: errors.add("Item #$1 is not an array"% $id)
+        elif i.len != 3: errors.add("($1) Item record should have 3 fields"%($id))
+        elif i[0].kind != JString or i[1].kind != JString or i[2].kind != JObject:
+          errors.add("($1) Item should be in form [name, type, {item: data}]"% $id)
+          result = false
+        inc id
+
+proc loadSettingsFromFile*(filename: string, errors: var seq[string]): bool =
+  if not existsFile(filename):
+    errors.add("File does not exist: "&filename)
+  else:
+    result = loadSettings(readFile(filename), errors)
+
+proc loadSettings*(rawJson: string, errors: var seq[string]): bool =
+  var settings: PJsonNode
+  try:
+    settings = parseJson(rawJson)
+  except EJsonParsingError:
+    errors.add("JSON parsing error: "& getCurrentExceptionMsg())
+    return
+  except: 
+    errors.add("Unknown exception: "& getCurrentExceptionMsg())
+    return
+  if not validateSettings(settings, errors):
+    return
+  if cfg != nil: #TODO try this
+    echo("Overwriting zone settings")
+    free(cfg)
+    cfg = nil
+  new(cfg, free)
+  cfg.levelSettings = importLevel(settings, errors)
+  cfg.vehicles = @[]
+  cfg.items = @[]
+  cfg.objects = @[]
+  cfg.bullets = @[]
+  nameToVehID = initTable[string, int](32)
+  nameToItemID = initTable[string, int](32)
+  nameToObjID = initTable[string, int](32)
+  nameToBulletID = initTable[string, int](32)
+  var 
+    vID = 0'i16
+    bID = 0'i16
+  for vehicle in settings["vehicles"].items:
+    var veh = importVeh(vehicle, errors)
+    veh.id = vID
+    cfg.vehicles.add veh
+    nameToVehID[veh.name] = veh.id
+    inc vID
+  vID = 0
+  if settings.existsKey("bullets"):
+    for blt in settings["bullets"].items:
+      var bullet = importBullet(blt, errors)
+      bullet.id = bID
+      cfg.bullets.add bullet
+      nameToBulletID[bullet.name] = bullet.id
+      inc bID
+  for item in settings["items"].items:
+    var itm = importItem(item, errors)
+    itm.id = vID
+    cfg.items.add itm
+    nameToItemID[itm.name] = itm.id
+    inc vID
+    if itm.kind == Projectile:
+      if itm.bullet.isNil:
+        errors.add("Projectile #$1 has no bullet!"% $vID)
+      elif itm.bullet.id == -1:
+        ## this item has an anonymous bullet, fix the ID and name
+        itm.bullet.id = bID 
+        itm.bullet.name = itm.name
+        cfg.bullets.add itm.bullet
+        nameToBulletID[itm.bullet.name] = itm.bullet.id
+        inc bID
+  vID = 0
+  for obj in settings["objects"].items:
+    var o = importObject(obj, errors)
+    o.id = vID
+    cfg.objects.add o
+    nameToObjID[o.name] = o.id
+    inc vID
+  result = (errors.len == 0)
+
+proc `$`*(obj: PSpriteSheet): string =
+  return "<Sprite $1 ($2x$3) $4 rows $5 cols>" % [obj.file, $obj.framew, $obj.frameh, $obj.rows, $obj.cols]
+
+proc fetchVeh*(name: string): PVehicleRecord =
+  return cfg.vehicles[nameToVehID[name]]
+proc fetchItm*(itm: string): PItemRecord =
+  return cfg.items[nameToItemID[itm]]
+proc fetchObj*(name: string): PObjectRecord =
+  return cfg.objects[nameToObjID[name]]
+proc fetchBullet(name: string): PBulletRecord =
+  return cfg.bullets[nameToBulletID[name]]
+
+proc getField(node: PJsonNode, field: string, target: var float) =
+  if not node.existsKey(field):
+    return
+  if node[field].kind == JFloat:
+    target = node[field].fnum
+  elif node[field].kind == JInt:
+    target = node[field].num.float
+proc getField(node: PJsonNode, field: string, target: var int) =
+  if not node.existsKey(field):
+    return
+  if node[field].kind == JInt:
+    target = node[field].num.int
+  elif node[field].kind == JFloat:
+    target = node[field].fnum.int
+proc getField(node: PJsonNode; field: string; target: var bool) =
+  if not node.existsKey(field):
+    return
+  case node[field].kind
+  of JBool:
+    target = node[field].bval
+  of JInt:
+    target = (node[field].num != 0)
+  of JFloat:
+    target = (node[field].fnum != 0.0)
+  else: nil
+
+template checkKey(node: expr; key: string): stmt =
+  if not existsKey(node, key):
+    return
+
+proc importTrail(data: PJsonNode; errors: var seq[string]): TTrailRecord =
+  checkKey(data, "trail")
+  result.anim = importAnim(data["trail"], errors)
+  result.timer = 1000.0
+  getField(data["trail"], "timer", result.timer)
+  result.timer /= 1000.0
+proc importLevel(data: PJsonNode; errors: var seq[string]): PLevelSettings =
+  new(result)
+  result.size = vec2i(5000, 5000)
+  result.starfield = @[]
+  
+  checkKey(data, "level")
+  var level = data["level"]
+  if level.existsKey("size") and level["size"].kind == JArray and level["size"].len == 2:
+    result.size.x = level["size"][0].num.cint
+    result.size.y = level["size"][1].num.cint
+  if level.existsKey("starfield"):
+    for star in level["starfield"].items:
+      result.starfield.add(newSprite(star.str, errors))
+proc importPhys(data: PJsonNode): TPhysicsRecord =
+  result.radius = 20.0
+  result.mass = 10.0
+  
+  if data.existsKey("physics") and data["physics"].kind == JObject:
+    let phys = data["physics"]
+    phys.getField("radius", result.radius)
+    phys.getField("mass", result.mass)
+  when not defined(NoChipmunk):
+    result.moment = momentForCircle(result.mass, 0.0, result.radius, vectorZero) * MomentMult
+proc importHandling(data: PJsonNode): THandlingRecord =
+  result.thrust = 45.0
+  result.topSpeed = 100.0 #unused
+  result.reverse = 30.0
+  result.strafe = 30.0
+  result.rotation = 2200.0
+  
+  checkKey(data, "handling")
+  if data["handling"].kind != JObject:
+    return
+  
+  let hand = data["handling"]
+  hand.getField("thrust", result.thrust)
+  hand.getField("top_speed", result.topSpeed)
+  hand.getField("reverse", result.reverse)
+  hand.getField("strafe", result.strafe)
+  hand.getField("rotation", result.rotation)
+proc importAnim(data: PJsonNode, errors: var seq[string]): PAnimationRecord =
+  new(result)
+  result.angle = 0.0
+  result.delay = 1000.0
+  result.spriteSheet = nil
+  
+  if data.existsKey("anim"):
+    let anim = data["anim"]
+    if anim.kind == JObject:
+      if anim.existsKey("file"):
+        result.spriteSheet = newSprite(anim["file"].str, errors)
+      
+      anim.getField "angle", result.angle
+      anim.getField "delay", result.delay
+    elif data["anim"].kind == JString:
+      result.spriteSheet = newSprite(anim.str, errors)
+  
+  result.angle = radians(result.angle) ## comes in as degrees 
+  result.delay /= 1000 ## delay comes in as milliseconds
+proc importSoul(data: PJsonNode): TSoulRecord =
+  result.energy = 10000
+  result.health = 1
+  checkKey(data, "soul")
+  let soul = data["soul"]
+  soul.getField("energy", result.energy)
+  soul.getField("health", result.health)
+proc importExplosion(data: PJsonNode; errors: var seq[string]): TExplosionRecord =
+  checkKey(data, "explode")
+  let expl = data["explode"]
+  result.anim = importAnim(expl, errors)
+  result.sound = importSound(expl, errors, "sound")
+proc importSound*(data: PJsonNode; errors: var seq[string]; fieldName: string = nil): PSoundRecord =
+  if data.kind == JObject:
+    checkKey(data, fieldName)
+    result = newSound(data[fieldName].str, errors)
+  elif data.kind == JString:
+    result = newSound(data.str, errors)
+
+proc importVeh(data: PJsonNode; errors: var seq[string]): PVehicleRecord =
+  new(result)
+  result.playable = false
+  if data.kind != JArray or data.len != 2 or 
+    (data.kind == JArray and 
+      (data[0].kind != JString or data[1].kind != JObject)):
+    result.name = "(broken)"
+    errors.add "Vehicle record is malformed"
+    return
+  var vehData = data[1]
+  result.name = data[0].str
+  result.anim = importAnim(vehdata, errors)
+  result.physics = importPhys(vehdata)
+  result.handling = importHandling(vehdata)
+  vehdata.getField("playable", result.playable)
+  if result.anim.spriteSheet.isNil and result.playable:
+    result.playable = false
+proc importObject(data: PJsonNode; errors: var seq[string]): PObjectRecord =
+  new(result)
+  if data.kind != JArray or data.len != 2:
+    result.name = "(broken)"
+    return
+  result.name = data[0].str
+  result.anim = importAnim(data[1], errors)
+  result.physics = importPhys(data[1])
+proc importItem(data: PJsonNode; errors: var seq[string]): PItemRecord =
+  new(result)
+  if data.kind != JArray or data.len != 3:
+    result.name = "(broken)"
+    errors.add "Item record is malformed"
+    return
+  result.name = data[0].str
+  result.anim = importAnim(data[2], errors)
+  result.physics = importPhys(data[2])
+  
+  result.cooldown = 100.0 
+  data[2].getField("cooldown", result.cooldown)
+  result.cooldown /= 1000.0  ##cooldown is stored in ms 
+  
+  result.useSound = importSound(data[2], errors, "useSound")
+  
+  case data[1].str.toLower
+  of "projectile":
+    result.kind = Projectile
+    if data[2]["bullet"].kind == JString:
+      result.bullet = fetchBullet(data[2]["bullet"].str)
+    elif data[2]["bullet"].kind == JInt:
+      result.bullet = cfg.bullets[data[2]["bullet"].num.int]
+    elif data[2]["bullet"].kind == JObject: 
+      result.bullet = importBullet(data[2]["bullet"], errors)
+    else:
+      errors.add "UNKNOWN BULLET TYPE for item "& result.name
+  of "ammo":
+    result.kind = Ammo
+  of "utility":
+    nil
+  else:
+    errors.add "Invalid item type \""& data[1].str &"\" for item "& result.name
+
+proc importBullet(data: PJsonNode; errors: var seq[string]): PBulletRecord =
+  new(result)
+  result.id = -1
+  
+  var bdata: PJsonNode
+  if data.kind == JArray:
+    result.name = data[0].str
+    bdata = data[1]
+  elif data.kind == JObject:
+    bdata = data
+  else: 
+    errors.add "Malformed bullet record"
+    return
+  
+  result.anim = importAnim(bdata, errors)
+  result.physics = importPhys(bdata)
+  
+  result.lifetime = 2000.0
+  result.inheritVelocity = 1000.0
+  result.baseVelocity = 30.0
+  getField(bdata, "lifetime", result.lifetime)
+  getField(bdata, "inheritVelocity", result.inheritVelocity)
+  getField(bdata, "baseVelocity", result.baseVelocity)
+  result.lifetime /= 1000.0 ## lifetime is stored as milliseconds
+  result.inheritVelocity /= 1000.0 ## inherit velocity 1000 = 1.0 (100%)
+  result.explosion = importExplosion(bdata, errors)
+  result.trail = importTrail(bdata, errors)
diff --git a/tests/manyloc/keineschweine/lib/sg_gui.nim b/tests/manyloc/keineschweine/lib/sg_gui.nim
new file mode 100644
index 000000000..6741fe55e
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sg_gui.nim
@@ -0,0 +1,281 @@
+import
+  sfml, sfml_colors, 
+  input_helpers, sg_packets
+from strutils import countlines
+{.deadCodeElim: on.}
+type
+  PGuiContainer* = ref TGuiContainer
+  TGuiContainer* = object of TObject
+    position: TVector2f
+    activeEntry: PTextEntry
+    widgets: seq[PGuiObject]
+    buttons: seq[PButton]
+  PGuiObject* = ref TGuiObject
+  TGuiObject* = object of TObject
+  PButton* = ref TButton
+  TButton* = object of TGuiObject
+    enabled: bool
+    bg*: sfml.PRectangleShape
+    text*: PText
+    onClick*: TButtonClicked
+    bounds: TFloatRect
+  PButtonCollection* = ref TButtonCollection
+  TButtonCollection* = object of TGuiContainer
+  PTextEntry* = ref TTextEntry
+  TTextEntry* = object of TButton
+    inputClient: input_helpers.PTextInput
+  PMessageArea* = ref TMessageArea
+  TMessageArea* = object of TGuiObject
+    pos: TVector2f
+    messages: seq[TMessage]
+    texts: seq[PText]
+    scrollBack*: int
+    sizeVisible*: int
+    direction*: int
+  TMessage = object
+    color: TColor
+    text: string
+    lines: int
+  TButtonClicked = proc(button: PButton)
+var
+  guiFont* = newFont("data/fnt/LiberationMono-Regular.ttf")
+  messageProto* = newText("", guiFont, 16)
+let
+  vectorZeroF* = vec2f(0.0, 0.0)
+
+proc newGuiContainer*(): PGuiContainer
+proc newGuiContainer*(pos: TVector2f): PGuiContainer {.inline.}
+proc free*(container: PGuiContainer)
+proc add*(container: PGuiContainer; widget: PGuiObject)
+proc clearButtons*(container: PGuiContainer)
+proc click*(container: PGuiContainer; position: TVector2f)
+proc setActive*(container: PGuiContainer; entry: PTextEntry)
+proc setPosition*(container: PGuiContainer; position: TVector2f)
+
+proc update*(container: PGuiContainer; dt: float)
+proc draw*(window: PRenderWindow; container: PGuiContainer) {.inline.}
+
+proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea {.discardable.}
+proc add*(m: PMessageArea; msg: ScChat)
+
+proc draw*(window: PRenderWindow; b: PButton) {.inline.}
+proc click*(b: PButton; p: TVector2f)
+proc setPosition*(b: PButton; p: TVector2f)
+proc setString*(b: PButton; s: string) {.inline.}
+
+proc newButton*(container: PGuiContainer; text: string; position: TVector2f; 
+  onClick: TButtonClicked; startEnabled: bool = true): PButton {.discardable.}
+proc init(b: PButton; text: string; position: TVector2f; onClick: TButtonClicked)
+proc setEnabled*(b: PButton; enabled: bool)
+proc disable*(b: PButton) {.inline.}
+proc enable*(b: PButton) {.inline.}
+
+proc newTextEntry*(container: PGuiContainer; text: string;
+                    position: TVector2f; onEnter: TInputFinishedProc = nil): PTextEntry {.discardable.}
+proc init(t: PTextEntry; text: string; onEnter: TInputFinishedProc)
+proc draw*(window: PRenderWindow, t: PTextEntry) {.inline.}
+proc setActive*(t: PTextEntry) {.inline.}
+proc clearText*(t: PTextEntry) {.inline.}
+proc getText*(t: PTextEntry): string {.inline.}
+
+proc update*(m: PMessageArea)
+
+if guiFont == nil:
+  echo("Could not load font, crying softly to myself.")
+  quit(1)
+
+proc newGuiContainer*(): PGuiContainer =
+  new(result, free)
+  result.widgets = @[]
+  result.buttons = @[]
+proc newGuiContainer*(pos: TVector2f): PGuiContainer =
+  result = newGuiContainer()
+  result.setPosition pos
+proc free*(container: PGuiContainer) = 
+  container.widgets = nil
+  container.buttons = nil
+proc add*(container: PGuiContainer; widget: PGuiObject) =
+  container.widgets.add(widget)
+proc add*(container: PGuiContainer; button: PButton) =
+  if container.isNil: return
+  container.buttons.add(button)
+proc clearButtons*(container: PGuiContainer) =
+  container.buttons.setLen 0
+proc click*(container: PGuiContainer; position: TVector2f) =
+  for b in container.buttons:
+    click(b, position)
+proc setActive*(container: PGuiContainer; entry: PTextEntry) =
+  container.activeEntry = entry
+  setActive(entry)
+proc setPosition*(container: PGuiContainer; position: TVector2f) =
+  container.position = position
+
+
+proc update*(container: PGuiContainer; dt: float) =
+  if not container.activeEntry.isNil:
+    container.activeEntry.setString(container.activeEntry.getText())
+proc draw*(window: PRenderWindow; container: PGuiContainer) =
+  for b in container.buttons:
+    window.draw b
+
+proc free(c: PButton) =
+  c.bg.destroy()
+  c.text.destroy()
+  c.bg = nil
+  c.text = nil
+  c.onClick = nil
+proc newButton*(container: PGuiContainer; text: string;
+                 position: TVector2f; onClick: TButtonClicked;
+                 startEnabled: bool = true): PButton =
+  new(result, free)
+  init(result, 
+       text, 
+       if not container.isNil: position + container.position else: position, 
+       onClick)
+  container.add result
+  if not startEnabled: disable(result)
+
+proc init(b: PButton; text: string; position: TVector2f; onClick: TButtonClicked) =
+  b.bg = newRectangleShape()
+  b.bg.setSize(vec2f(80.0, 16.0))
+  b.bg.setFillColor(color(20, 30, 15))
+  b.text = newText(text, guiFont, 16)
+  b.onClick = onClick
+  b.setPosition(position)
+  b.enabled = true
+proc copy*(c: PButton): PButton =
+  new(result, free)
+  result.bg = c.bg.copy()
+  result.text = c.text.copy()
+  result.onClick = c.onClick
+  result.setPosition(result.bg.getPosition())
+
+proc setEnabled*(b: PButton; enabled: bool) =
+  b.enabled = enabled
+  if enabled:
+    b.text.setColor(White)
+  else:
+    b.text.setColor(Gray)
+proc enable*(b: PButton) = setEnabled(b, true)
+proc disable*(b: PButton) = setEnabled(b, false)
+
+proc draw*(window: PRenderWindow; b: PButton) =
+  window.draw b.bg
+  window.draw b.text
+proc setPosition*(b: PButton, p: TVector2f) =
+  b.bg.setPosition(p)
+  b.text.setPosition(p)
+  b.bounds = b.text.getGlobalBounds()
+proc setString*(b: PButton; s: string) =
+  b.text.setString(s)
+proc click*(b: PButton, p: TVector2f) = 
+  if b.enabled and (addr b.bounds).contains(p.x, p.y): 
+    b.onClick(b)
+
+proc free(obj: PTextEntry) =
+  free(PButton(obj))
+proc newTextEntry*(container: PGuiContainer; text: string; 
+                    position: TVector2F; onEnter: TInputFinishedProc = nil): PTextEntry =
+  new(result, free)
+  init(PButton(result), text, position + container.position, proc(b: PButton) =
+    setActive(container, PTextEntry(b)))
+  init(result, text, onEnter)
+  container.add result
+proc init(t: PTextEntry; text: string; onEnter: TInputFinishedProc) =
+  t.inputClient = newTextInput(text, text.len, onEnter)
+proc draw(window: PRenderWindow; t: PTextEntry) =
+  window.draw PButton(t)
+proc clearText*(t: PTextEntry) =
+  t.inputClient.clear()
+proc getText*(t: PTextEntry): string =
+  return t.inputClient.text
+proc setActive*(t: PTextEntry) =
+  if not t.isNil and not t.inputClient.isNil:
+    input_helpers.setActive(t.inputClient)
+
+
+discard """proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea =
+  new(result)
+  result.messages = @[]
+  result.pos = position
+  container.add(result)
+proc add*(m: PMessageArea, text: string): PText =
+  result = messageProto.copy()
+  result.setString(text)
+  m.messages.add(result)
+  let nmsgs = len(m.messages)
+  var pos   = vec2f(m.pos.x, m.pos.y)
+  for i in countdown(nmsgs - 1, max(nmsgs - 30, 0)):
+    setPosition(m.messages[i], pos)
+    pos.y -= 16.0
+
+proc draw*(window: PRenderWindow; m: PMessageArea) =
+  let nmsgs = len(m.messages) 
+  if nmsgs == 0: return
+  for i in countdown(nmsgs - 1, max(nmsgs - 30, 0)):
+    window.draw(m.messages[i])
+"""
+proc newMessageArea*(container: PGuiContainer; position: TVector2f): PMessageArea =
+  new(result)
+  result.messages = @[]
+  result.texts = @[]
+  result.pos = position + container.position
+  result.sizeVisible = 10
+  result.scrollBack = 0
+  result.direction = -1 ## to push old messages up
+  container.add(result)
+  
+proc add*(m: PMessageArea, msg: ScChat) =
+  const prependName = {CPub, CPriv}
+  var mmm: TMessage
+  if msg.kind in prependName: 
+    mmm.text = "<"
+    mmm.text.add msg.fromPlayer
+    mmm.text.add "> "
+    mmm.text.add msg.text
+  else:
+    mmm.text = msg.text
+  case msg.kind
+  of CPub:  mmm.color = RoyalBlue
+  of CPriv, CSystem: mmm.color = Green
+  of CError: mmm.color = Red
+  
+  mmm.lines = countLines(mmm.text)+1
+  
+  m.messages.add mmm
+  update m
+proc add*(m: PMessageArea, msg: string) {.inline.} =
+  var chat = newScChat(kind = CSystem, text = msg)
+  add(m, chat)
+
+proc proctor*(m: PText; msg: ptr TMessage; pos: ptr TVector2f) =
+  m.setString msg.text 
+  m.setColor msg.color
+  m.setPosition pos[]
+proc update*(m: PMessageArea) =
+  if m.texts.len < m.sizeVisible:
+    echo "adding ", m.sizeVisible - m.texts.len, " fields"
+    for i in 1..m.sizeVisible - m.texts.len:
+      var t = messageProto.copy()
+      m.texts.add messageProto.copy()
+  elif m.texts.len > m.sizeVisible:
+    echo "cutting ", m.texts.len - m.sizeVisible, " fields"
+    for i in m.sizeVisible.. < m.texts.len:
+      m.texts.pop().destroy()
+  let nmsgs = m.messages.len()
+  if m.sizeVisible == 0 or nmsgs == 0: 
+    echo "no messages? ", m.sizeVisible, ", ", nmsgs
+    return
+  var pos = vec2f(m.pos.x, m.pos.y)
+  for i in 0.. min(m.sizeVisible, nmsgs)-1:
+    ##echo nmsgs - i - 1 - m.scrollBack
+    let msg = addr m.messages[nmsgs - i - 1 - m.scrollBack]
+    proctor(m.texts[i], msg, addr pos)
+    pos.y += (16 * m.direction * msg.lines).cfloat  
+
+proc draw*(window: PRenderWindow; m: PMessageArea) =
+  let nmsgs = len(m.texts)
+  if nmsgs == 0: return
+  for i in countdown(nmsgs - 1, max(nmsgs - m.sizeVisible, 0)):
+    window.draw m.texts[i]
+
diff --git a/tests/manyloc/keineschweine/lib/sg_packets.nim b/tests/manyloc/keineschweine/lib/sg_packets.nim
new file mode 100644
index 000000000..30e83c147
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sg_packets.nim
@@ -0,0 +1,106 @@
+import genpacket_enet, sockets, md5, enet
+defPacketImports()
+
+type
+  PacketID* = char
+
+template idpacket(pktName, id, s2c, c2s: expr): stmt {.immediate, dirty.} =
+  let `H pktName`* {.inject.} = id
+  defPacket(`Sc pktName`, s2c)
+  defPacket(`Cs pktName`, c2s)
+
+forwardPacketT(Uint8, int8)
+forwardPacketT(Uint16, int16)
+forwardPacketT(TPort, int16)
+
+idPacket(Login, 'a',
+  tuple[id: int32; alias: string; sessionKey: string],
+  tuple[alias: string, passwd: string])
+
+let HZoneJoinReq* = 'j'
+defPacket(CsZoneJoinReq, tuple[session: ScLogin])
+
+defPacket(ScZoneRecord, tuple[
+  name: string = "", desc: string = "",
+  ip: string = "", port: TPort = 0.Tport])
+idPacket(ZoneList, 'z',
+  tuple[network: string = "", zones: seq[ScZoneRecord]],
+  tuple[time: string])
+
+let HPoing* = 'p'
+defPacket(Poing, tuple[id: int32, time: float32])
+
+type ChatType* = enum
+  CPub = 0'i8, CPriv, CSystem, CError
+forwardPacketT(ChatType, int8)
+idPacket(Chat, 'C', 
+  tuple[kind: ChatType = CPub; fromPlayer: string = ""; text: string = ""],
+  tuple[target: string = ""; text: string = ""])
+
+idPacket(Hello, 'h',
+  tuple[resp: string],
+  tuple[i: int8 = 14])
+
+let HPlayerList* = 'P'
+defPacket(ScPlayerRec, tuple[id: int32; alias: string = ""])
+defPacket(ScPlayerList, tuple[players: seq[ScPlayerRec]])
+
+let HTeamList* = 'T'
+defPacket(ScTeam, tuple[id: int8; name: string = ""])
+defPacket(ScTeamList, tuple[teams: seq[ScTeam]])
+let HTeamChange* = 't'
+
+idPacket(ZoneQuery, 'Q',
+  tuple[playerCount: Uint16], ##i should include a time here or something
+  tuple[pad: char = '\0'])
+
+type SpawnKind = enum
+  SpawnItem = 1'i8, SpawnVehicle, SpawnObject
+forwardPacketT(SpawnKind, int8)
+defPacket(ScSpawn, tuple[
+  kind: SpawnKind; id: uint16; record: uint16; amount: uint16])
+
+
+
+
+type TAssetType* = enum
+  FZoneCfg = 1'i8, FGraphics, FSound 
+
+forwardPacketT(TAssetType, int8)
+forwardPacket(MD5Digest, array[0..15, int8])
+
+idPacket(FileChallenge, 'F',
+  tuple[file: string; assetType: TAssetType; fullLen: int32],
+  tuple[needFile: bool; checksum: MD5Digest])
+
+
+let HChallengeResult* = '('
+defPacket(ScChallengeResult, tuple[status: bool])
+
+let HFileTransfer* = 'f'
+defPacket(ScFileTransfer, tuple[fileSize: int32; pos: int32; data: string])
+defPacket(CsFilepartAck, tuple[lastpos: int32])
+
+##dir server messages
+let HZoneLogin* = 'u'
+defPacket(SdZoneLogin, tuple[name: string; key: string; record: ScZoneRecord])
+defPacket(DsZoneLogin, tuple[status: bool])
+let HDsMsg* = 'c'
+defPacket(DsMsg, tuple[msg: string])
+let HVerifyClient* = 'v'
+defPacket(SdVerifyClient, tuple[session: ScLogin])
+
+when isMainModule:
+  
+  var buf = newBuffer(100)
+  var m = toMd5("hello there")
+  echo(repr(m))
+  buf.pack m
+
+  echo(repr(buf.data))
+  echo(len(buf.data))
+  
+  buf.reset()
+
+  var x = buf.readMD5Digest()
+  echo(repr(x))
diff --git a/tests/manyloc/keineschweine/lib/sound_buffer.nim b/tests/manyloc/keineschweine/lib/sound_buffer.nim
new file mode 100644
index 000000000..a88eb08de
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/sound_buffer.nim
@@ -0,0 +1,38 @@
+when defined(NoSFML) or defined(NoChipmunk):
+  {.error.}
+import sfml_audio, sfml_stuff, sg_assets, chipmunk
+const
+  MinDistance* = 350.0
+  Attenuation* = 20.0
+var
+  liveSounds: seq[PSound] = @[]
+  deadSounds: seq[PSound] = @[]
+
+proc playSound*(sound: PSoundRecord, pos: TVector) =
+  if sound.isNil or sound.soundBuf.isNil: return
+  var s: PSound
+  if deadSounds.len == 0:
+    s = sfml_audio.newSound()
+    s.setLoop false
+    s.setRelativeToListener true
+    s.setAttenuation Attenuation
+    s.setMinDistance MinDistance
+  else:
+    s = deadSounds.pop()
+  s.setPosition(vec3f(pos.x, 0, pos.y))
+  s.setBuffer(sound.soundBuf)
+  s.play()
+  liveSounds.add s
+
+proc updateSoundBuffer*() =
+  var i = 0
+  while i < len(liveSounds):
+    if liveSounds[i].getStatus == Stopped:
+      deadSounds.add liveSounds[i]
+      liveSounds.del i
+    else:
+      inc i
+
+proc report*() =
+  echo "live: ", liveSounds.len
+  echo "dead: ", deadSounds.len
diff --git a/tests/manyloc/keineschweine/lib/vehicles.nim b/tests/manyloc/keineschweine/lib/vehicles.nim
new file mode 100644
index 000000000..edbd84ff9
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/vehicles.nim
@@ -0,0 +1,35 @@
+import
+  sfml, chipmunk, 
+  sg_assets, sfml_stuff, keineschweine
+
+
+proc accel*(obj: PVehicle, dt: float) =
+  #obj.velocity += vec2f(
+  #  cos(obj.angle) * obj.record.handling.thrust.float * dt,
+  #  sin(obj.angle) * obj.record.handling.thrust.float * dt)
+  obj.body.applyImpulse(
+    vectorForAngle(obj.body.getAngle()) * dt * obj.record.handling.thrust,
+    vectorZero)
+proc reverse*(obj: PVehicle, dt: float) =
+  #obj.velocity += vec2f(
+  #  -cos(obj.angle) * obj.record.handling.reverse.float * dt,
+  #  -sin(obj.angle) * obj.record.handling.reverse.float * dt)
+  obj.body.applyImpulse(
+    -vectorForAngle(obj.body.getAngle()) * dt * obj.record.handling.reverse,
+    vectorZero)
+proc strafe_left*(obj: PVehicle, dt: float) =
+  obj.body.applyImpulse(
+    vectorForAngle(obj.body.getAngle()).perp() * obj.record.handling.strafe * dt,
+    vectorZero)
+proc strafe_right*(obj: PVehicle, dt: float) =
+  obj.body.applyImpulse(
+    vectorForAngle(obj.body.getAngle()).rperp()* obj.record.handling.strafe * dt,
+    vectorZero)
+proc turn_right*(obj: PVehicle, dt: float) =
+  #obj.angle = (obj.angle + (obj.record.handling.rotation.float / 10.0 * dt)) mod TAU
+  obj.body.setTorque(obj.record.handling.rotation)
+proc turn_left*(obj: PVehicle, dt: float) =
+  #obj.angle = (obj.angle - (obj.record.handling.rotation.float / 10.0 * dt)) mod TAU
+  obj.body.setTorque(-obj.record.handling.rotation)
+proc offsetAngle*(obj: PVehicle): float {.inline.} =
+  return (obj.record.anim.angle + obj.body.getAngle())
diff --git a/tests/manyloc/keineschweine/lib/zlib_helpers.nim b/tests/manyloc/keineschweine/lib/zlib_helpers.nim
new file mode 100644
index 000000000..ef977afb0
--- /dev/null
+++ b/tests/manyloc/keineschweine/lib/zlib_helpers.nim
@@ -0,0 +1,40 @@
+import zlib
+
+proc compress*(source: string): string =
+  var
+    sourcelen = source.len
+    destlen = sourcelen + (sourcelen.float * 0.1).int + 16
+  result = ""
+  result.setLen destLen
+  var res = zlib.compress(cstring(result), addr destLen, cstring(source), sourceLen)
+  if res != Z_OK:
+    echo "Error occured: ", res
+  elif destLen < result.len:
+    result.setLen(destLen)
+
+proc uncompress*(source: string, destLen: var int): string =
+  result = ""
+  result.setLen destLen
+  var res = zlib.uncompress(cstring(result), addr destLen, cstring(source), source.len)
+  if res != Z_OK:
+    echo "Error occured: ", res
+    
+
+when isMainModule:
+  import strutils
+  var r = compress("Hello")
+  echo repr(r)
+  var l = "Hello".len
+  var rr = uncompress(r, l)
+  echo repr(rr)
+  assert rr == "Hello"
+
+  proc `*`(a: string; b: int): string {.inline.} = result = repeatStr(b, a)
+  var s = "yo dude sup bruh homie" * 50
+  r = compress(s)
+  echo s.len, " -> ", r.len
+
+  l = s.len
+  rr = uncompress(r, l)
+  echo r.len, " -> ", rr.len
+  assert rr == s
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/nakefile.nim b/tests/manyloc/keineschweine/nakefile.nim
new file mode 100644
index 000000000..f175321b9
--- /dev/null
+++ b/tests/manyloc/keineschweine/nakefile.nim
@@ -0,0 +1,155 @@
+import nake
+import httpclient, zipfiles, times, math
+nakeImports
+
+randomize()
+
+const 
+  GameAssets = "http://dl.dropbox.com/u/37533467/data-08-01-2012.7z"
+  BinLibs = "http://dl.dropbox.com/u/37533467/libs-2012-09-12.zip"
+  ExeName = "keineschweine"
+  ServerDefines = "-d:NoSFML -d:NoChipmunk"
+  TestBuildDefines = "-d:escapeMenuTest -d:debugWeps -d:showFPS -d:moreNimrod -d:debugKeys -d:foo -d:recordMode --forceBuild"
+  ReleaseDefines = "-d:release --deadCodeElim:on"
+  ReleaseTestDefines = "-d:debugWeps -d:debugKeys --forceBuild"
+
+task "testprofile", "..":
+  if shell("nimrod", TestBuildDefines, "--profiler:on", "--stacktrace:on", "compile", ExeName) == 0:
+    shell "."/ExeName, "offline"
+
+task "test", "Build with test defines":
+  if shell("nimrod", TestBuildDefines, "compile", ExeName) != 0:
+    quit "The build failed."
+
+task "testrun", "Build with test defines and run":
+  runTask "test"
+  shell "."/ExeName
+
+task "test2", "Build release test build test release build":
+  if shell("nimrod", ReleaseDefines, ReleaseTestDefines, "compile", ExeName) == 0:
+    shell "."/ExeName
+
+discard """task "dirserver", "build the directory server":
+  withDir "server":
+    if shell("nimrod", ServerDefines, "compile", "dirserver") != 0:
+      echo "Failed to build the dirserver"
+      quit 1"""
+
+task "zoneserver", "build the zone server":
+  withDir "enet_server":
+    if shell("nimrod", ServerDefines, "compile", "enet_server") != 0:
+      quit "Failed to build the zoneserver"
+task "zoneserver-gui", "build the zone server, with gui!":
+  withDir "enet_server":
+    if shell("nimrod", ServerDefines, "--app:gui", "compile", "enet_server") != 0:
+      quit "Failed to build the zoneserver"
+
+task "servers", "build the server and directory server":
+  #runTask "dirserver"
+  runTask "zoneserver"
+  echo "Successfully built both servers :')"
+
+task "all", "run SERVERS and TEST tasks":
+  runTask "servers"
+  runTask "test"
+
+task "release", "release build":
+  let res = shell("nimrod", ReleaseDefines, "compile", ExeName)
+  if res != 0:
+    echo "The build failed."
+    quit 1
+  else:
+    runTask "clean"
+    ## zip up all the files and such or something useful here 
+
+task "testskel", "create skeleton test dir for testing":
+  let dirname = "test-"& $random(5000)
+  removeDir dirName
+  createDir dirName/"data/fnt"
+  copyFile "data/fnt/LiberationMono-Regular", dirName/"data/fnt/LiberationMono-Regular.ttf"
+  copyFile "client_settings.json", dirName/"client_settings.json"
+  runTask "test"
+  copyFile ExeName, dirName/ExeName
+  withDir dirName:
+    shell "."/ExeName
+
+
+task "clean", "cleanup generated files":
+  var dirs = @["nimcache", "server"/"nimcache"]
+  dirs.each(proc(x: var string) =
+    if existsDir(x): removeDir(x))
+
+task "download", "download game assets":
+  var
+    skipAssets = false
+    path = expandFilename("data")
+  path.add DirSep
+  path.add(extractFilename(gameAssets))
+  if existsFile(path):
+    echo "The file already exists\n",
+      "[R]emove  [M]ove  [Q]uit  [S]kip    Source: ", GameAssets
+    case stdin.readLine.toLower
+    of "r":
+      removeFile path
+    of "m":
+      moveFile path, path/../(extractFilename(gameAssets)&"-old")
+    of "s":
+      skipAssets = true
+    else:
+      quit 0
+  else:
+    echo "Downloading from ", GameAssets
+  if not skipAssets:
+    echo "Downloading to ", path
+    downloadFile gameAssets, path
+    echo "Download finished"
+  
+    let targetDir = parentDir(parentDir(path))
+    when defined(linux):
+      let z7 = findExe("7z")
+      if z7 == "":
+        echo "Could not find 7z"
+      elif shell(z7, "t", path) != 0: ##note to self: make sure this is right
+        echo "Bad download"
+      else:
+        echo "Unpacking..."
+        shell(z7, "x", "-w[$1]" % targetDir, path)
+    else:
+      echo "I do not know how to unpack the data on this system. Perhaps you could ",
+        "fill this part in?"
+  
+  echo "Download binary libs? Only libs for linux are available currently, enjoy the irony.\n",
+    "[Y]es [N]o   Source: ", BinLibs
+  case stdin.readline.toLower
+  of "y", "yes":
+    discard ## o_O
+  else:
+    return
+  path = extractFilename(BinLibs)
+  downloadFile BinLibs, path 
+  echo "Downloaded dem libs ", path
+  when true: echo "Unpack it yourself, sorry."
+  else:  ## this crashes, dunno why
+    var 
+      z: TZipArchive
+      destDir = getCurrentDir()/("unzip"& $random(5000))
+    if not z.open(path, fmRead):
+      echo "Could not open zip, bad download?"
+      return
+    echo "Extracting to ", destDir
+    createDir destDir
+    #z.extractAll destDir
+    for f in z.walkFiles():
+      z.extractFile(f, destDir/f)
+    z.close()
+    echo "Extracted the libs dir. Copy the ones you need to this dir."
+
+task "zip-lib", "zip up the libs dir":
+  var z: TZipArchive
+  if not z.open("libs-"& getDateStr() &".zip", fmReadWrite):
+    quit "Could not open zip"
+  for file in walkDirRec("libs", {pcFile, pcDir}):
+    echo "adding file ", file
+    z.addFile(file)
+  z.close()
+  echo "Great success!"
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/nakefile.nimrod.cfg b/tests/manyloc/keineschweine/nakefile.nimrod.cfg
new file mode 100644
index 000000000..6f3e86fe6
--- /dev/null
+++ b/tests/manyloc/keineschweine/nakefile.nimrod.cfg
@@ -0,0 +1 @@
+path = "dependencies/nake"
diff --git a/tests/manyloc/keineschweine/server/dirserver_settings.json b/tests/manyloc/keineschweine/server/dirserver_settings.json
new file mode 100644
index 000000000..18c15fb46
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/dirserver_settings.json
@@ -0,0 +1,7 @@
+{
+ "network":"lamenet",
+ "port":2049,
+ "zones":[
+  {"name":"alphazone","key":"skittles"} 
+ ]
+}
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/server/nimrod.cfg b/tests/manyloc/keineschweine/server/nimrod.cfg
new file mode 100644
index 000000000..fdc45a8e1
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/nimrod.cfg
@@ -0,0 +1,6 @@
+debugger = off
+deadCodeElim = on
+path = ".."
+path = "../genpacket"
+path = "../helpers"
+define = NoSFML
diff --git a/tests/manyloc/keineschweine/server/old_dirserver.nim b/tests/manyloc/keineschweine/server/old_dirserver.nim
new file mode 100644
index 000000000..897fc7d32
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/old_dirserver.nim
@@ -0,0 +1,201 @@
+## directory server
+## handles client authorization and assets
+
+import
+  sockets, times, streams, streams_enh, tables, json, os,
+  sg_packets, sg_assets, md5, server_utils, map_filter
+type
+  THandler = proc(client: PCLient; stream: PStream)
+var
+  server: TSocket
+  handlers = initTable[char, THandler](16)
+  thisZone = newScZoneRecord("local", "sup")
+  zoneList = newScZoneList()
+  thisZoneSettings: string
+  zoneSlots: seq[tuple[name: string; key: string]] = @[]
+  zones: seq[PClient] = @[]
+  ## I was high.
+  clients = initTable[TupAddress, PClient](16)
+  alias2client = initTable[string, PClient](32)
+  allClients: seq[PClient] = @[] 
+
+proc findClient*(host: string; port: int16): PClient =
+  let addy: TupAddress = (host, port)
+  if clients.hasKey(addy):
+    return clients[addy]
+  result = newClient(addy)
+  clients[addy] = result
+  allClients.add(result)
+
+proc loginZone(client: PClient; login: SdZoneLogin): bool =
+  if not client.auth:
+    for s in zoneSlots.items:
+      if s.name == login.name and s.key == login.key:
+        client.auth = true
+        client.kind = CServer
+        client.record = login.record
+        result = true
+        break
+
+proc sendZoneList(client: PClient) = 
+  echo(">> zonelist ", client, ' ', HZoneList)
+  client.send(HZonelist, zonelist)
+proc forwardPrivate(rcv: PClient; sender: PClient; txt: string) =
+  var m = newScChat(CPriv, sender.alias, txt)
+  rcv.send(HChat, m)
+proc sendChat(client: PClient; kind: ChatType; txt: string) =
+  echo(">> chat ", client)
+  var m = newScChat(kind, "", txt)
+  client.send(HChat, m)
+
+
+
+var pubChatQueue = newIncomingBuffer()
+proc queuePub(sender: string, msg: CsChat) =
+  var chat = newScChat(kind = CPub, fromPlayer = sender, text = msg.text)
+  pubChatQueue.write(HChat)
+  chat.pack(pubChatQueue)
+
+handlers[HHello] = (proc(client: PClient; stream: PStream) =
+  var h = readCsHello(stream)
+  if h.i == 14:
+    var greet = newScHello("Well hello there")
+    client.send(HHello, greet))
+handlers[HLogin] = proc(client: PClient; stream: PStream) =
+  var loginInfo = readCsLogin(stream)
+  echo("** login: alias = ", loginInfo.alias)
+  if alias2client.hasKey(loginInfo.alias):
+    client.sendError("Alias in use.")
+    return
+  if client.loginPlayer(loginInfo):
+    alias2client[client.alias] = client
+    client.sendMessage("Welcome "& client.alias)
+    var session = newScLogin(client.id, client.alias, client.session)
+    client.send HLogin, session
+    client.sendZonelist()
+
+handlers[HZoneList] = proc(client: PClient; stream: PStream) =
+  var pinfo = readCsZoneList(stream)
+  echo("** zonelist req")
+  sendZoneList client
+handlers[HChat] = proc(client: PClient; stream: PStream) =
+  var chat = readCsChat(stream)
+  if not client.auth:
+    client.sendError("You are not logged in.")
+    return
+  if chat.target != "": ##private
+    if alias2client.hasKey(chat.target):
+      alias2client[chat.target].forwardPrivate(client, chat.text)
+  else:
+    queuePub(client.alias, chat)
+
+proc sendServMsg(client: PClient; msg: string) =
+  var m = newDsMsg(msg)
+  client.send HDsMsg, m
+handlers[HZoneLogin] = proc(client: PClient; stream: PStream) =
+  var 
+    login = readSdZoneLogin(stream)
+  if not client.loginZone(login):
+    client.sendServMsg "Invalid login"
+  else:
+    client.sendServMsg "Welcome to the servers"
+    echo "** Zone logged in: ", login
+    zones.add client
+    zonelist.zones.add client.record
+
+
+handlers[HFileChallenge] = proc(client: PClient; stream: PStream) =
+  if client.auth:
+    if client.kind == CServer:
+      var chg = readScFileChallenge(stream)
+
+proc handlePkt(s: PClient; stream: PStream) =
+  while not stream.atEnd:  
+    var typ = readChar(stream)
+    if not handlers.hasKey(typ):
+      break
+    else:
+      handlers[typ](s, stream)
+
+proc createServer(port: TPort) =
+  if not server.isNil:
+    server.close()
+  server = socket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, buffered = false)
+  server.bindAddr(port)
+
+
+var clientIndex = 0
+var incoming = newIncomingBuffer()
+proc poll*(timeout: int = 250) =
+  if server.isNil: return
+  var 
+    reads = @[server]
+    writes = @[server]
+  if select(reads, timeout) > 0:
+    var
+      addy = ""
+      port: TPort
+    incoming.data.setLen 512
+    let res = server.recvFromAsync(incoming.data, 512, addy, port, 0)
+    if not res:
+      echo("No recv")
+      return
+    else:
+      var client = findClient(addy, port.int16)
+      echo "<< ", res, " ", client, ": ", len(incoming.data), " ", repr(incoming.data)
+      handlePkt(client, incoming)
+    incoming.flush()
+  if selectWrite(writes, timeout) > 0:
+    let nclients = allClients.len
+    if nclients == 0:
+      return
+    clientIndex = (clientIndex + 1) mod nclients
+    var c = allClients[clientIndex]
+    if c.outputBuf.getPosition > 0:
+      let res = server.sendTo(c.addy.host, c.addy.port.TPort, c.outputBuf.data)
+      echo("Write ", c, " result: ", res, " data: ", repr(c.outputBuf.data))
+      c.outputBuf.flush()
+
+when isMainModule:
+  import parseopt, matchers, strutils
+  var cfgFile = "dirserver_settings.json"
+  for kind, key, val in getOpt():
+    case kind
+    of cmdShortOption, cmdLongOption:
+      case key
+      of "f", "file": 
+        if existsFile(val):
+          cfgFile = val
+        else:
+          echo("File does not exist: ", val)
+      else:
+        echo("Unknown option: ", key," ", val)
+    else:
+      echo("Unknown option: ", key, " ", val)
+  var jsonSettings = parseFile(cfgFile)
+  let port = TPort(jsonSettings["port"].num)
+  zonelist.network = jsonSettings["network"].str
+  for slot in jsonSettings["zones"].items:
+    zoneSlots.add((slot["name"].str, slot["key"].str))
+  
+  createServer(port)
+  echo("Listening on port ", port, "...")
+  var pubChatTimer = cpuTime() #newClock()
+  const PubChatDelay = 1000/1000
+  while true:
+    poll(15)
+    ## TODO sort this type of thing VV into a queue api 
+    if cpuTime() - pubChatTimer > PubChatDelay:       #.getElapsedTime.asMilliseconds > 100:
+      pubChatTimer -= pubChatDelay
+      if pubChatQueue.getPosition > 0:
+        var cn = 0
+        let sizePubChat = pubChatQueue.data.len
+        var sent = 0
+        filterIt2(allClients, it.auth == true and it.kind == CPlayer):
+          it.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat)
+          sent += 1
+        #for c in allClients:
+        #  c.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat)
+        pubChatQueue.flush()
+        echo "pubChatQueue flushed to ", sent, "clients"
+
diff --git a/tests/manyloc/keineschweine/server/old_server_utils.nim b/tests/manyloc/keineschweine/server/old_server_utils.nim
new file mode 100644
index 000000000..af9a1b01e
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/old_server_utils.nim
@@ -0,0 +1,98 @@
+import 
+  streams, md5, sockets, unsigned,
+  sg_packets, zlib_helpers, idgen
+type
+  TClientType* = enum
+    CServer = 0'i8, CPlayer, CUnknown
+  PClient* = ref TClient
+  TClient* = object of TObject
+    id*: int32
+    addy*: TupAddress
+    clientID*: uint16
+    auth*: bool
+    outputBuf*: PStringStream
+    case kind*: TClientType
+    of CPlayer:
+      alias*: string
+      session*: string
+      lastPing*: float
+      failedPings*: int
+    of CServer:
+      record*: ScZoneRecord
+      cfg*: TChecksumFile
+    of CUnknown: nil
+  TChecksumFile* = object
+    unpackedSize*: int
+    sum*: MD5Digest
+    compressed*: string
+  TupAddress* = tuple[host: string, port: int16]
+  PIDGen*[T: Ordinal] = ref TIDGen[T]
+  TIDGen[T: Ordinal] = object
+    max: T
+    freeIDs: seq[T]
+var cliID = newIdGen[int32]()
+
+proc sendMessage*(client: PClient; txt: string)
+proc sendError*(client: PClient; txt: string)
+proc `$`*(client: PClient): string
+
+proc newIncomingBuffer*(size = 1024): PStringStream =
+  result = newStringStream("")
+  result.data.setLen size
+  result.data.setLen 0
+  result.flushImpl = proc(stream: PStream) =
+    stream.setPosition(0)
+    PStringStream(stream).data.setLen(0)
+
+
+proc free*(c: PClient) =
+  echo "Client freed: ", c
+  cliID.del c.id
+  c.outputBuf.flush()
+  c.outputBuf = nil
+proc newClient*(addy: TupAddress): PClient =
+  new(result, free)
+  result.addy = addy
+  result.outputBuf = newStringStream("")
+  result.outputBuf.flushImpl = proc(stream: PStream) = 
+    stream.setPosition 0
+    PStringStream(stream).data.setLen 0
+
+proc loginPlayer*(client: PClient; login: CsLogin): bool =
+  if client.auth:
+    client.sendError("You are already logged in.")
+    return
+  client.id = cliID.next()
+  client.auth = true
+  client.kind = CPlayer
+  client.alias = login.alias
+  client.session = getMD5(client.alias & $rand(10000))
+  result = true
+
+proc `$`*(client: PClient): string =
+  if not client.auth: return $client.addy
+  case client.kind
+  of CPlayer: result = client.alias
+  of CServer: result = client.record.name
+  else: result = $client.addy
+proc send*[T](client: PClient; pktType: char; pkt: var T) =
+  client.outputBuf.write(pktType)
+  pkt.pack(client.outputBuf)
+
+proc sendMessage*(client: PClient; txt: string) =
+  var m = newScChat(CSystem, text = txt)
+  client.send HChat, m
+proc sendError*(client: PClient; txt: string) =
+  var m = newScChat(CError, text = txt)
+  client.send HChat, m
+
+proc checksumFile*(filename: string): TChecksumFile =
+  let fullText = readFile(filename)
+  result.unpackedSize = fullText.len
+  result.sum = toMD5(fullText)
+  result.compressed = compress(fullText)
+proc checksumStr*(str: string): TChecksumFile =
+  result.unpackedSize = str.len
+  result.sum = toMD5(str)
+  result.compressed = compress(str)
+
diff --git a/tests/manyloc/keineschweine/server/old_sg_server.nim b/tests/manyloc/keineschweine/server/old_sg_server.nim
new file mode 100644
index 000000000..ac85cbf62
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/old_sg_server.nim
@@ -0,0 +1,254 @@
+import
+  sockets, times, streams, streams_enh, tables, json, os, unsigned,
+  sg_packets, sg_assets, md5, server_utils, client_helpers
+var
+  dirServer: PServer
+  thisZone = newScZoneRecord("local", "sup")
+  thisZoneSettings: PZoneSettings
+  dirServerConnected = false
+  ## I was high.
+  clients = initTable[TupAddress, PClient](16)
+  alias2client = initTable[string, PClient](32)
+  allClients: seq[PClient] = @[] 
+  zonePlayers: seq[PClient] = @[] 
+const
+  PubChatDelay = 100/1000 #100 ms
+
+import hashes
+proc hash*(x: uint16): THash {.inline.} = 
+  result = int32(x)
+
+proc findClient*(host: string; port: int16): PClient =
+  let addy: TupAddress = (host, port)
+  if clients.hasKey(addy):
+    return clients[addy]
+  result = newClient(addy)
+  clients[addy] = result
+  allClients.add(result)
+
+
+proc sendZoneList(client: PClient) = 
+  echo(">> zonelist ", client)
+  #client.send(HZonelist, zonelist)
+
+proc forwardPrivate(rcv: PClient; sender: PClient; txt: string) =
+  var m = newScChat(CPriv, sender.alias, txt)
+  rcv.send(HChat, m)
+proc sendChat(client: PClient; kind: ChatType; txt: string) =
+  echo(">> chat ", client)
+  var m = newScChat(kind, "", txt)
+  client.send(HChat, m)
+
+var pubChatQueue = newStringStream("")
+pubChatQueue.flushImpl = proc(stream: PStream) =
+  stream.setPosition(0)
+  PStringStream(stream).data.setLen(0)
+proc queuePub(sender: string, msg: CsChat) =
+  var chat = newScChat(kind = CPub, fromPlayer = sender, text = msg.text)
+  pubChatQueue.write(HChat)
+  chat.pack(pubChatQueue)
+
+handlers[HHello] = (proc(client: PClient; stream: PStream) =
+  var h = readCsHello(stream)
+  if h.i == 14:
+    var greet = newScHello("Well hello there")
+    client.send(HHello, greet))
+handlers[HLogin] = proc(client: PClient; stream: PStream) =
+  var loginInfo = readCsLogin(stream)
+  echo("** login: alias = ", loginInfo.alias)
+  if not dirServerConnected and client.loginPlayer(loginInfo):
+    client.sendMessage("Welcome "& client.alias)
+    alias2client[client.alias] = client
+    client.sendZonelist()
+handlers[HZoneList] = proc(client: PClient; stream: PStream) =
+  var pinfo = readCsZoneList(stream)
+  echo("** zonelist req")
+handlers[HChat] = proc(client: PClient; stream: PStream) =
+  var chat = readCsChat(stream)
+  if not client.auth:
+    client.sendError("You are not logged in.")
+    return
+  if chat.target != "": ##private
+    if alias2client.hasKey(chat.target):
+      alias2client[chat.target].forwardPrivate(client, chat.text)
+  else:
+    queuePub(client.alias, chat)
+handlers[HZoneQuery] = proc(client: PClient; stream: PStream) =
+  echo("Got zone query")
+  var q = readCsZoneQuery(stream)
+  var resp = newScZoneQuery(zonePlayers.len.uint16)
+  client.send(HZoneQuery, resp)
+
+
+
+handlers[HZoneJoinReq] = proc(client: PClient; stream: PStream) =
+  var req = readCsZoneJoinReq(stream)
+  echo "Join zone request from (",req.session.id,") ", req.session.alias 
+  if client.auth and client.kind == CPlayer:
+    echo "Client is authenticated, verifying filez"
+    client.startVerifyingFiles()
+  elif dirServerConnected:
+    echo "Dirserver is connected, verifying client"
+    dirServer.send HVerifyClient, req.session
+  else:
+    echo "Dirserver is disconnected =("
+    client.startVerifyingFiles()
+
+
+
+proc handlePkt(s: PClient; stream: PStream) =
+  while not stream.atEnd:  
+    var typ = readChar(stream)
+    if not handlers.hasKey(typ):
+      break
+    else:
+      handlers[typ](s, stream)
+
+proc createServer(port: TPort) =
+  if not server.isNil:
+    server.close()
+  server = socket(typ = SOCK_DGRAM, protocol = IPPROTO_UDP, buffered = false)
+  server.bindAddr(port)
+
+var clientIndex = 0
+var incoming = newIncomingBuffer()
+proc poll*(timeout: int = 250) =
+  if server.isNil: return
+  var 
+    reads = @[server]
+    writes = @[server]
+  if select(reads, timeout) > 0:
+    var
+      addy = ""
+      port: TPort
+    let res = server.recvFromAsync(incoming.data, 512, addy, port, 0)
+    if not res:
+      echo("No recv")
+      return
+    else:
+      var client = findClient(addy, port.int16)
+      #echo("<< ", res, " ", client.alias, ": ", len(line.data), " ", repr(line.data))
+      handlePkt(client, incoming)
+    incoming.flush()
+  if selectWrite(writes, timeout) > 0:
+    let nclients = allClients.len
+    if nclients == 0:
+      return
+    clientIndex = (clientIndex + 1) mod nclients
+    var c = allClients[clientIndex]
+    if c.outputBuf.getPosition > 0:
+      let res = server.sendTo(c.addy.host, c.addy.port.TPort, c.outputBuf.data)
+      echo("Write ", c, " result: ", res, " data: ", c.outputBuf.data)
+      c.outputBuf.flush()
+
+when isMainModule:
+  import parseopt, matchers, strutils
+  var zoneCfgFile = "./server_settings.json"
+  for kind, key, val in getOpt():
+    case kind
+    of cmdShortOption, cmdLongOption:
+      case key
+      of "f", "file": 
+        if existsFile(val):
+          zoneCfgFile = val
+        else:
+          echo("File does not exist: ", val)
+      else:
+        echo("Unknown option: ", key," ", val)
+    else:
+      echo("Unknown option: ", key, " ", val)
+  var jsonSettings = parseFile(zoneCfgFile)
+  let 
+    host = jsonSettings["host"].str
+    port = TPort(jsonSettings["port"].num)
+    zoneFile = jsonSettings["settings"].str
+    dirServerInfo = jsonSettings["dirserver"]
+  
+  var path = getAppDir()/../"data"/zoneFile
+  if not existsFile(path):
+    echo("Zone settings file does not exist: ../data/", zoneFile)
+    echo(path)
+    quit(1)
+  
+  ## Test file
+  block:
+    var 
+      TestFile: FileChallengePair
+      contents = repeatStr(2, "abcdefghijklmnopqrstuvwxyz")
+    testFile.challenge = newScFileChallenge("foobar.test", FZoneCfg, contents.len.int32) 
+    testFile.file = checksumStr(contents)
+    myAssets.add testFile
+  
+  setCurrentDir getAppDir().parentDir()
+  block:
+    let zonesettings = readFile(path)
+    var 
+      errors: seq[string] = @[]
+    if not loadSettings(zoneSettings, errors):
+      echo("You have errors in your zone settings:")
+      for e in errors: echo("**", e)
+      quit(1)
+    errors.setLen 0
+    
+    var pair: FileChallengePair
+    pair.challenge.file = zoneFile
+    pair.challenge.assetType = FZoneCfg
+    pair.challenge.fullLen = zoneSettings.len.int32
+    pair.file = checksumStr(zoneSettings)
+    myAssets.add pair
+    
+    allAssets:
+      if not load(asset):
+        echo "Invalid or missing file ", file
+      else:
+        var pair: FileChallengePair
+        pair.challenge.file = file
+        pair.challenge.assetType = assetType
+        pair.challenge.fullLen = getFileSize(
+          expandPath(assetType, file)).int32
+        pair.file = asset.contents
+        myAssets.add pair
+        
+    echo "Zone has ", myAssets.len, " associated assets"
+    
+      
+    dirServer = newServerConnection(dirServerInfo[0].str, dirServerInfo[1].num.TPort)
+    dirServer.handlers[HDsMsg] = proc(serv: PServer; stream: PStream) =
+      var m = readDsMsg(stream)
+      echo("DirServer> ", m.msg)
+    dirServer.handlers[HZoneLogin] = proc(serv: PServer; stream: PStream) =
+      let loggedIn = readDsZoneLogin(stream).status
+      if loggedIn:
+        dirServerConnected = true
+    dirServer.writePkt HZoneLogin, login
+  
+  thisZone.name = jsonSettings["name"].str
+  thisZone.desc = jsonSettings["desc"].str
+  thisZone.ip = "localhost"
+  thisZone.port = port
+  var login = newSdZoneLogin(
+    dirServerInfo[2].str, dirServerInfo[3].str,
+    thisZone)  
+  #echo "MY LOGIN: ", $login
+  
+  
+  
+  createServer(port)
+  echo("Listening on port ", port, "...")
+  var pubChatTimer = cpuTime()#newClock()
+  while true:
+    discard dirServer.pollServer(15)
+    poll(15)
+    ## TODO sort this type of thing VV into a queue api
+    #let now = cpuTime() 
+    if cpuTime() - pubChatTimer > PubChatDelay:       #.getElapsedTime.asMilliseconds > 100:
+      pubChatTimer -= pubChatDelay #.restart()
+      if pubChatQueue.getPosition > 0:
+        var cn = 0
+        let sizePubChat = pubChatQueue.data.len
+        for c in allClients:
+          c.outputBuf.writeData(addr pubChatQueue.data[0], sizePubChat)
+        pubChatQueue.flush()
+
+  
+  
\ No newline at end of file
diff --git a/tests/manyloc/keineschweine/server/sg_lobby.nim b/tests/manyloc/keineschweine/server/sg_lobby.nim
new file mode 100644
index 000000000..042d72337
--- /dev/null
+++ b/tests/manyloc/keineschweine/server/sg_lobby.nim
@@ -0,0 +1,267 @@
+
+import
+  sockets, streams, tables, times, math, strutils, json, os, md5, 
+  sfml, sfml_vector, sfml_colors, 
+  streams_enh, input_helpers, zlib_helpers, client_helpers, sg_packets, sg_assets, sg_gui
+type
+  TClientSettings = object
+    resolution*: TVideoMode
+    offlineFile: string
+    dirserver: tuple[host: string, port: TPort]
+    website*: string
+var
+  clientSettings: TClientSettings
+  gui = newGuiContainer()
+  zonelist = newGuiContainer()
+  u_alias, u_passwd: PTextEntry
+  activeInput = 0
+  aliasText, passwdText: PText
+  fpsTimer: PButton
+  loginBtn: PButton
+  playBtn: PButton
+  keyClient = newKeyClient("lobby")
+  showZonelist = false
+  chatInput*: PTextEntry
+  messageArea*: PMessageArea
+  mySession*: ScLogin
+var
+  dirServer: PServer
+  zone*: PServer
+  activeServer: PServer
+  bConnected = false
+  outgoing = newStringStream("")
+  downloadProgress: PButton
+  connectionButtons: seq[PButton] #buttons that depend on connection to function
+
+template dispmessage(m: expr): stmt = 
+  messageArea.add(m)
+proc connectZone(host: string; port: TPort)
+proc connectToDirserv()
+
+proc writePkt[T](pid: PacketID; p: var T) =
+  if activeServer.isNil: return
+  activeServer.writePkt pid, p
+
+proc setConnected(state: bool) =
+  if state:
+    bConnected = true
+    for b in connectionButtons: enable(b)
+  else:
+    bConnected = false
+    for b in connectionButtons: disable(b)
+
+proc setActiveZone(ind: int; zone: ScZoneRecord) =
+  #hilight it or something
+  dispmessage("Selected " & zone.name)
+  connectZone(zone.ip, zone.port)
+  playBtn.enable()
+
+proc handleChat(serv: PServer; s: PStream) =
+  var msg = readScChat(s)
+  messageArea.add(msg)
+
+proc connectToDirserv() =
+  if dirServer.isNil:
+    dirServer = newServerConnection(clientSettings.dirserver.host, clientSettings.dirserver.port)
+    dirServer.handlers[HHello] = proc(serv: PServer; s: PStream) = 
+      let msg = readScHello(s)
+      dispMessage(msg.resp)
+      setConnected(true)
+    dirServer.handlers[HLogin] = proc(serv: PServer; s: PStream) =
+      mySession = readScLogin(s)
+      ##do something here
+    dirServer.handlers[HZonelist] = proc(serv: PServer; s: PStream) =
+      var 
+        info = readScZonelist(s)
+        zones = info.zones
+      if zones.len > 0:
+        zonelist.clearButtons()
+        var pos = vec2f(0.0, 0.0)
+        zonelist.newButton(
+          text = "Zonelist - "& info.network,
+          position = pos,
+          onClick = proc(b: PButton) =
+            dispmessage("Click on header"))
+        pos.y += 20
+        for i in 0..zones.len - 1:
+          var z = zones[i]
+          zonelist.newButton(
+            text = z.name, position = pos,
+            onClick = proc(b: PButton) = 
+              setActiveZone(i, z))
+          pos.y += 20
+        showZonelist = true
+    dirServer.handlers[HPoing] = proc(serv: PServer; s: PStream) = 
+      var ping = readPoing(s)
+      dispmessage("Ping: "& $ping.time)
+      ping.time = epochTime().float32
+      serv.writePkt HPoing, ping
+    dirServer.handlers[HChat] = handleChat
+    dirServer.handlers[HFileChallenge] = handleFileChallenge
+  var hello = newCsHello()
+  dirServer.writePkt HHello, hello
+  activeServer = dirServer
+
+
+proc zoneListReq() =
+  var pkt = newCsZonelist("sup")
+  writePkt HZonelist, pkt
+
+##key handlers
+keyClient.registerHandler(MouseMiddle, down, proc() = 
+  gui.setPosition(getMousePos()))
+
+keyClient.registerHandler(KeyO, down, proc() = 
+  if keyPressed(KeyRShift): echo(repr(outgoing)))
+keyClient.registerHandler(KeyTab, down, proc() =
+  activeInput = (activeInput + 1) mod 2) #does this work?
+keyClient.registerHandler(MouseLeft, down, proc() = 
+  let p = getMousePos()
+  gui.click(p)
+  if showZonelist: zonelist.click(p))
+var mptext = newText("", guiFont, 16)
+keyClient.registerHandler(MouseRight, down, proc() = 
+  let p = getMousePos()
+  mptext.setPosition(p)
+  mptext.setString("($1,$2)"%[$p.x.int,$p.y.int]))
+
+
+proc connectZone(host: string, port: TPort) =
+  echo "Connecting to zone at ", host, ':', port
+  if zone.isNil:
+    zone = newServerConnection(host, port)
+    zone.handlers[HFileChallenge] = handleFileChallenge
+    zone.handlers[HChallengeResult] = handleFileChallengeResult
+    zone.handlers[HFileTransfer] = handleFileTransfer
+    zone.handlers[HChat] = handleChat 
+  else:
+    zone.sock.connect(host, port)
+  var hello = newCsHello()
+  zone.writePkt HHello, hello
+  
+
+
+proc lobbyReady*() = 
+  keyClient.setActive()
+  gui.setActive(u_alias)
+
+proc tryConnect*(b: PButton) =
+  connectToDirserv()
+proc tryLogin*(b: PButton) =
+  var login = newCsLogin(
+    alias = u_alias.getText(),
+    passwd = u_passwd.getText())
+  writePkt HLogin, login
+proc tryTransition*(b: PButton) =
+  ##check if we're logged in
+  #<implementation censored by the church>
+  #var joinReq = newCsJ
+  zone.writePkt HZoneJoinReq, mySession
+  #var errors: seq[string] = @[]
+  #if loadSettings("", errors):
+  #  transition()
+  #else:
+  #  for e in errors: dispmessage(e)
+proc playOffline*(b: PButton) =
+  var errors: seq[string] = @[]
+  if loadSettingsFromFile(clientSettings.offlineFile, errors):
+    transition()
+  else:
+    dispmessage("Errors reading the file ("& clientSettings.offlineFile &"):")
+    for e in errors: dispmessage(e)
+
+proc getClientSettings*(): TClientSettings =
+  result = clientSettings
+
+proc lobbyInit*() =
+  var s = json.parseFile("./client_settings.json")
+  clientSettings.offlineFile = "data/"
+  clientSettings.offlineFile.add s["default-file"].str
+  let dirserv = s["directory-server"]
+  clientSettings.dirserver.host = dirserv["host"].str
+  clientSettings.dirserver.port = dirserv["port"].num.TPort
+  clientSettings.resolution.width = s["resolution"][0].num.cint
+  clientSettings.resolution.height= s["resolution"][1].num.cint
+  clientSettings.resolution.bitsPerPixel = s["resolution"][2].num.cint
+  clientSettings.website = s["website"].str
+  zonelist.setPosition(vec2f(200.0, 100.0))
+  connectionButtons = @[]
+  
+  downloadProgress = gui.newButton(
+    text = "", position = vec2f(10, 130), onClick = nil) 
+  downloadProgress.bg.setFillColor(color(34, 139, 34))
+  downloadProgress.bg.setSize(vec2f(0, 0))
+  
+  var pos = vec2f(10, 10)
+  u_alias = gui.newTextEntry(
+    if s.existsKey("alias"): s["alias"].str else: "alias", 
+    pos)
+  pos.y += 20
+  u_passwd = gui.newTextEntry("buzz", pos)
+  pos.y += 20
+  connectionButtons.add(gui.newButton(
+    text = "Login", 
+    position = pos,
+    onClick = tryLogin,
+    startEnabled = false))
+  pos.y += 20
+  fpsText.setPosition(pos)
+  
+  playBtn = gui.newButton(
+    text = "Play",
+    position = vec2f(680.0, 8.0),
+    onClick = tryTransition,
+    startEnabled = false)
+  gui.newButton(
+    text = "Play Offline",
+    position = vec2f(680.0, 28.0),
+    onClick = playOffline)
+  fpsTimer = gui.newButton(
+    text = "FPS: ",
+    position = vec2f(10.0, 70.0),
+    onClick = proc(b: PButton) = nil)
+  gui.newButton(
+    text = "Connect",
+    position = vec2f(10.0, 90.0),
+    onClick = tryConnect)
+  connectionButtons.add(gui.newButton(
+    text = "Test Chat",
+    position = vec2f(10.0, 110.0),
+    onClick = (proc(b: PButton) = 
+      var pkt = newCsChat(text = "ohai")
+      writePkt HChat, pkt),
+    startEnabled = false))
+  chatInput = gui.newTextEntry("...", vec2f(10.0, 575.0), proc() =
+    sendChat dirServer, chatInput.getText()
+    chatInput.clearText())
+  messageArea = gui.newMessageArea(vec2f(10.0, 575.0 - 20.0))
+  messageArea.sizeVisible = 25
+  gui.newButton(text = "Scrollback + 1", position = vec2f(185, 10), onClick = proc(b: PButton) =
+    messageArea.scrollBack += 1
+    update(messageArea))
+  gui.newButton(text = "Scrollback - 1", position = vec2f(185+160, 10), onClick = proc(b: PButton) = 
+    messageArea.scrollBack -= 1
+    update(messageArea))
+  gui.newButton(text = "Flood msg area", position = vec2f(185, 30), onClick = proc(b: PButton) =
+    for i in 0.. <30: 
+      dispMessage($i))
+
+var i = 0
+proc lobbyUpdate*(dt: float) = 
+  #let res = disp.poll()
+  gui.update(dt)
+  i = (i + 1) mod 60
+  if i == 0:
+    fpsTimer.setString("FPS: "& $round(1.0/dt))
+  if not pollServer(dirServer, 5) and bConnected:
+    setConnected(false)
+    echo("Lost connection")
+  discard pollServer(zone, 5)
+
+proc lobbyDraw*(window: PRenderWindow) =
+  window.clear(Black)
+  window.draw messageArea
+  window.draw mptext
+  window.draw gui
+  if showZonelist: window.draw zonelist
+  window.display()