ADDED   src/ServerEntity.h
Index: src/ServerEntity.h
==================================================================
--- /dev/null
+++ src/ServerEntity.h
@@ -0,0 +1,9 @@
+#import <ObjFW/ObjFW.h>
+
+// server side version of "entity" type
+@interface ServerEntity: OFObject
+@property (nonatomic) bool spawned;
+@property (nonatomic) int spawnsecs;
+
++ (instancetype)entity;
+@end

ADDED   src/ServerEntity.m
Index: src/ServerEntity.m
==================================================================
--- /dev/null
+++ src/ServerEntity.m
@@ -0,0 +1,8 @@
+#import "ServerEntity.h"
+
+@implementation ServerEntity
++ (instancetype)entity
+{
+	return [[self alloc] init];
+}
+@end

Index: src/meson.build
==================================================================
--- src/meson.build
+++ src/meson.build
@@ -16,10 +16,11 @@
     'OFString+Cube.mm',
     'PersistentEntity.m',
     'Projectile.m',
     'ResolverResult.mm',
     'ResolverThread.mm',
+    'ServerEntity.m',
     'ServerInfo.mm',
     'Variable.mm',
     'clients.mm',
     'clientextras.mm',
     'clientgame.mm',
@@ -67,10 +68,11 @@
   win_subsystem: 'windows')
 
 executable('server',
   [
     'Client.mm',
+    'ServerEntity.m',
     'server.mm',
     'serverms.mm',
     'serverutil.mm',
     'tools.mm',
   ],

Index: src/server.mm
==================================================================
--- src/server.mm
+++ src/server.mm
@@ -3,39 +3,34 @@
 
 #include "cube.h"
 
 #import "Client.h"
 #import "Entity.h"
+#import "ServerEntity.h"
 
 enum { ST_EMPTY, ST_LOCAL, ST_TCPIP };
 
 static OFMutableArray<Client *> *clients;
 
 int maxclients = 8;
 static OFString *smapname;
 
-// server side version of "entity" type
-struct server_entity {
-	bool spawned;
-	int spawnsecs;
-};
-
-vector<server_entity> sents;
+static OFMutableArray<ServerEntity *> *sents;
 
 // true when map has changed and waiting for clients to send item
 bool notgotitems = true;
 int mode = 0;
 
 // hack: called from savegame code, only works in SP
 void
 restoreserverstate(OFArray<Entity *> *ents)
 {
-	loopv(sents)
-	{
-		sents[i].spawned = ents[i].spawned;
-		sents[i].spawnsecs = 0;
-	}
+	[sents enumerateObjectsUsingBlock:^(
+	    ServerEntity *e, size_t i, bool *stop) {
+		e.spawned = ents[i].spawned;
+		e.spawnsecs = 0;
+	}];
 }
 
 int interm = 0, minremain = 0, mapend = 0;
 bool mapreload = false;
 
@@ -114,19 +109,19 @@
 }
 
 void
 resetitems()
 {
-	sents.setsize(0);
+	[sents removeAllObjects];
 	notgotitems = true;
 }
 
 void
 pickup(uint i, int sec, int sender) // server side item pickup, acknowledge
                                     // first client that gets it
 {
-	if (i >= (uint)sents.length())
+	if (i >= (uint)sents.count)
 		return;
 	if (sents[i].spawned) {
 		sents[i].spawned = false;
 		sents[i].spawnsecs = sec;
 		send2(true, sender, SV_ITEMACC, i);
@@ -228,13 +223,13 @@
 
 		case SV_ITEMLIST: {
 			int n;
 			while ((n = getint(p)) != -1)
 				if (notgotitems) {
-					server_entity se = { false, 0 };
-					while (sents.length() <= n)
-						sents.add(se);
+					while (sents.count <= n)
+						[sents addObject:[ServerEntity
+						                     entity]];
 					sents[n].spawned = true;
 				}
 			notgotitems = false;
 			break;
 		}
@@ -302,11 +297,11 @@
 send_welcome(int n)
 {
 	ENetPacket *packet =
 	    enet_packet_create(NULL, MAXTRANS, ENET_PACKET_FLAG_RELIABLE);
 	uchar *start = packet->data;
-	uchar *p = start + 2;
+	__block uchar *p = start + 2;
 	putint(p, SV_INITS2C);
 	putint(p, n);
 	putint(p, PROTOCOL_VERSION);
 	putint(p, *smapname.UTF8String);
 	sendstring(serverpassword, p);
@@ -314,11 +309,15 @@
 	if (smapname.length > 0) {
 		putint(p, SV_MAPCHANGE);
 		sendstring(smapname, p);
 		putint(p, mode);
 		putint(p, SV_ITEMLIST);
-		loopv(sents) if (sents[i].spawned) putint(p, i);
+		[sents enumerateObjectsUsingBlock:^(
+		    ServerEntity *e, size_t i, bool *stop) {
+			if (e.spawned)
+				putint(p, i);
+		}];
 		putint(p, -1);
 	}
 	*(ushort *)start = ENET_HOST_TO_NET_16(p - start);
 	enet_packet_resize(packet, p - start);
 	send(n, packet);
@@ -400,19 +399,19 @@
 void
 serverslice(int seconds,
     unsigned int timeout) // main server update, called from cube main loop in
                           // sp, or dedicated server loop
 {
-	loopv(sents) // spawn entities when timer reached
-	{
-		if (sents[i].spawnsecs &&
-		    (sents[i].spawnsecs -= seconds - lastsec) <= 0) {
-			sents[i].spawnsecs = 0;
-			sents[i].spawned = true;
+	// spawn entities when timer reached
+	[sents enumerateObjectsUsingBlock:^(
+	    ServerEntity *e, size_t i, bool *stop) {
+		if (e.spawnsecs && (e.spawnsecs -= seconds - lastsec) <= 0) {
+			e.spawnsecs = 0;
+			e.spawned = true;
 			send2(true, -1, SV_ITEMSPAWN, i);
 		}
-	}
+	}];
 
 	lastsec = seconds;
 
 	if ((mode > 1 || (mode == 0 && nonlocalclients)) &&
 	    seconds > mapend - minremain * 60)
@@ -532,10 +531,11 @@
 initserver(bool dedicated, int uprate, OFString *sdesc, OFString *ip,
     OFString *master, OFString *passwd, int maxcl)
 {
 	serverpassword = passwd;
 	maxclients = maxcl;
+	sents = [[OFMutableArray alloc] init];
 	servermsinit(master ? master : @"wouter.fov120.com/cube/masterserver/",
 	    sdesc, dedicated);
 
 	if ((isdedicated = dedicated)) {
 		ENetAddress address = { ENET_HOST_ANY, CUBE_SERVER_PORT };