\section{Netværk}

\begin{intro}

I det følgende vil implementeringen af spillets netværk blive beskrevet. Beskeder i spillet vil først blive gennemgået, og derefter følger afsnit om den grundliggende netværkshåndtering i spillet.

\end{intro}



Som udgangspunkt, skal klient og server opfylde kravspecifikationen. Dvs at det skal være muligt at kommunikere over UDP såvel som TCP. Netværket er implementeret vha. netværks-biblioteket SDL\_net \cite{sdlnet}. SDL\_net er dels valgt fordi projektet i forvejen benytter sig af SDL, og dels fordi SDL\_net er et simpelt og let bibliotek.



Server og klient deler en række krav i kravspecifikationen:

\begin{itemize}

    \item De skal begge kunne sende og modtage data via UDP

    \item De skal begge kunne sende og modtage data via TCP

    \item De skal begge kunne oprette og nedlægge TCP-forbindelser

\end{itemize}

Ydermere skal de begge kunne sende og modtage data af samme karakter. Det kan f.eks. være information om spilleres placering, spilleres energi osv.

Det lægger op til at server og klient deler en relativ stor del af netværks-koden. Dette er implementeret ved at lade server, såvel som klient, være klasser der nedarver fra en fælles superklasse \texttt{NetworkController}.

Der bruges forskellige protokoller med hver deres tilgang til at sende data. UDP er datagram (pakke) baseret, og TCP er socket-baseret\cite{networking}. Det betyder at der skal implementeres to forskellige måder at sende beskeder hen over netværket på. For at lette behandlingen af beskeder er hver besked i spillet implementeret som en klasse.

\subsection{Beskeder}

Da alle beskeder deler visse funktionaliteter, såsom at de skal kunne afsendes, nedarver alle besked-klasser fra en fælles superklasse \texttt{NetMessage}. Beskeder i spillet oprettes via et såkaldt ``Pluggable Factory''\\cite{plug}\cite{plugorg}. Foredelen ved et Pluggable Factory fremfor et normalt Factory er, at hvor et normalt Factory kan producere et fastlagt antal objekter, kan et Pluggable Factory producere et variabelt antal objekter der bliver fastsat compile-time. 

Skulle beskeder i spillet være implementeret som et normalt Factory ville det i grove træk se ud som vist i kodeliste \ref{lst:factory}. Hver besked har en unik id, i dette tilfælde et tal. Når beskedFactory bliver kaldt med et tal, finder den frem til den tilhørende besked-klasse, og returnerer en ny instans af denne. Antallet af mulige besked-klasser er fast i metoden, så hvis man senere ønsker at udvide spillet med endnu en klasse, vil man skulle udvide denne metode.



\subsubsection{Pluggable Factory}

I et PluggableFactory, benytter man sig af et map over ``Maker''\-objekter. Et Maker-objekt er et simpelt Factory, der kan producere et objekt af én bestemt type. Hver af disse Maker-objekter er i map'et associeret med en unik id. Når man ønsker et objekt af en bestemt type, slår man op i mappet og finder et Maker-objekt med den tilhørende id. Derefter bruger man Maker-objektet, til at producere det konkrete besked-objekt. Dette er vist i kodeliste \ref{lst:pluggablefactory}. Maker-objektet kan virke som et unødigt mellemled, men da map'et sammenholder id'er med konkrete objekter, er det nødvendigt at indføre et led. Hvis man i stedet havde lagt besked-objekter i map'et ville man altid få returneret det samme objekt. Da der godt kan optræde flere beskeder af samme type ad gangen i spillet er dette uønsket.

\begin{lstlisting}[caption=Et Factory, label=lst:factory]

beskedFactory ( id )

    hvis(id == 1)

        returner nyt besked1-objekt;



    ellers hvis ( id == 2)

        returner nyt besked2-objekt;    

    .

    .

    .

\end{lstlisting}



\begin{lstlisting}[caption=Et PluggableFactory, label=lst:pluggablefactory]

pluggableBeskedFactory ( id )

    makerObjekt =  beskedMap( id )

    returner makerObjekt.lavObjekt()

\end{lstlisting}



\subsubsection{NetMessage}

Alle beskeder nedarver fra klassen \texttt{NetMessage}. \texttt{NetMessage} indeholder en række funktioner alle beskeder har til fælles.

\begin{description}

    \item[\texttt{getSize}] Returnere størrelsen af pakken i bytes. Dette er f.eks. nødvendigt for at kunne bestemme størrelsen af pakken når beskeden sendes over UDP.

    \item[\texttt{serializeTo}] Tager beskeden og skriver den til buffer i et format som beskeden senere kan gendannes fra. Dette bruges når beskeden skal sendes over netværket.

    \item[\texttt{serializeFrom}] Læser en given mængde data fra en buffer, og indlæser en besked fra denne. Dette bruges når en besked modtages over netværket.

    \item[\texttt{think}] Denne abstrakte metode bliver kaldt på subklasser af \texttt{NetMessage} når beskeden er nået frem. Think-metoden er ``hjernen''\ i beskeden.

\end{description}



Derudover indeholder \texttt{NetMessage} 4 felter:

\begin{description}

    \item[to] Modtager af beskeden.

    \item[from] Afsender af beskeden.

    \item[type] Et tal der angiver hvilken type besked, der er tale om.

    \item[time] Tidspunktet hvor hændelsen fandt sted.

\end{description}



%\fixme{Når TestMessage er klar skal den smides ind i listen, nogen skal finde ud af om TestMessageMaker også skal vises}

%En C++ implementation af beskeden \texttt{TestMessage} samt dens maker-klasse \texttt{TestMessageMaker}, kan ses på kodelisten \ref{lst:testmessage} og \ref{lst:testmessagemaker}.



%\begin{lstlisting}[caption=TestMessage klassen, label=lst:testmessage]

    

%\end{lstlisting}



%\begin{lstlisting}[caption=TestMessageMaker klassen, label=lst:testmessagemaker]



%\end{lstlisting}



\subsubsection{PlayerKilled}



\texttt{PlayerKilled} beskeden nedarver fra \texttt{SingleIntValuedMessage}, som nedarver fra \texttt{NetMessage}. I forhold til \texttt{NetMessage} indeholder \texttt{PlayerKilled} et spiller id.



Beskeden sendes fra serveren til alle klienter når en spiller dør. Beskeden sletter den relevante spillers skib, som vist i liste \ref{lst:playerkilledthink}.



\begin{center}

\begin{minipage}[t]{0.8\textwidth}

\begin{flushleft}

\begin{lstlisting}[caption=Pseudo-kode for think i PlayerKilled, label=lst:playerkilledthink]

find spilleren med det givne id



hvis spilleren findes

    dræb spillerens skib

\end{lstlisting}

\end{flushleft}

\end{minipage}

\end{center}



\subsubsection{ShipUpdate}



\texttt{ShipUpdate} beskeden opdaterer informationen omkring et skib. Dette inkluderer dets placering og orientering i spillet, samt mængden af ammunition og brændstof skibet har tilbage. Beskeden kan sendes både fra en klient eller en server. Hvis den kommer fra en klient, er det klientens eget skib som skal opdateres på serveren. Hvis den kommer fra serveren, er det oftest andre spilleres skibe der skal opdateres, men ved kollision har serveren brug for at fortælle klienten at den skal ændre retning.



\texttt{ShipUpdate} er ikke implementeret i skrivende stund. Det ville være trivielt at implementere, men indtil det er muligt at modtage beskeder ansås det ikke som vigtigt at implementere flere beskeder. Det ansås dog som vigtigt at beskrive klassen, da den ville være en central del af netværksfunktionaliteten når/hvis den blev implementeret.



\begin{center}

\begin{minipage}[t]{0.8\textwidth}

\begin{flushleft}

\begin{lstlisting}[caption=Pseudo-kode for think i LocalPlayer, label=lst:localplayerthink]

find spilleren med det givne spillerid



hvis spilleren ikke findes

    returner



skib = spillerens skib



overskriv skibets position med det fra beskeden

overskriv skibets hastighed med det fra beskeden

overskriv skibets acceleration med det fra beskeden

overskriv skibets orientering med det fra beskeden

\end{lstlisting}

\end{flushleft}

\end{minipage}

\end{center}



\subsection{NetworkController}


\texttt{NetworkController} håndterer oprettelse og nedlæggelse af alle forbindelser imellem klient og server. Serveren har brug for at kunne kontrollere flere forbindelser til flere forskellige klienter. \texttt{NetworkController} arbejder derfor med en liste af forbindelser. Klienten har kun brug for en en enkelt udadgående forbindelse til serveren, men da der ikke er noget i vejen for blot at bruge en liste med et en enkelt forbindelse i, ændrer dette ikke på implementeringen.



TCP er en forbindelses-orienteret, socketbaseret protokol. UDP er en forbindelses-løs datagrambaseret protokol. Man kan derfor ikke tale om en egentligt UDP-forbindelse. Det er dog vigtigt for server såvel som klient at holde styr på om man har mistet forbindelsen med den anden ende. Dette er håndteret ved at lave en forbindelses-klasse(\texttt{Connection}). Klassen indeholder en TCP-forbindelse(socket), et forbindelses-id (\texttt{ConnectionID}) samt en IP-adresse. IP-adressen bruges når man skal sendes data via UDP, og TCP-forbindelsen bruges, når der skal sendes data via TCP. Hvis TCP-forbindelsen på noget tidspunkt fejler, eller bliver nedlagt, slettes forbindelses-objektet. På denne måde bruges TCP-forbindelsen til at kompensere for manglen på forbindelses-orientering i UDP.



Ind- og udgående data er begge implementeret som køer. Når man ønsker at sende f.eks. UDP-data, skubbes den først på den udgående UDP-kø, der herefter tømmes af \texttt{NetworkController}. Der findes ligeledes en kø for udadgående TCP-data. Indgående UDP- og TCP-data håndteres begge via den samme kø, da protokollen en besked leveres med ikke har nogen betydning for spillet.





\subsubsection{Oprettelse og nedlæggelse af forbindelser}

Metoderne \texttt{addConnection} og \texttt{removeConnection} bruges til at oprette og nedlægge forbindelser. Når en forbindelse oprettes, indsættes den i listen af forbindelser. Når den nedlægges, fjernes den fra listen. Pseudo-koden for de to metoder kan ses i listing \ref{lst:addConnection} og \ref{lst:removeConnection}.



\begin{lstlisting}[caption=addConnection-metoden, label=lst:addConnection]

    opret TCP-forbindelse med SDL_net

    opret et nyt Connection-objekt

    indsæt objektet i forbindelses-listen

\end{lstlisting}



\begin{lstlisting}[caption=removeConnection-metoden, label=lst:removeConnection]

    find forbindelsen i forbindelses-listen

    nedlæg TCP-socket med SDL_net

    slet forbindelses-objektet fra forbindelses-listen

\end{lstlisting}



\subsubsection{Køer i NetworkController}

\texttt{NetworkController} indeholder 3 køer:

\begin{description}

    \item[\texttt{messageInQueue}] der er en kø af indkommende beskeder.

    \item[\texttt{UDPOutQueue}] er en kø af udgående beskeder der skal sendes via UDP.

    \item[\texttt{TCPOutQueue}] er en kø af udgående beskeder der skal sendes via TCP.

\end{description}

Når man vil sende beskeder foregår det v.ha. metoderne \texttt{TCPSendMessage} og \texttt{UDPSendMessage}. Disse metoder tager en besked som argument, og putter den på den respektive kø. \texttt{NetworkController} indeholder metoden \texttt{readMessages}, der kaldes med jævne mellemrum. Denne metode gennemløber alle forbindelser i forbindelses-listen, og indlæser evt indkommende data. Denne data laves v.ha. \texttt{MessageMakerBase} om til beskeder, og puttes på den indkommende besked-kø. Til sidst bliver \texttt{think} metoden på alle beskeder i besked-køen kaldt, således at alle beskeder bliver udført.

Pseudo-koden for metoden \texttt{flush}, der sender de udgående køer findes i kode-liste \ref{lst:flush}. Pseudo-koden for metoden \texttt{readMessages} findes i kode-liste \ref{lst:readMessages}.





\begin{lstlisting}[caption=flush-metoden fra NetworkController, label=lst:flush]

sålænge der er beskeder i TCP-køen

    serialiser beskeden

    send beskeden vha SDL_net

    fjern beskeden fra TCP-køen



sålænge der er beskeder i UDP-køen

    serialiser beskeden

    send beskeden vha SDL_net

    fjern beskeden fra UDP-køen

\end{lstlisting}





\begin{lstlisting}[caption=readMessages-metoden fra NetworkController, label=lst:readMessages]

for hver forbindelse i forbindelses-listen

    sålænge der er data på TCP-forbindelsen

         opret ny besked ud fra data

         skub beskeden på besked-køen



sålænge der er data på UDP-forbindelsen

    opret ny besked ud fra data

    skub beskeden på besked-køen

    

for hver besked i besked-køen

    kald think-metoden på beskeden

    fjern beskeden fra køen

\end{lstlisting} 