diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..ff30ec5
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,27 @@
+{
+ // Use IntelliSense to find out which attributes exist for C# debugging
+ // Use hover for the description of the existing attributes
+ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": ".NET Core Launch (console)",
+ "type": "coreclr",
+ "request": "launch",
+ "preLaunchTask": "build",
+ // If you have changed target frameworks, make sure to update the program path.
+ "program": "${workspaceFolder}/bin/Debug/netcoreapp3.1/SkinnerBox.dll",
+ "args": [],
+ "cwd": "${workspaceFolder}",
+ // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
+ "console": "internalConsole",
+ "stopAtEntry": false
+ },
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach",
+ "processId": "${command:pickProcess}"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..d8d64ba
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,42 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/SkinnerBox.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/SkinnerBox.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "${workspaceFolder}/SkinnerBox.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Entities/Entity.cs b/Entities/Entity.cs
new file mode 100644
index 0000000..310ec39
--- /dev/null
+++ b/Entities/Entity.cs
@@ -0,0 +1,76 @@
+using System.Drawing;
+using System.Numerics;
+using SlatedGameToolkit.Framework.Graphics.Render;
+using SlatedGameToolkit.Framework.Graphics.Textures;
+
+namespace SkinnerBox.Entities
+{
+ public abstract class Entity : IMesh, IPositionInterpolable
+ {
+ public RectangleMesh mesh;
+ public virtual float CenterX {
+ get {
+ return X + Width / 2f;
+ }
+ set {
+ X = value - Width / 2f;
+ }
+ }
+ public float X { get; set; }
+
+ public float Y { get; set; }
+
+ public float Width {
+ get {
+ return mesh.Width;
+ }
+
+ set {
+ mesh.Width = value;
+ }
+ }
+
+ public float Height {
+ get {
+ return mesh.Height;
+ }
+
+ set {
+ mesh.Height = value;
+ }
+ }
+
+ public virtual RectangleF HitBox
+ {
+ get {
+ return mesh.Bounds;
+ }
+ }
+
+ public Entity(ITexture texture)
+ {
+ this.mesh = new RectangleMesh(texture, Color.White);
+ }
+
+ public (Vector3, Vector2)[] Vertices => mesh.Vertices;
+
+ public uint[] Elements => mesh.Elements;
+
+ public ITexture Texture => mesh.Texture;
+
+ public Color Color {
+ get {
+ return this.mesh.Color;
+ }
+ set {
+ this.mesh.Color = value;
+ }
+ }
+
+ public virtual void InterpolatePosition(float delta)
+ {
+ mesh.X += delta * (X - mesh.X);
+ mesh.Y += delta * (Y - mesh.Y);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Entities/PacketEntity.cs b/Entities/PacketEntity.cs
new file mode 100644
index 0000000..e2b158f
--- /dev/null
+++ b/Entities/PacketEntity.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Numerics;
+using SlatedGameToolkit.Framework.Graphics.Render;
+using SlatedGameToolkit.Framework.Graphics.Textures;
+using SlatedGameToolkit.Framework.Utilities.Collections.Pooling;
+
+namespace SkinnerBox.Entities
+{
+ public class PacketEntity : Entity, IPositionInterpolable, IPoolable
+ {
+ public float velocity;
+ public PacketEntity(ITexture texture) : base(texture)
+ {
+ this.Width = 0.5f;
+ this.Height = 1f;
+ Reset();
+ }
+
+ public void Reset()
+ {
+ this.Y = Game.HEIGHT_UNITS;
+ this.mesh.Y = this.Y;
+ this.velocity = 0;
+ this.X = 0;
+ this.mesh.X = this.X;
+ }
+
+ public void Update(double delta) {
+ this.Y -= (float)(velocity * delta);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Entities/ServerEntity.cs b/Entities/ServerEntity.cs
new file mode 100644
index 0000000..f8d93f8
--- /dev/null
+++ b/Entities/ServerEntity.cs
@@ -0,0 +1,58 @@
+using System.Drawing;
+using SlatedGameToolkit.Framework.Graphics.Render;
+using SlatedGameToolkit.Framework.Graphics.Textures;
+using SlatedGameToolkit.Framework.Graphics.Window;
+
+namespace SkinnerBox.Entities
+{
+ public class ServerEntity : Entity
+ {
+ private readonly float length = 4/8f;
+ public float Speed { get; set; }
+ public override float CenterX {
+ get {
+ return base.X + (length * size) / 2f;
+ }
+
+ set {
+ base.X = value - (length * size) / 2f;
+ }
+ }
+ private int size;
+ public int Size {
+ get {
+ return size;
+ }
+
+ set {
+ if (this.size != value) {
+ this.size = value;
+ this.mesh.TextureBounds = new RectangleF(0, 0, size, 1);
+ this.Width = value * length;
+ }
+ }
+ }
+ public override RectangleF HitBox {
+ get {
+ RectangleF hitbox = base.HitBox;
+ hitbox.Width = hitbox.Width * size;
+ return hitbox;
+ }
+ }
+ public ServerEntity(Texture texture, float initialX, float Y) : base(texture)
+ {
+ this.X = (Game.WIDTH_UNITS - this.Width) / 2f;
+ this.Height = length;
+
+ Size = 1;
+
+ this.Speed = 2f;
+
+ CenterX = initialX;
+ mesh.X = X;
+ this.Y = Y;
+ mesh.Y = this.Y;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Entities/WarningEntity.cs b/Entities/WarningEntity.cs
new file mode 100644
index 0000000..8cfc0f5
--- /dev/null
+++ b/Entities/WarningEntity.cs
@@ -0,0 +1,38 @@
+using SkinnerBox.Utilities.Gameplay;
+using SlatedGameToolkit.Framework.Graphics.Textures;
+using SlatedGameToolkit.Framework.Utilities.Collections.Pooling;
+using System;
+using System.Drawing;
+
+namespace SkinnerBox.Entities
+{
+ public class WarningEntity : Entity, IPoolable
+ {
+ public float LifeTime { get; set; }
+ public TransitionValue aliveTime;
+
+ public WarningEntity(ITexture texture) : base(texture) {
+ this.Width = 2;
+ this.Height = 2;
+ Reset();
+ }
+ public void Reset()
+ {
+ LifeTime = 0;
+ X = 0 - Width;
+ mesh.X = X;
+ Y = Game.HEIGHT_UNITS - Height;
+ mesh.Y = Y;
+ aliveTime.HardSet(0);
+ this.Color = Color.Red;
+ }
+
+ public override void InterpolatePosition(float delta) {
+ aliveTime.InterpolatePosition(delta);
+ float prog = (aliveTime.Value / LifeTime);
+ if (prog > 1) prog = 1;
+ this.Color = Color.FromArgb((int)(byte.MaxValue * (1f - prog)), this.Color);
+ base.InterpolatePosition(delta);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Game.cs b/Game.cs
new file mode 100644
index 0000000..e196f8d
--- /dev/null
+++ b/Game.cs
@@ -0,0 +1,24 @@
+using System;
+using SkinnerBox.States.Gameplay;
+using SkinnerBox.States.Main;
+using SlatedGameToolkit.Framework;
+using SlatedGameToolkit.Framework.AssetSystem;
+using SlatedGameToolkit.Framework.Graphics;
+using SlatedGameToolkit.Framework.Graphics.Window;
+using SlatedGameToolkit.Framework.Loaders;
+
+namespace SkinnerBox
+{
+ class Game
+ {
+ public const int WIDTH_UNITS = 8;
+ public const int HEIGHT_UNITS = 8;
+ static void Main(string[] args)
+ {
+ GameEngine.targetFPS = 0;
+ GameEngine.UpdatesPerSecond = 20;
+ GameEngine.Ignite(new MenuState());
+ }
+
+ }
+}
diff --git a/SkinnerBox.csproj b/SkinnerBox.csproj
new file mode 100644
index 0000000..aa71130
--- /dev/null
+++ b/SkinnerBox.csproj
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+ Exe
+ netcoreapp3.1
+
+
+
diff --git a/States/Gameplay/GamePlayState.cs b/States/Gameplay/GamePlayState.cs
new file mode 100644
index 0000000..515843f
--- /dev/null
+++ b/States/Gameplay/GamePlayState.cs
@@ -0,0 +1,205 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Numerics;
+using SDL2;
+using SkinnerBox.Entities;
+using SlatedGameToolkit.Framework.AssetSystem;
+using SlatedGameToolkit.Framework.Graphics.Render;
+using SlatedGameToolkit.Framework.Graphics.Textures;
+using SlatedGameToolkit.Framework.Graphics.Window;
+using SlatedGameToolkit.Framework.Input.Devices;
+using SlatedGameToolkit.Framework.StateSystem;
+using SlatedGameToolkit.Framework.StateSystem.States;
+using SlatedGameToolkit.Framework.Utilities.Collections.Pooling;
+
+namespace SkinnerBox.States.Gameplay
+{
+ public class GamePlayState : IState
+ {
+ private MeshBatchRenderer renderer;
+ private AssetManager assets;
+ private StateManager stateManager;
+ private Random random;
+
+ //Cursor information
+ private float widthFactor, heightFactor;
+ private float leftXPos; //Last left click position
+
+
+ //Entities
+ private ServerEntity server;
+
+ private ObjectPool warningPool;
+ private List activeWarnings = new List();
+
+ private ObjectPool packetPool;
+ private List activePackets = new List();
+ private SpawnInfo packetSpawnInfo;
+
+ public GamePlayState(MeshBatchRenderer renderer, AssetManager asset)
+ {
+ this.assets = asset;
+ this.renderer = renderer;
+ packetPool = new ObjectPool(CreatePacket);
+ warningPool = new ObjectPool(createWarning);
+ }
+
+ public bool Activate()
+ {
+ Keyboard.keyboardUpdateEvent += KeyInputListener;
+ Mouse.mouseUpdateEvent += MouseInput;
+ leftXPos = 0.5f * Game.WIDTH_UNITS;
+ server = new ServerEntity((Texture)assets["serverunit.png"], leftXPos, 0.1f);
+ random = new Random();
+
+ packetSpawnInfo = new SpawnInfo(2, 1, (float)(random.NextDouble() * Game.WIDTH_UNITS), 1f, 0.2f);
+ return true;
+ }
+
+ public PacketEntity CreatePacket() {
+ return new PacketEntity((Texture)assets["packet.png"]);
+ }
+
+ public WarningEntity createWarning() {
+ return new WarningEntity((Texture)assets["warning.png"]);
+ }
+
+ public bool Deactivate()
+ {
+ Keyboard.keyboardUpdateEvent -= KeyInputListener;
+ Mouse.mouseUpdateEvent -= MouseInput;
+ return true;
+ }
+
+ public void Deinitialize()
+ {
+
+ }
+
+ public string getName()
+ {
+ return "GamePlayState";
+ }
+
+ public void Initialize(StateManager manager)
+ {
+ this.stateManager = manager;
+ int vw, vh, vx, vy;
+ WindowContextsManager.CurrentGL.GetViewport(out vx, out vy, out vw, out vh);
+ CalculateScaleFactors(vw, vh);
+
+ }
+
+ public void Render(double delta)
+ {
+ renderer.Begin(Matrix4x4.Identity, delta);
+ foreach (WarningEntity warn in activeWarnings)
+ {
+ renderer.Draw(warn);
+ }
+ foreach (PacketEntity packet in activePackets)
+ {
+ renderer.Draw(packet);
+ }
+ renderer.Draw(server);
+ renderer.End();
+ }
+
+ public void Update(double timeStep)
+ {
+ #region ServerUpdate
+ if (Mouse.LeftButtonPressed) {
+ leftXPos = widthFactor * Mouse.X;
+ }
+
+ if (leftXPos < server.CenterX)
+ {
+ server.CenterX -= ((float)timeStep * server.Speed);
+ if (server.CenterX < leftXPos) server.CenterX = leftXPos;
+ } else if (leftXPos > server.CenterX)
+ {
+ server.CenterX += ((float)timeStep * server.Speed);
+ if (server.X > leftXPos) server.CenterX = leftXPos;
+ }
+ #endregion
+ #region PacketUpdate
+ packetSpawnInfo.timeElapsed += (float) timeStep;
+ if (packetSpawnInfo.timeElapsed >= packetSpawnInfo.period) {
+ packetSpawnInfo.timeElapsed = 0;
+ //do spawning
+ for(int i = 0; i < packetSpawnInfo.perSpawn; i++) {
+ PacketEntity packet = packetPool.Retrieve();
+ packet.CenterX = packetSpawnInfo.batchLocation;
+ packet.Y = i * packet.Height + packetSpawnInfo.distanceBetween + Game.HEIGHT_UNITS + packetSpawnInfo.speed * (2/3f);
+ packet.velocity = packetSpawnInfo.speed;
+ packet.Color = Color.Blue;
+ activePackets.Add(packet);
+ }
+
+ //Spawn Warning
+ WarningEntity warning = warningPool.Retrieve();
+ warning.CenterX = packetSpawnInfo.batchLocation;
+ warning.LifeTime = packetSpawnInfo.period * (2/3f);
+ warning.Y = Game.HEIGHT_UNITS - warning.Height;
+ activeWarnings.Add(warning);
+
+ //Prepare next batch
+ packetSpawnInfo.batchLocation = (float)(random.NextDouble() * Game.WIDTH_UNITS);
+ }
+
+ for (int i = 0; i < activePackets.Count; i++)
+ {
+ PacketEntity packet = activePackets[i];
+ packet.Update(timeStep);
+ if (packet.HitBox.IntersectsWith(server.HitBox) && packet.velocity > 0) {
+ packet.velocity *= -2f;
+ packet.Color = Color.Cyan;
+ }
+ if (packet.Y <= 0 - packet.Height) {
+ packetPool.Release(packet);
+ activePackets.RemoveAt(i);
+ i--;
+ continue;
+ }
+ if (packet.Y >= Game.HEIGHT_UNITS && packet.velocity < 0) {
+ packetPool.Release(packet);
+ activePackets.RemoveAt(i);
+ i--;
+ }
+ }
+ #endregion
+ #region WarningCleanup
+ for (int i = 0; i < activeWarnings.Count; i++)
+ {
+ WarningEntity warn = activeWarnings[i];
+ warn.aliveTime.Value += (float) timeStep;
+ if (warn.aliveTime.Value >= warn.LifeTime) {
+ warningPool.Release(warn);
+ activeWarnings.RemoveAt(i);
+ i--;
+ }
+ }
+ #endregion
+ }
+
+ public void KeyInputListener(SDL.SDL_Keycode keycode, bool down) {
+ }
+
+ public void MouseInput(bool leftDown, bool rightDown, bool middle, int x, int y, int scrollX, int scrollY) {
+
+ }
+
+ public void WindowResize(int width, int height) {
+ WindowContextsManager.CurrentWindowContext.GetDrawableDimensions();
+ int vw, vh, vx, vy;
+ WindowContextsManager.CurrentGL.GetViewport(out vx, out vy, out vw, out vh);
+ CalculateScaleFactors(vw, vh);
+ }
+
+ private void CalculateScaleFactors(float width, float height) {
+ this.widthFactor = Game.WIDTH_UNITS * (1f / width);
+ this.heightFactor = Game.HEIGHT_UNITS * (1f / height);
+ }
+ }
+}
\ No newline at end of file
diff --git a/States/Gameplay/SpawnInfo.cs b/States/Gameplay/SpawnInfo.cs
new file mode 100644
index 0000000..336dae0
--- /dev/null
+++ b/States/Gameplay/SpawnInfo.cs
@@ -0,0 +1,21 @@
+namespace SkinnerBox.States.Gameplay
+{
+ public struct SpawnInfo
+ {
+ public float timeElapsed;
+ public int period;
+ public int perSpawn;
+ public float batchLocation;
+ public float distanceBetween;
+ public float speed;
+
+ public SpawnInfo(int period, int perSpawn, float location, float speed, float distance) {
+ timeElapsed = 0;
+ this.period = period;
+ this.perSpawn = perSpawn;
+ this.batchLocation = location;
+ this.distanceBetween = distance;
+ this.speed = speed;
+ }
+ }
+}
\ No newline at end of file
diff --git a/States/Main/MenuState.cs b/States/Main/MenuState.cs
new file mode 100644
index 0000000..ad1f610
--- /dev/null
+++ b/States/Main/MenuState.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Drawing;
+using System.Numerics;
+using SDL2;
+using SkinnerBox.States.Gameplay;
+using SlatedGameToolkit.Framework.AssetSystem;
+using SlatedGameToolkit.Framework.Graphics;
+using SlatedGameToolkit.Framework.Graphics.Render;
+using SlatedGameToolkit.Framework.Graphics.Text;
+using SlatedGameToolkit.Framework.Graphics.Textures;
+using SlatedGameToolkit.Framework.Graphics.Window;
+using SlatedGameToolkit.Framework.Input.Devices;
+using SlatedGameToolkit.Framework.Loaders;
+using SlatedGameToolkit.Framework.StateSystem;
+using SlatedGameToolkit.Framework.StateSystem.States;
+
+namespace SkinnerBox.States.Main
+{
+ public class MenuState : IState
+ {
+ private StateManager manager;
+ WindowContext context;
+ AssetManager assets;
+ Camera2D camera;
+ MeshBatchRenderer renderer;
+ BitmapFont titleFont, boldFont;
+ RectangleMesh serverUnit;
+
+ public bool Activate()
+ {
+ Keyboard.keyboardUpdateEvent += KeyInput;
+ return true;
+ }
+
+ public bool Deactivate()
+ {
+ Keyboard.keyboardUpdateEvent -= KeyInput;
+ return true;
+ }
+
+ public void Deinitialize()
+ {
+ this.renderer.Dispose();
+ this.assets.UnloadAll();
+ }
+
+ public string getName()
+ {
+ return "Main";
+ }
+
+ public void Initialize(StateManager manager)
+ {
+ this.manager = manager;
+ this.manager.backgroundColour = Color.White;
+ this.context = new WindowContext("You Are the Website", width: 640, height: 640, options: SDL.SDL_WindowFlags.SDL_WINDOW_HIDDEN); // Creates the window context.
+ this.assets = new AssetManager();
+ this.assets.DefaultPathModifier = (p) => "resources/" + p;
+ this.assets.Loaders.TryAdd("png", TextureLoader.Load2DTexture);
+ this.camera = new Camera2D(Game.WIDTH_UNITS, Game.HEIGHT_UNITS);
+ this.camera.Position = new Vector2(Game.WIDTH_UNITS / 2, Game.HEIGHT_UNITS / 2);
+ this.camera.MoveTo = this.camera.Position;
+ this.renderer = new MeshBatchRenderer(camera);
+
+ //Add additional states
+ manager.AddState(new GamePlayState(renderer, this.assets));
+
+ //Load assets
+ this.assets.Load("serverunit.png");
+ this.assets.Load("packet.png");
+ this.assets.Load("warning.png");
+
+ //Set up title TTF
+ this.titleFont = new BitmapFont("resources/BigShouldersDisplay-Regular.ttf", textureSizes: 512);
+ this.titleFont.PixelHeight = 120;
+ this.titleFont.PixelsPerUnitHeight = 80;
+ this.titleFont.PixelsPerUnitWidth = 80;
+ this.titleFont.PrepareCharacterGroup("You Are the Website.".ToCharArray());
+ this.titleFont.PixelHeight = 40;
+ this.titleFont.PrepareCharacterGroup("By: Reslate".ToCharArray());
+
+ //Set up bold TTF
+ boldFont = new BitmapFont("resources/BigShouldersDisplay-Black.ttf", textureSizes: 512);
+ boldFont.PixelHeight = 60;
+ boldFont.PixelsPerUnitWidth = 80;
+ boldFont.PixelsPerUnitHeight = 80;
+ boldFont.PrepareCharacterGroup("Press any key to start...".ToCharArray());
+
+ //Set up icon
+ Texture serverUnitTex = (Texture)assets["serverunit.png"];
+ serverUnitTex.SetNearestFilter(true, true);
+ this.serverUnit = new RectangleMesh(new RectangleF(Game.WIDTH_UNITS/2 - 0.75f, Game.HEIGHT_UNITS * 0.75f - 0.75f, 1.5f, 1.5f), serverUnitTex, Color.White);
+
+ this.context.Shown = true;
+ }
+
+ public void Render(double delta)
+ {
+ renderer.Begin(Matrix4x4.Identity, delta);
+ this.titleFont.PixelHeight = 120;
+ this.titleFont.WriteLine(renderer, 0.02f, 0.02f, "You Are the Website.", Color.Black);
+
+ this.titleFont.PixelHeight = 40;
+ this.titleFont.WriteLine(renderer, 0, 1.2f, "By: Reslate", Color.Gray);
+
+ renderer.Draw(serverUnit);
+
+ this.boldFont.WriteLine(renderer, 1.15f, Game.HEIGHT_UNITS / 2, "Press any key to start...", Color.Black);
+ renderer.End();
+ }
+
+ public void Update(double timeStep)
+ {
+ }
+
+ public void KeyInput(SDL.SDL_Keycode keys, bool pressed)
+ {
+ if (pressed)
+ {
+ manager.ChangeState("GamePlayState");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Utilities/TransitionValue.cs b/Utilities/TransitionValue.cs
new file mode 100644
index 0000000..68a1e5d
--- /dev/null
+++ b/Utilities/TransitionValue.cs
@@ -0,0 +1,31 @@
+using SlatedGameToolkit.Framework.Graphics.Render;
+
+namespace SkinnerBox.Utilities.Gameplay
+{
+ public struct TransitionValue : IPositionInterpolable
+ {
+ private float current;
+ private float value;
+
+ public float Value
+ {
+ get
+ {
+ return current;
+ }
+ set
+ {
+ this.value = value;
+ }
+ }
+ public void InterpolatePosition(float delta)
+ {
+ this.current += (value - current) * delta;
+ }
+
+ public void HardSet(float value) {
+ current = value;
+ this.value = value;
+ }
+ }
+}
\ No newline at end of file
diff --git a/resources/BigShouldersDisplay-Black.ttf b/resources/BigShouldersDisplay-Black.ttf
new file mode 100644
index 0000000..7047626
Binary files /dev/null and b/resources/BigShouldersDisplay-Black.ttf differ
diff --git a/resources/BigShouldersDisplay-Regular.ttf b/resources/BigShouldersDisplay-Regular.ttf
new file mode 100644
index 0000000..708fff5
Binary files /dev/null and b/resources/BigShouldersDisplay-Regular.ttf differ
diff --git a/resources/packet.png b/resources/packet.png
new file mode 100644
index 0000000..d86f0d6
Binary files /dev/null and b/resources/packet.png differ
diff --git a/resources/serverunit.png b/resources/serverunit.png
new file mode 100644
index 0000000..01a4ad8
Binary files /dev/null and b/resources/serverunit.png differ
diff --git a/resources/warning.png b/resources/warning.png
new file mode 100644
index 0000000..36cd499
Binary files /dev/null and b/resources/warning.png differ