File: code-notes.txt

package info (click to toggle)
netpanzer 0.8.7%2Bds-5
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 34,448 kB
  • sloc: cpp: 45,217; sh: 278; objc: 259; python: 102; xml: 30; perl: 30; makefile: 15
file content (364 lines) | stat: -rw-r--r-- 15,941 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
Notes about NetPanzer code.

1. Initialization

Code starts in src/NetPanzer/Core/main.cpp netpanzer_main.

ScriptManager is initialized (creates a lua state), and registers the Palette
bindings.

global_engine_state is created at this point.

Ignore signals on non windows systems if DEBUG is not defined.

Initializes SDL:
    * timers only.
    * no parachute.
    * enables unicode support.

Initializes PhysFS:
    * sets write directory to the "user dir"/."netpanzer", "user dir" is $HOME
      on non windows, C:\Documents And Settings\<username> on Windows.
    * creates the write directory if needed.
    * will EXIT if can't create or use the ".netpanzer" directory.
    * search path:
        - write dir.
        - base dir (`pwd`).
        - adds any zip file that is found at the current search path.
        - NP_DATADIR if defined.
        - in Mac OS X adds the Resource dir of the bundle.
        - on non Windows, handles the attached "datadir=" at end of binary.

Open log files, named "server" or "netpanzer" depends if user used -d option.

On Windows if dedicated server, allocate a console.

Random number generator inialized here, use time as seed.

Creates the PID file if requested.

Creates the BaseGameManager, depends on "-d" option used:
    * PlayerGameManager
        - sets all its poiters to null
    * DedicatedGameManager
        - sets all its pointers to null
        - create mutex
        - initialize Console

Initialize the game manager
    * creates "config" directory (note: on the define write dir)
    * create the game config, uses the passed parameter as config file, if used,
      gameconfig can be acceses from this point.
    * creates the sound manager (handled in each concrete BaseGameManager)
    * initializes video, only PlayerGameManager creates a SDLVideo and sets the
      video mode (GameManager::setVideoMode).
    * creates global_game_state.
    * creates UnitProfileInterface and loads profiles. Need to move.
    * ResourceManager loads default flags (sets all flags to black). Can move?
    * calculates some values for Physics.
    * loads images for weapons. Need to move.
    * loads images for powerups. Need to move.
    * initializes the game console (the messages that player or game prints on
      screen). Need to move.
    * initialies ServerConnectDaemon with the max plauers configuration. Need to
      move.
    * sets the NetworkState status to "server" state.
    * resets all network stats.
    * initializes input devices:
        - PlayerGameManager initializes mouse:
            # loads images in "pics/cursors".
            # sets default cursor ("default.png").
            # sets the clicktimer to 150ms.
        - DedicagtedGameManager sets ConsoleInterface::setStdoutPipe to true.

Handles a quick connect (-c <server> command line parameter), it sets
gameconfig->serverConnect to the host and gameconfig->quickConnect to true.

If the option for masterserver was passed, updates the
gameconfig->masterservers (overrides config file).

If the port option was used (server port default is 3030) updates
gameconfig->serverport (overrides config file).

At this point sets global_engine_state->game_manager to the just created and
initialized game manager, if some error happened on initialization, will never
get to this point.

Launch the game, two completely different paths here, in concrete classes:
    * PlayerGameManager:
        - creates all Views.
        - sets the "MainView" as visible (shows main menu).
    * DedicatedGameManager:
        - initializes MessageRouter.
        - NetworkServer clears the client list and creates the listening socket.
            *will fail* if can't create socket, nobody would be able to connect.
        - GameControlRulesDaemon is set as dedicated server, state to loading
          map.
        - gameconfig->hostorjoin is host.
        - disable creation of particles.
        - if the server is public and there are configured masterservers,
            creates the infosocket and the heartbeat.
        - creates a ServerConsole (is a different thread), which will receive
            the server admin commands.

Initialization is finish, do the main loop while it returns true.

1.1 Game configuration initialization (done in GameConfig constructor)

Similar game settings are grouped on standard containers. The constructor
initializes ALL the configuration variables with default values. The player name
is always initialized as as "Player<random number>".

The settings variable pointers is added to the containers, then loads the
configuration from the config file (might be passed as command line parameter).

2. Game Main Loop

DedicatedGameManager:
    * run heartbeat.
    * do default main loop.

PlayerGameManager:
    * if first run, and is quick connect, joins game.
    * check heartbeat.
    * handles SDL events (quits if received quit message).
    * do default main loop.

default main loop (BaseGameManager):
    * initializes frame timer
    * checks game inputs:
        - DedicatedGameManager:
            # checks commands input in console.
        - PlayerGameManager:
            # handle key presses.
            # handle mouse multi-click timer.
            # handle mouse events.
            # manage scroll of view.
    * draw graphics (only PlayerGameManager):
        - lock screen.
        - draw all visible views.
        - draw mouse.
        - unlock scren.
        - flip screen.
    * run logic (called simLoop):
        - deleted disconnected players on server, should move to server only
            code.
        - handle network events, always neede, should move out of logic to loop.
        - runs GameControlRulesDaemon, right know it handles client connection
            map loading and check for map rules in server.
        - if we are server, run ServerConnectDaemon (manages connecting clients
            on server).
        - updates network statistics.
        - run units simulation (tank movement, shoots, etc).
        - run projectiles (flying weapons) simulation.
        - run objective simulation (capture of outposts).
        - run powerups simulation (generate powerup, check if player get one).
        - run path generation.
        - run physics simulation (calculates displacement by wind).
        - run particles simulation (2 kinds?).
        - sends unsent network data in client and server.
        - run bot simulation

3. Subsystems

3.1 Graphics

To better understand the current graphics state is better to know the original
game graphics approach. This doesn't include views or sprites.

3.1.1 Original Graphics Approach

The graphics code was located on:
    * src/NetPanzer/System/SDLVideo.*
    * src/Netpanzer/Classes/ScreenSurface.*
    * src/Lib/2D/*.*

All the graphics was handled in 256 colors, paletted mode.

Palettes was loaded from "act" files, an easy file format, made by an array red,
green and blue colors for each of the 256 colors of the palette.

There was 2 different palettes, the "menu" palette, used on the main menu views,
and the game palette used in the game. The palettes was called "netpmenu" and
"netp".

To optain specific colors for drawing, there was a class to store the final
colors "Color", it had named variables for colors. Each color stored the 8 bit
index of the palette with the desired color.

Each time the palette was loaded, the colors was initialized with the palette
color that was more similar to the wanted rgb one.

To simulate transparency and lighting effects, some tables was pregenerated
to obtain the new color after applying of the effect. For example, if we wanted to
brighten a color, by some value, we would do a table lookup with the old color
and the brighten value, obtaining the new color. The same method was used for
transparency effects.

The all the image data was handled in 2 classes, Surface and PackedSurface.

Each Surface contained one or more frames. The image data was stored as a big
chunk of memory. Image blitting was done by copy the memory in blocks to the new
location. Surfaces can be rotated and scaled. If transparency was used on this
kind, it was a pixel by pixel copy, if the color 0 was used, the pixel was
skipped, hence doing full transparency of the pixel.

PackedSurface was similar to normal Surfaces, as it had frames and similar
method names. It had 2 chunks of memory, one with the pixel data, other with the
pixel indexes. It is a form of RLE encoded data. The pointer of the first table
tells how many bytes of memory to skip, and how many bytes to copy to the
screen, bytes of memory being pixels in thescreen, as it was a 8 bit paletted
mode.

There was a dedicated BMP loading function on Surface, and a PAK loading
function for the PackedSurfaces.

Text drawing on surfaces was done by loading a file with the font data. A value
of 0 would skip the pixel, any other value would set the color that was passed
to the string blitting method.

SDLVideo had all the methods needed to work with the SDL_Surface of the video
device (as returned by SDL_SetVideoMode, or the background surface if double
buffer was not enabled in the SDL_Surface).

ScreenSurface was a facade to allow the normal Surface and PacketSurface
blitting functions to blit directly on the video surface. Because it was 8 color
paletted mode the relationship was 1 on 1, after video surface was locked,
normal memcpy would work the same as Surface blitting on the video surface.

Blitting to the video:
    * lock the back (hidden) surface, it could be the same as video surface, but
      in practice, used to be a dedicated surface for doing double buffering.
      The locking operation made the raw pixel data addresable.
    * draw/copy pixels to video memory (--> the backbuffer).
    * unlock the back surface (pixel might not be addresable now).
    * copy to the video surface and update the visual.

3.1.2 Current Graphics approach.

Surface has a container for SDL_Surface, a container is needed to hold
different frames. The SDL_Surfaces are created as 32 bit surface.

PackedSurface does not exists any more, full transparency of pixels uses
SDL_RLEACCEL and SDL_SRCCOLORKEY. Transparency of the full image is handled by
SDL_SRCALPHA (no tables lookup).

The palette is not loaded from files anymore, is stored in the code, there is
only one palette (netp). Colors are initialized using a Lua script.

The font is integrated in the code (BuiltinFont.cpp).

All the blitting operations uses SDL for its blitting. The images has to be
prepared beforehand to blit in the way it was intended, like setting the alpha
and/or the color key.

The images are loaded from PNG files. The code to load PNG was taken from
SDL_image library (IMG_png.c). The libpng library is added to the source code.
It is possible to load multiframed images, has to add the size parameters when
loading the image, the loaded will autodetect the frames. The PAK files has been
converted to PNG files.

The shadows are created as a mask of the images. Blitting shadows has to enable
the SDL_SRCALPHA flag to do transparency.

The current approach is slower than the previous, try to show 100 tanks on
screen and see the framerate to drop to slugish values. It needs optimization.

Other possibility would be to use OpenGL for drawing.

3.2 Views system

Let the mess begin. All views related stuff is in src/NetPanzer/Views:
    * Components: Some components for use in views, View and Desktop here.
    * Game: Views used in game.
    * MainMenu: don't need to explain.

Desktop is the container for all the other views, is like the "Desktop" of the
operating systems.

View is a internal window, it can have "Component"s.

Views are added to the desktop and never "deleted". Views has a name and are
searched by name. Views can be hidden or shown.

Views are activated when added to the Desktop or when the mouse enters the view.
If the mouse leaves the View, they are deactivated. This causes that one of the
components (cInputField) lose its focus when the mouse exits its view, so when
players are typing their player name, or the address of some server, the mouse
must stay inside the view.

The old View system had a Surface created each time it wanted to draw, using the
original memory of the destination Surface, clipped to the View size. It drew
directly on the pixel memory of the destination Surface, in fact, the
ScreenSurface.

The modified View system, doesn't create any surface, it draws (blits mostly)
on the ScreenSurface always, no new Surfaces are created for this drawing.

It is difficult to follow the Views, some of them works as a multi view, and
holds a string with the name of the real view.

Views with focus will receive mouse events (only), and they must take care of
read the keyboard events if they need them. The interesting case here is the
GameView, it calls WorldInputCmdProcessor to handle the mouse/keyboard events.
Input will be explained later.

3.2.1 View Components

There was 2 kind of Components, one handled in each View internally other
handled as real "Components". When I took the code, it seems that there was some
changes going on to convert from the internal View components to external
Components, the developers found the mess and decided to rewrite the view
system, called it Panels or something like that, but was really never used. I
deleted that code and did more work to convert the components to Components.

The current components can use some kind of pre-rendering, if nothing changes
just blit the pre-rendered image. All the components has a name and may have a
custom code.

The current components are:
    * Button: can have a text label, 1 to 3 images and border. The text can have
        3 different colors for each state (normal, hover, pressed) and so does
        the border. Border colors split between top left and bottom right
        colors.
        Buttons doesn't have a callback function, but you can create your own
        Button subclass and override actionPerformed.
        When the Button is crated, its component name is set to
        "Button.<component_name_argument>".
    * CheckBox: can have a label, the text color is always white.
        CheckBoxes can have a StateChangedCallback object, will be called if
        state changes.
    * Choice: this is a ComboBox known in other languages. It has a list of
        items that will be shown.
        Choices can have a StateChangedCallback too. The colors are fixed.
    * InfoBar: used in game (top bar) to show game information.
    * Label: can have some text to show, foreground, background color and
        shadow.
        Labels has a component name "Label.<something>".
        Labels uses the prerendering way.
    * MiniMap: used in game to draw the minimap.
    * cInputField: Uses old component method, allows to enter a line of text.

The current in-game views are:
    * GameView: Draws everything game related, also call the in-game key/mouse
        handler.
    * AreYouSureExitView, AreYouSureResignView, DisconnectedView: those are very
        simple views, its name says what they do.
    * CodeStatsView: Used for in-game developer information, shows things like
        network stats (packets sent/received), pathfinding stats, unit stats...
    * GameTemplateView: Base class for some other game related views, not for
        GameView and it is not a c++ template.
    * HelpScrollView: Shows the help.
    * LibView: some some in-game developer information, allows to change some
        of the engine configuration (mainly for tests).
    * LoadingView: the window that is seen when the game is connecting to a
        server and loading the resources as map, etc...
    * MiniMapView: has a MiniMap component.
    * RankView: shows the current player ranking.
    * VehicleSelectionView: is the window to select which tank to create in the
        outposts.

----- Thats it for now -----