2 The game has been threaded. Major changes have occurred.
3 Emp_update, emp_login, emp_tm, and emp_player have been merged.
4 Basically, there isn't anything else besides server. It's big.
5 60,000-lines of code big.
7 The lib directory now contains nine subdirectories:
18 The main directory contains five (code) directories:
25 The server has seven basic threads:
28 creates accept, killidle, and update scheduler.
29 sets signals, opens files.
31 opens a socket, binds, listens, and accepts new players.
32 creates a player thread for each new socket.
34 negotaties the player's login, and then interprets
35 the player's game commands.
37 eyeballs the logged-in players every sixty seconds and
38 closes the connections of those who have been idle for
39 longer than 15 minutes.
41 Sleeps until update is due to go off, then instructs all
42 player threads currently running commands to abort them.
43 It waits for a few seconds so that this can occur, and
44 then creates the update thread, and schedules the next
45 update. (This scheduler should produce single, accurate
46 updates instead of double-updates and delayed updates)
48 The standard update procedure. It runs at high priority
49 and performs no network i/o, so the game effectively hangs
50 while the update is in progress.
52 This thread and its interface provides a mechanism for
53 other threads to deschedule until either a a file descriptor
54 is read/write ready, or a particular amount of time has passed.
55 When the select thread actually runs, the whole process
56 blocks until the select system call returns. However,
57 select runs at the lowest possible priority so other
58 threads get to run to completion before the select gets
63 Unit and sector files are kept in-core for Your Viewing Pleasure.
64 (It was actually required in order to merge in emp_update)
65 This means the server will use significant memory for the larger
68 Per-player bigmap files have been merged into one EF_MAP file, with
69 each player getting one record. This is also kept in-core.
71 Estimated memory cost of a 64-player 256x256 world game with
72 each player having 100 land units, 100 planes, 100 ships, and
73 a bigmap comes to a little over eleven megabytes of space,
74 including the 700k text segment.
76 the "wai()" command doesn't work yet.
78 Implementation Notes: My Opportunity to Spout Empire Technical Jargon
80 Empire is now a miniature operating system, with all that entails.
81 Threads are not simple to use. I know the threads package
82 intimately, and I was confused several times -- probably because
83 the threads interface I provide isn't all that straightforward,
84 even though it seems like it. Hopefully a second iteration by
85 someone who knows what they're doing will be better.
87 I expect this will be much worse for everyone else who hasn't gone
88 through my experience. Bottom line for all you part-time hackers
89 out there: don't mess with the current process model, or you'll get
90 yourself into all kinds of trouble.
92 Thread scheduling and descheduling happens in the io_input and
93 io_output calls. The higher level interfaces in the player thread
94 to these are the getstarg/getstring and pr procedures. If your
95 process ever has to wait for input or output, it will block, allowing
96 other threads to run. Those other threads may well modify data
97 out from under you, so be prepared to have your shared in-memory
98 constructs (ships, planes, sectors, land units, etc) modified out
99 from under you whenever you do i/o.
101 There's a new player global context structure that is shared
102 amongst all the player threads. When a given thread starts
103 or restarts, it sets the global player variable to the appropriate
104 value. Thus, part of the logic of a "context switch" is the setting
105 of player. If you go and add calls to the lightweight process
106 system, you *must* be sure to set the player variable as the
107 io_output and io_input routines do. Otherwise, things will be
108 extremely confused. (I'm not very happy with this global
109 variable, but I didn't have the gumption to do anything more)
111 Most routines that used to return pointers to static space no
112 longer do so. Instead, you're expected to pass in a buffer which
113 will be filled up by the routine. This hit a *lot* of routines,
114 so check the new syntax before using an old and trusted routine
117 Any files that are loaded into core (like the sector, map, nation,
118 ship, plane, and land unit files) are shared between all the threads.
119 That's good news. If your thread modifies another player's nat_tgms
120 field, he'll see it next time through the command loop, without
121 anyone having to read anything from disk! Furthermore, he'll have
122 no delay in zeroing out that field, so there won't be the annoying
123 double telegram reports which were caused by the delay induced by
126 Unfortunately, modifications to entries to these mapped files must
127 be followed by the appropriate "write record" command (like putship,
128 putnat, etc) or else the changes won't be stored to disk permanently.
129 Update is the exception to this rule, because it writes all records
130 to disk using ef_flush when it's done. This is important, since
131 if and when the players learn how to coredump the server *and* they've
132 managed to build some object w/o their nation record having been
133 updated, they essentially get the item without paying for it.
135 There are two interfaces to the empire file code: the pointer
136 interface exemplified by np = getnatp(cnum), and the copy interface
137 shown by getsect(x, y, §)/putsect(§). Both still work fine.
138 However, you have to be careful when using the pointer interface
139 not to change things prematurely, because any changes to the pointer
140 actually change the data itself -- including putvar, etc. Some
141 commands use the copy interface now, change some variables, and
142 then decide to bail out of the command when something goes wrong.
143 Be careful if you decide to use pointers and then bail out early.
144 Even if *you* don't write the pointer to disk, other subsequent
145 activity probably *will*, resulting in a surprise for the players.
147 Each player thread gets 64k of stack space + more depending on the
148 size of WORLD_X*WORLD_Y. I hope that's enough. If not, we'll have
149 to remove the larger stack variables and move them into static space.
151 Adding new records to core-loaded (EFF_MEM) files is annoying now.
152 Instead of simply writing out a new record, you have to call
153 ef_extend(type, count) to enlarge the file by count records.
154 Additionally, any outstanding pointers you obtained from that
155 file are now invalid. This command results in a "close/open"
156 for the file, requiring the entire contents to be read in from
157 disk again. Luckily, the only instance I saw of this was the
158 "build" command, and my call to ef_extend does it in groups of