From ae64a4fe099bf329d4cbc8b199255f446af6f435 Mon Sep 17 00:00:00 2001 From: Yodeler <51685082+Superyodeler@users.noreply.github.com> Date: Sat, 2 Sep 2023 21:52:25 -0400 Subject: [PATCH 1/9] Separates the project into a Blocktest project handling the graphics and a shared folder handling the simulation logic and will also be used by the server. This commit doesn't include multiplayer, it's just the initial split of the code. Co-authored-by: Mark Suckerberg Co-authored-by: Imaginos16 <77556824+Imaginos16@users.noreply.github.com> Co-authored-by: Zeta --- Blocktest/Blocktest.csproj | 13 +- Blocktest/BlocktestGame.cs | 5 +- Blocktest/Code/Block System/BlockSprites.cs | 52 ++++++++ .../Code/Block System/BlockSpritesManager.cs | 31 +++++ Blocktest/Code/Block System/TilemapSprites.cs | 38 ++++++ Blocktest/Code/Globals.cs | 18 +-- Blocktest/Code/Misc/FrameCounter.cs | 36 ++++++ Blocktest/Code/Scenes/GameScene.cs | 59 ++++++---- Blocktest/GlobalUsings.cs | 3 +- Blocktest/packages.lock.json | 6 + DedicatedServer/DedicatedServer.csproj | 10 ++ DedicatedServer/Program.cs | 2 + .../Code/Block System/BlockManagerShared.cs | 24 ++-- .../Code/Block System/BlockShared.cs | 37 +----- .../Code/Block System/TilemapShared.cs | 111 +++++++----------- {Blocktest => Shared}/Code/Blocks/Asphalt.cs | 4 +- {Blocktest => Shared}/Code/Blocks/Brick.cs | 4 +- {Blocktest => Shared}/Code/Blocks/Concrete.cs | 4 +- {Blocktest => Shared}/Code/Blocks/Dirt.cs | 4 +- {Blocktest => Shared}/Code/Blocks/Glass.cs | 10 +- .../Code/Blocks/GlassPane.cs | 6 +- {Blocktest => Shared}/Code/Blocks/Grass.cs | 4 +- .../Code/Blocks/LargeStoneBrick.cs | 6 +- {Blocktest => Shared}/Code/Blocks/Log.cs | 4 +- {Blocktest => Shared}/Code/Blocks/Pykrete.cs | 4 +- .../Code/Blocks/SmoothMetal.cs | 4 +- {Blocktest => Shared}/Code/Blocks/Stone.cs | 4 +- .../Code/Blocks/StoneBrick.cs | 4 +- .../Code/Blocks/StonePathBrick.cs | 4 +- {Blocktest => Shared}/Code/Blocks/Wood.cs | 4 +- .../Code/Blocks/WoodPanel.cs | 4 +- {Blocktest => Shared}/Code/BuildSystem.cs | 19 +-- {Blocktest => Shared}/Code/Math.cs | 4 +- Shared/GlobalUsings.cs | 1 + Shared/Globals.cs | 29 +++++ Shared/Shared.csproj | 9 ++ 36 files changed, 374 insertions(+), 207 deletions(-) create mode 100644 Blocktest/Code/Block System/BlockSprites.cs create mode 100644 Blocktest/Code/Block System/BlockSpritesManager.cs create mode 100644 Blocktest/Code/Block System/TilemapSprites.cs create mode 100644 Blocktest/Code/Misc/FrameCounter.cs create mode 100644 DedicatedServer/DedicatedServer.csproj create mode 100644 DedicatedServer/Program.cs rename Blocktest/Code/Block System/BlockManager.cs => Shared/Code/Block System/BlockManagerShared.cs (81%) rename Blocktest/Code/Block System/Block.cs => Shared/Code/Block System/BlockShared.cs (57%) rename Blocktest/Code/Block System/Tilemap.cs => Shared/Code/Block System/TilemapShared.cs (66%) rename {Blocktest => Shared}/Code/Blocks/Asphalt.cs (76%) rename {Blocktest => Shared}/Code/Blocks/Brick.cs (76%) rename {Blocktest => Shared}/Code/Blocks/Concrete.cs (76%) rename {Blocktest => Shared}/Code/Blocks/Dirt.cs (76%) rename {Blocktest => Shared}/Code/Blocks/Glass.cs (58%) rename {Blocktest => Shared}/Code/Blocks/GlassPane.cs (70%) rename {Blocktest => Shared}/Code/Blocks/Grass.cs (76%) rename {Blocktest => Shared}/Code/Blocks/LargeStoneBrick.cs (66%) rename {Blocktest => Shared}/Code/Blocks/Log.cs (77%) rename {Blocktest => Shared}/Code/Blocks/Pykrete.cs (76%) rename {Blocktest => Shared}/Code/Blocks/SmoothMetal.cs (75%) rename {Blocktest => Shared}/Code/Blocks/Stone.cs (76%) rename {Blocktest => Shared}/Code/Blocks/StoneBrick.cs (75%) rename {Blocktest => Shared}/Code/Blocks/StonePathBrick.cs (75%) rename {Blocktest => Shared}/Code/Blocks/Wood.cs (76%) rename {Blocktest => Shared}/Code/Blocks/WoodPanel.cs (76%) rename {Blocktest => Shared}/Code/BuildSystem.cs (83%) rename {Blocktest => Shared}/Code/Math.cs (98%) create mode 100644 Shared/GlobalUsings.cs create mode 100644 Shared/Globals.cs create mode 100644 Shared/Shared.csproj diff --git a/Blocktest/Blocktest.csproj b/Blocktest/Blocktest.csproj index 9d0ab65..3fd825e 100644 --- a/Blocktest/Blocktest.csproj +++ b/Blocktest/Blocktest.csproj @@ -11,12 +11,12 @@ Icon.ico - - + + - - + + true @@ -24,7 +24,10 @@ - + + + + diff --git a/Blocktest/BlocktestGame.cs b/Blocktest/BlocktestGame.cs index 7e08bf9..ab46833 100644 --- a/Blocktest/BlocktestGame.cs +++ b/Blocktest/BlocktestGame.cs @@ -9,6 +9,7 @@ public class BlocktestGame : Game private GraphicsDeviceManager _graphics; private Scene? _currentScene; + /// public BlocktestGame() { @@ -19,7 +20,7 @@ public BlocktestGame() /// protected override void Initialize() { - BlockManager.Initialize(); + BlockManagerShared.Initialize(); base.Initialize(); } @@ -27,7 +28,7 @@ protected override void Initialize() { protected override void LoadContent() { Drawable.ContentManager = Content; - BlockManager.LoadBlockSprites(Content); + BlockSpritesManager.LoadBlockSprites(Content); _currentScene = new GameScene(this); } diff --git a/Blocktest/Code/Block System/BlockSprites.cs b/Blocktest/Code/Block System/BlockSprites.cs new file mode 100644 index 0000000..8ce65f0 --- /dev/null +++ b/Blocktest/Code/Block System/BlockSprites.cs @@ -0,0 +1,52 @@ +using Blocktest.Rendering; + +namespace Blocktest +{ + /// + /// Handles sprites for blocks. + /// + public class BlockSprites + { + /// Shared block info + public BlockShared blockShared; + + /// The block's sprite. + public Drawable blockSprite; + + /// The sprite sheet used for smoothing the block. + public SpriteSheet spriteSheet; + + /* METHODS */ + + public BlockSprites(BlockShared newBlockShared, ContentManager content) + { + blockShared = newBlockShared; + LoadSprite(content); + } + + /// + /// Called when the block is created by the block sprites manager. + /// + /// + /// DO NOT FORGET TO CALL THE BASE METHOD IF YOU OVERRIDE THIS. + /// + public virtual void LoadSprite(ContentManager content) + { + string path = @"Graphics\Blocks\" + blockShared.blockName.ToLower().Replace(" ", ""); + try { + blockSprite = new Drawable(path, new Rectangle(1, 1, 10, 10)); //this might need to be expanded in the future in case we decide to make use of the full 12x12 tiles on our spritesheets + if (!blockShared.blockSmoothing) { + return; + } + spriteSheet = new SpriteSheet(path, 4, 4, 1); + if (spriteSheet.OrderedSprites.Length <= 1) { + Console.WriteLine("Block " + this + " is marked as smoothable, but a sprite sheet could not be found at " + path + "!"); + } + } + catch (ContentLoadException) { + blockSprite = new Drawable(@"Graphics\Blocks\error"); + Console.WriteLine("Block " + this + " does not have an icon at " + path + "!"); + } + } + } +} diff --git a/Blocktest/Code/Block System/BlockSpritesManager.cs b/Blocktest/Code/Block System/BlockSpritesManager.cs new file mode 100644 index 0000000..ab2526e --- /dev/null +++ b/Blocktest/Code/Block System/BlockSpritesManager.cs @@ -0,0 +1,31 @@ +using Blocktest.Rendering; + +namespace Blocktest +{ + public class BlockSpritesManager + { + /// Array which stores all blocksprites instances for referencing as if they were globals. + private static BlockSprites[] allBlocksSprites; + /// Array which stores all blocksprites instances for referencing as if they were globals. + public static BlockSprites[] AllBlocksSprites { get => allBlocksSprites; private set => allBlocksSprites = value; } + + /// List used to store the names of blocks. The indexes are the corresponding block's ID. + private static string[] blockSpriteNames; + /// List used to store the names of blocks. The indexes are the corresponding block's ID. + public static string[] BlockSpriteNames { get => blockSpriteNames; private set => blockSpriteNames = value; } + + public static void LoadBlockSprites(ContentManager content) + { + AllBlocksSprites = new BlockSprites[BlockManagerShared.AllBlocks.Length]; + BlockSpriteNames = new string[BlockManagerShared.AllBlocks.Length]; + + for(int i = 0; i < BlockManagerShared.AllBlocks.Length; i++) + { + BlockShared block = BlockManagerShared.AllBlocks[i]; + BlockSprites newBlockSprites = new(block, content); + BlockSpriteNames[block.blockID] = block.blockName; + AllBlocksSprites[block.blockID] = newBlockSprites; + } + } + } +} diff --git a/Blocktest/Code/Block System/TilemapSprites.cs b/Blocktest/Code/Block System/TilemapSprites.cs new file mode 100644 index 0000000..8dc0e78 --- /dev/null +++ b/Blocktest/Code/Block System/TilemapSprites.cs @@ -0,0 +1,38 @@ +using Blocktest.Rendering; +namespace Blocktest +{ + /// + /// Handles drawing . + /// + public class TilemapSprites + { + public TilemapShared tilemap; + + /// + /// Creates a . + /// + /// The width of the tilemap in tiles. + /// The height of the tilemap in tiles. + public TilemapSprites(TilemapShared newTilemap) + { + tilemap = newTilemap; + } + + /// + /// Called from the main draw loop, draws each tile in the tilemap. + /// + /// + /// This can almost definitely be optimized, but I'm focused on getting a decent version out + /// quickly so the codebase split causes fewer issues for others. + /// + /// The spritebatch to draw the tilemap tiles' sprite on. + public void Draw(SpriteBatch spriteBatch) + { + foreach (TileShared tile in tilemap.allTiles) { + BlockSprites blockSprites = BlockSpritesManager.AllBlocksSprites[tile.SourceBlock.blockID]; + Drawable sprite = blockSprites.spriteSheet.OrderedSprites[tile.bitmask]; + spriteBatch.Draw(sprite.Texture, new Vector2(tile.rectangle.X, tile.rectangle.Y), sprite.Bounds, tile.color); + } + } + } +} diff --git a/Blocktest/Code/Globals.cs b/Blocktest/Code/Globals.cs index 853f769..4dcfcb7 100644 --- a/Blocktest/Code/Globals.cs +++ b/Blocktest/Code/Globals.cs @@ -4,24 +4,14 @@ public static class Globals { /// Tilemap for foreground objects. - private static Tilemap foregroundTilemap; + private static TilemapSprites foregroundTilemapSprites; /// Tilemap for foreground objects. - public static Tilemap ForegroundTilemap { get => foregroundTilemap; set => foregroundTilemap = value; } + public static TilemapSprites ForegroundTilemapSprites { get => foregroundTilemapSprites; set => foregroundTilemapSprites = value; } /// Tilemap for background (non-dense) objects. - private static Tilemap backgroundTilemap; + private static TilemapSprites backgroundTilemapSprites; /// Tilemap for background (non-dense) objects. - public static Tilemap BackgroundTilemap { get => backgroundTilemap; set => backgroundTilemap = value; } - - /// The maximum world size. (Width) - public static readonly int maxX = 255; - /// The maximum world size. (Height) - public static readonly int maxY = 255; - - /// The size of the grid the game is played on. - public static readonly Vector2Int gridSize = new(8, 8); - - + public static TilemapSprites BackgroundTilemapSprites { get => backgroundTilemapSprites; set => backgroundTilemapSprites = value; } } } diff --git a/Blocktest/Code/Misc/FrameCounter.cs b/Blocktest/Code/Misc/FrameCounter.cs new file mode 100644 index 0000000..ffbb845 --- /dev/null +++ b/Blocktest/Code/Misc/FrameCounter.cs @@ -0,0 +1,36 @@ +using System.Linq; + +namespace Blocktest +{ + public class FrameCounter + { + public long TotalFrames { get; private set; } + public float TotalSeconds { get; private set; } + public float AverageFramesPerSecond { get; private set; } + public float CurrentFramesPerSecond { get; private set; } + + public const int MaximumSamples = 100; + + private Queue _sampleBuffer = new(); + + public void Update(float deltaTime) + { + CurrentFramesPerSecond = 1.0f / deltaTime; + + _sampleBuffer.Enqueue(CurrentFramesPerSecond); + + if (_sampleBuffer.Count > MaximumSamples) + { + _sampleBuffer.Dequeue(); + AverageFramesPerSecond = _sampleBuffer.Average(i => i); + } + else + { + AverageFramesPerSecond = CurrentFramesPerSecond; + } + + TotalFrames++; + TotalSeconds += deltaTime; + } + } +} \ No newline at end of file diff --git a/Blocktest/Code/Scenes/GameScene.cs b/Blocktest/Code/Scenes/GameScene.cs index fc80263..b9788ed 100644 --- a/Blocktest/Code/Scenes/GameScene.cs +++ b/Blocktest/Code/Scenes/GameScene.cs @@ -4,6 +4,8 @@ namespace Blocktest.Scenes; public class GameScene : Scene { private readonly BlocktestGame _game; private readonly SpriteBatch _spriteBatch; + private FrameCounter _frameCounter = new FrameCounter(); + private readonly SpriteFont _spriteFont; bool latch = false; //latch for button pressing private bool latchBlockSelect = false; //same but for block selection @@ -37,7 +39,7 @@ public void Update(GameTime gameTime) { else if (latchBlockSelect == false) { blockSelected++; - if (blockSelected >= BlockManager.AllBlocks.Length) + if (blockSelected >= BlockManagerShared.AllBlocks.Length) { blockSelected = 0; } @@ -50,13 +52,13 @@ public void Update(GameTime gameTime) { { if(currentState.LeftButton == ButtonState.Pressed) { - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[blockSelected], true, - new Vector2Int(MathHelper.Clamp(currentState.X / Globals.gridSize.X, 0, Globals.maxX), - MathHelper.Clamp(currentState.Y / Globals.gridSize.Y, 0, Globals.maxY))); + BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[blockSelected], true, + new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), + MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY))); } else if (currentState.RightButton == ButtonState.Pressed) { - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[blockSelected], false, - new Vector2Int(MathHelper.Clamp(currentState.X / Globals.gridSize.X, 0, Globals.maxX), - MathHelper.Clamp(currentState.Y / Globals.gridSize.Y, 0, Globals.maxY))); + BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[blockSelected], false, + new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), + MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY))); } } else @@ -64,12 +66,12 @@ public void Update(GameTime gameTime) { if(currentState.LeftButton == ButtonState.Pressed) { BuildSystem.BreakBlockCell( true, - new Vector2Int(MathHelper.Clamp(currentState.X / Globals.gridSize.X, 0, Globals.maxX), - MathHelper.Clamp(currentState.Y / Globals.gridSize.Y, 0, Globals.maxY))); + new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), + MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY))); } else if (currentState.RightButton == ButtonState.Pressed) { BuildSystem.BreakBlockCell( false, - new Vector2Int(MathHelper.Clamp(currentState.X / Globals.gridSize.X, 0, Globals.maxX), - MathHelper.Clamp(currentState.Y / Globals.gridSize.Y, 0, Globals.maxY))); + new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), + MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY))); } } @@ -79,8 +81,17 @@ public void Draw(GameTime gameTime, GraphicsDevice graphicsDevice) { graphicsDevice.Clear(Color.CornflowerBlue); _spriteBatch.Begin(); - Globals.BackgroundTilemap.Draw(_spriteBatch); - Globals.ForegroundTilemap.Draw(_spriteBatch); + Globals.BackgroundTilemapSprites.Draw(_spriteBatch); + Globals.ForegroundTilemapSprites.Draw(_spriteBatch); + + var deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; + + _frameCounter.Update(deltaTime); + + String fps = string.Format("FPS: {0}", _frameCounter.AverageFramesPerSecond); + + Console.WriteLine(fps); + _spriteBatch.End(); } @@ -88,18 +99,20 @@ public GameScene(BlocktestGame game) { _spriteBatch = new SpriteBatch(game.GraphicsDevice); _game = game; - Globals.BackgroundTilemap = new Tilemap(Globals.maxX, Globals.maxY); - Globals.ForegroundTilemap = new Tilemap(Globals.maxX, Globals.maxY); + GlobalsShared.BackgroundTilemap = new TilemapShared(GlobalsShared.maxX, GlobalsShared.maxY); + GlobalsShared.ForegroundTilemap = new TilemapShared(GlobalsShared.maxX, GlobalsShared.maxY); + Globals.BackgroundTilemapSprites = new(GlobalsShared.BackgroundTilemap); + Globals.ForegroundTilemapSprites = new(GlobalsShared.ForegroundTilemap); - for (int i = 0; i < Globals.maxX; i++) { - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[2], true, new Vector2Int(i, 5)); - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(i, 4)); - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(i, 3)); - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(i, 2)); - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(i, 1)); - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[1], true, new Vector2Int(i, 0)); + for (int i = 0; i < GlobalsShared.maxX; i++) { + BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[2], true, new Vector2Int(i, 5)); + BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[0], true, new Vector2Int(i, 4)); + BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[0], true, new Vector2Int(i, 3)); + BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[0], true, new Vector2Int(i, 2)); + BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[0], true, new Vector2Int(i, 1)); + BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[1], true, new Vector2Int(i, 0)); } - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(20, 20)); + BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[0], true, new Vector2Int(20, 20)); } } \ No newline at end of file diff --git a/Blocktest/GlobalUsings.cs b/Blocktest/GlobalUsings.cs index 7f7a095..3b66368 100644 --- a/Blocktest/GlobalUsings.cs +++ b/Blocktest/GlobalUsings.cs @@ -4,4 +4,5 @@ global using System.Collections.Generic; global using Microsoft.Xna.Framework; global using Microsoft.Xna.Framework.Content; -global using Microsoft.Xna.Framework.Graphics; \ No newline at end of file +global using Microsoft.Xna.Framework.Graphics; +global using Shared; \ No newline at end of file diff --git a/Blocktest/packages.lock.json b/Blocktest/packages.lock.json index c14bb39..beb8aa6 100644 --- a/Blocktest/packages.lock.json +++ b/Blocktest/packages.lock.json @@ -19,6 +19,12 @@ "requested": "[2.2.*, )", "resolved": "2.2.0", "contentHash": "u06nYzGcXCBcnF7cRe8Xa0KxBxGx8grhujZmb3PUiMVbds8d/I6qJ+waGn0IeC7Tdwmt0P6l3v7MqdYog5rJQg==" + }, + "shared": { + "type": "Project", + "dependencies": { + "MonoGame.Framework.DesktopGL": "[3.8.1.303, )" + } } } } diff --git a/DedicatedServer/DedicatedServer.csproj b/DedicatedServer/DedicatedServer.csproj new file mode 100644 index 0000000..f02677b --- /dev/null +++ b/DedicatedServer/DedicatedServer.csproj @@ -0,0 +1,10 @@ + + + + Exe + net7.0 + enable + enable + + + diff --git a/DedicatedServer/Program.cs b/DedicatedServer/Program.cs new file mode 100644 index 0000000..3751555 --- /dev/null +++ b/DedicatedServer/Program.cs @@ -0,0 +1,2 @@ +// See https://aka.ms/new-console-template for more information +Console.WriteLine("Hello, World!"); diff --git a/Blocktest/Code/Block System/BlockManager.cs b/Shared/Code/Block System/BlockManagerShared.cs similarity index 81% rename from Blocktest/Code/Block System/BlockManager.cs rename to Shared/Code/Block System/BlockManagerShared.cs index f47e50c..9504e5a 100644 --- a/Blocktest/Code/Block System/BlockManager.cs +++ b/Shared/Code/Block System/BlockManagerShared.cs @@ -1,17 +1,17 @@ -using System.Linq; +using System.Linq; -namespace Blocktest +namespace Shared { /// /// The BlockManager contains all of the block types in an array of blocks and a list of block names. /// - public static class BlockManager + public abstract class BlockManagerShared { /// Array which stores all block instances for referencing as if they were globals. - private static Block[] allBlocks; + private static BlockShared[] allBlocks; /// Array which stores all block instances for referencing as if they were globals. - public static Block[] AllBlocks { get => allBlocks; private set => allBlocks = value; } + public static BlockShared[] AllBlocks { get => allBlocks; private set => allBlocks = value; } /// List used to store the names of blocks. The indexes are the corresponding block's ID. @@ -30,16 +30,16 @@ public static void Initialize() Type[] allBlockTypes = ( from domainAssembly in AppDomain.CurrentDomain.GetAssemblies() from assemblyType in domainAssembly.GetTypes() - where assemblyType.IsSubclassOf(typeof(Block)) + where assemblyType.IsSubclassOf(typeof(BlockShared)) select assemblyType).ToArray(); - AllBlocks = new Block[allBlockTypes.Length]; + AllBlocks = new BlockShared[allBlockTypes.Length]; BlockNames = new string[allBlockTypes.Length]; // For loops to populate main allBlocks array. for (int i = 0; i < allBlockTypes.Length; i++) { Type newBlockType = allBlockTypes[i]; - Block newBlock = (Block)Activator.CreateInstance(newBlockType); + BlockShared newBlock = (BlockShared)Activator.CreateInstance(newBlockType); newBlock.Initialize(); if (newBlock.blockID == -1) { newBlock.blockID = i; @@ -53,13 +53,5 @@ where assemblyType.IsSubclassOf(typeof(Block)) AllBlocks[newBlock.blockID] = newBlock; } } - - public static void LoadBlockSprites(ContentManager content) - { - foreach(Block block in AllBlocks) { - block.LoadSprite(content); - } - } } - } diff --git a/Blocktest/Code/Block System/Block.cs b/Shared/Code/Block System/BlockShared.cs similarity index 57% rename from Blocktest/Code/Block System/Block.cs rename to Shared/Code/Block System/BlockShared.cs index 2e5fae5..3b21597 100644 --- a/Blocktest/Code/Block System/Block.cs +++ b/Shared/Code/Block System/BlockShared.cs @@ -1,11 +1,9 @@ -using Blocktest.Rendering; - -namespace Blocktest +namespace Shared { /// /// Each block is a different type of tile which can be placed. The behaviours specified in each block class subtype will be used for every tile of that type. /// - public class Block + public abstract class BlockShared { /// The block's ID (index in the allblocks list). /// Leave as -1 for automatic assignment based on init order (probably not a good idea) @@ -21,12 +19,6 @@ public class Block /// Whether or not a block can be placed in the background. public bool canPlaceBackground = true; - /// The block's sprite. - public Drawable blockSprite; - - /// The sprite sheet used for smoothing the block. - public SpriteSheet spriteSheet; - /* METHODS */ /// @@ -37,31 +29,6 @@ public virtual void Initialize() } - /// - /// Called whenever a block's content is loaded by the block manager. - /// - /// - /// DO NOT FORGET TO CALL THE BASE METHOD IF YOU OVERRIDE THIS. - /// - public virtual void LoadSprite(ContentManager content) - { - string path = @"Graphics\Blocks\" + blockName.ToLower().Replace(" ", ""); - try { - blockSprite = new Drawable(path, new Rectangle(1, 1, 10, 10)); //this might need to be expanded in the future in case we decide to make use of the full 12x12 tiles on our spritesheets - if (!blockSmoothing) { - return; - } - spriteSheet = new SpriteSheet(path, 4, 4, 1); - if (spriteSheet.OrderedSprites.Length <= 1) { - Console.WriteLine("Block " + this + " is marked as smoothable, but a sprite sheet could not be found at " + path + "!"); - } - } - catch (ContentLoadException) { - blockSprite = new Drawable(@"Graphics\Blocks\error"); - Console.WriteLine("Block " + this + " does not have an icon at " + path + "!"); - } - } - /// /// Called whenever a block is placed. /// diff --git a/Blocktest/Code/Block System/Tilemap.cs b/Shared/Code/Block System/TilemapShared.cs similarity index 66% rename from Blocktest/Code/Block System/Tilemap.cs rename to Shared/Code/Block System/TilemapShared.cs index 1654cc3..b95c100 100644 --- a/Blocktest/Code/Block System/Tilemap.cs +++ b/Shared/Code/Block System/TilemapShared.cs @@ -1,19 +1,21 @@ -using Blocktest.Rendering; -namespace Blocktest +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +namespace Shared { /// - /// A grid filled with s, usually representing terrain. + /// A grid filled with s, usually representing terrain. /// - public class Tilemap + public class TilemapShared { /// /// The 2D array of all tiles in the tilemap. /// - public Tile?[,] tileGrid; + public TileShared?[,] tileGrid; /// /// A list of all the tiles currently on the tilemap. /// - private readonly List allTiles = new(); + public readonly List allTiles = new(); /// /// The size of the tilemap in tiles. /// @@ -33,21 +35,10 @@ public class Tilemap /// /// The width of the tilemap in tiles. /// The height of the tilemap in tiles. - public Tilemap(int sizeX, int sizeY) + public TilemapShared(int sizeX, int sizeY) { tilemapSize = new(sizeX, sizeY); - tileGrid = new Tile[sizeX, sizeY]; - } - - /// - /// Called from the main draw loop, calls on each tile in the tilemap. - /// - /// The spritebatch to draw the tilemap tiles' sprite on. - public void Draw(SpriteBatch spriteBatch) - { - foreach (Tile tile in allTiles) { - tile.Draw(spriteBatch); - } + tileGrid = new TileShared[sizeX, sizeY]; } /// @@ -55,15 +46,15 @@ public void Draw(SpriteBatch spriteBatch) /// /// Location the new Block will be placed. /// Block type to be placed in the cell. - public Tile SetBlock(Vector2Int location, Block newBlock) => SetTile(location, new Tile(newBlock, location)); + public TileShared SetBlock(Vector2Int location, BlockShared newBlock) => SetTile(location, new TileShared(newBlock, location)); /// /// Sets a Tile at the given XYZ coordinates of a cell in the tile map to a specific type. /// /// Location the new Block will be placed. /// Block type to be placed in the cell. - public Tile SetTile(Vector2Int location, Tile newTile) + public TileShared SetTile(Vector2Int location, TileShared newTile) { - Tile oldTile = GetTile(location); + TileShared oldTile = GetTile(location); if (oldTile != null) { allTiles.Remove(oldTile); } @@ -83,25 +74,25 @@ public Tile SetTile(Vector2Int location, Tile newTile) } /// - /// Deletes a at a specific location(sets value to null). + /// Deletes a at a specific location(sets value to null). /// /// public void DeleteTile(Vector2Int location) => SetTile(location, null); /// - /// Gets the at a specific location on a . + /// Gets the at a specific location on a . /// /// Location of the Tile on the Tilemap to check. - /// placed at the cell. - public Tile? GetTile(Vector2Int location) => GetTile(location.X, location.Y); + /// placed at the cell. + public TileShared? GetTile(Vector2Int location) => GetTile(location.X, location.Y); /// - /// Gets the at a specific location on a . + /// Gets the at a specific location on a . /// /// X position of the Tile on the Tilemap to check. /// Y position of the Tile on the Tilemap to check. - /// placed at the cell. - public Tile? GetTile(int x, int y) { + /// placed at the cell. + public TileShared? GetTile(int x, int y) { if (x < 0 || y < 0 || x >= tilemapSize.X || y >= tilemapSize.Y) { return null; } @@ -109,23 +100,23 @@ public Tile SetTile(Vector2Int location, Tile newTile) } /// - /// Gets the at a specific location on a . + /// Gets the at a specific location on a . /// /// The subtype of Tile to return. /// Location of the Tile on the Tilemap to check. - /// of type T placed at the cell. - public T? GetTile(Vector2Int location) where T : Tile => (T?)GetTile(location.X, location.Y); + /// of type T placed at the cell. + public T? GetTile(Vector2Int location) where T : TileShared => (T?)GetTile(location.X, location.Y); /// - /// Gets the at a specific location on a . + /// Gets the at a specific location on a . /// /// The subtype of Tile to return. /// X position of the Tile on the Tilemap to check. /// Y position of the Tile on the Tilemap to check. - /// of type T placed at the cell. - public T? GetTile(int x, int y) where T : Tile => (T?)GetTile(x, y); + /// of type T placed at the cell. + public T? GetTile(int x, int y) where T : TileShared => (T?)GetTile(x, y); /// - /// Returns whether there is a at the location specified. + /// Returns whether there is a at the location specified. /// /// Location to check. /// Returns true if there is a Tile at the position. Returns false otherwise. @@ -133,42 +124,41 @@ public Tile SetTile(Vector2Int location, Tile newTile) } /// - /// A is filled with tile instances, one for each grid square. + /// A is filled with tile instances, one for each grid square. /// They contain basic information such as name and sprite, but the behaviours and more advanced properties are found in the correlating Block classes. /// - public class Tile + public class TileShared { /// /// The type of block this tile is. /// - public Block SourceBlock; - /// - /// Sprite to be rendered at the Tile. - /// - protected Drawable sprite; + public BlockShared SourceBlock; /// /// The size of the tile square's edges, in pixels (Default 8) /// protected int size = 8; /// + /// The rectangle of the tile, used for sprite rendering and collisions. + /// + public Rectangle rectangle; + /// /// Color of the tile. /// public Color color = Color.White; /// - /// The rectangle of the tile, used for sprite rendering and collisions. + /// Used for bitmask smoothing, should MAYBE not be here. /// - public Rectangle rectangle; + public int bitmask = 0; /// - /// Creates a . + /// Creates a . /// /// The type of block the new tile should be. /// The position in a tilemap the tile will be. - public Tile(Block newBlock, Vector2Int position) + public TileShared(BlockShared newBlock, Vector2Int position) { SourceBlock = newBlock; - sprite = SourceBlock.blockSprite; - rectangle = new Rectangle(Globals.gridSize.X * position.X, Globals.gridSize.Y * position.Y, size, size); // HACK: This can probably be done better + rectangle = new Rectangle(GlobalsShared.gridSize.X * position.X, GlobalsShared.gridSize.Y * position.Y, size, size); // HACK: This can probably be done better } /// @@ -176,11 +166,11 @@ public Tile(Block newBlock, Vector2Int position) /// /// The position of the current tile. /// The tilemap the tile is on. - public void UpdateAdjacencies(Vector2Int position, Tilemap tilemap) + public void UpdateAdjacencies(Vector2Int position, TilemapShared tilemap) { - if (!SourceBlock.blockSmoothing || (SourceBlock.spriteSheet == null)) { return; } // If the tile doesn't or can't smooth, don't even try + if (!SourceBlock.blockSmoothing) { return; } // If the tile doesn't smooth, don't even try - int bitmask = 0; // Using bitmask smoothing, look it up + bitmask = 0; // Using bitmask smoothing, look it up if (HasSmoothableTile(position + Vector2Int.Up, tilemap)) { bitmask += 2; @@ -194,8 +184,6 @@ public void UpdateAdjacencies(Vector2Int position, Tilemap tilemap) if (HasSmoothableTile(position + Vector2Int.Left, tilemap)) { bitmask += 8; } - - sprite = SourceBlock.spriteSheet.OrderedSprites[bitmask]; } /// @@ -204,28 +192,19 @@ public void UpdateAdjacencies(Vector2Int position, Tilemap tilemap) /// The position of the tile to check for smoothing. /// The tilemap on which the tile you want to check for smoothing is. /// Whether or not the tile can smooth with this tile. - private bool HasSmoothableTile(Vector2Int position, Tilemap tilemap) + private bool HasSmoothableTile(Vector2Int position, TilemapShared tilemap) { - Tile otherTile = tilemap.GetTile(position); + TileShared otherTile = tilemap.GetTile(position); if (SourceBlock.smoothSelf) { return IsSameTileType(otherTile); } return otherTile != null; } - /// - /// Called from the main draw loop. - /// - /// The spritebatch to draw the tile's sprite on. - public void Draw(SpriteBatch spriteBatch) - { - spriteBatch.Draw(sprite.Texture, new Vector2(rectangle.X, rectangle.Y), sprite.Bounds, Color.White); - } - /// /// If the tile provided is the same type (references the same block) as the current tile. /// /// The other tile to check. /// Whether or not the other block is the same type as the current tile - private bool IsSameTileType(Tile otherTile) => otherTile?.SourceBlock == SourceBlock; + private bool IsSameTileType(TileShared otherTile) => otherTile?.SourceBlock == SourceBlock; } } diff --git a/Blocktest/Code/Blocks/Asphalt.cs b/Shared/Code/Blocks/Asphalt.cs similarity index 76% rename from Blocktest/Code/Blocks/Asphalt.cs rename to Shared/Code/Blocks/Asphalt.cs index fc2c05a..0236f79 100644 --- a/Blocktest/Code/Blocks/Asphalt.cs +++ b/Shared/Code/Blocks/Asphalt.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class Asphalt : Block + public class Asphalt : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/Blocks/Brick.cs b/Shared/Code/Blocks/Brick.cs similarity index 76% rename from Blocktest/Code/Blocks/Brick.cs rename to Shared/Code/Blocks/Brick.cs index 654e0b5..a40d4bf 100644 --- a/Blocktest/Code/Blocks/Brick.cs +++ b/Shared/Code/Blocks/Brick.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class Brick : Block + public class Brick : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/Blocks/Concrete.cs b/Shared/Code/Blocks/Concrete.cs similarity index 76% rename from Blocktest/Code/Blocks/Concrete.cs rename to Shared/Code/Blocks/Concrete.cs index 3613a14..bc73ca5 100644 --- a/Blocktest/Code/Blocks/Concrete.cs +++ b/Shared/Code/Blocks/Concrete.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class Concrete : Block + public class Concrete : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/Blocks/Dirt.cs b/Shared/Code/Blocks/Dirt.cs similarity index 76% rename from Blocktest/Code/Blocks/Dirt.cs rename to Shared/Code/Blocks/Dirt.cs index cf9eccc..1747627 100644 --- a/Blocktest/Code/Blocks/Dirt.cs +++ b/Shared/Code/Blocks/Dirt.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class Dirt : Block + public class Dirt : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/Blocks/Glass.cs b/Shared/Code/Blocks/Glass.cs similarity index 58% rename from Blocktest/Code/Blocks/Glass.cs rename to Shared/Code/Blocks/Glass.cs index 7931452..a324bdd 100644 --- a/Blocktest/Code/Blocks/Glass.cs +++ b/Shared/Code/Blocks/Glass.cs @@ -1,13 +1,15 @@ -namespace Blocktest.Blocks +/* Glass crashes game right now +namespace Shared.Blocks { - public class Glass : Block + public class Glass : BlockShared { public override void Initialize() { blockName = "Glass"; - blockID = 4; + blockID = 15; blockSmoothing = false; base.Initialize(); } } -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/Blocktest/Code/Blocks/GlassPane.cs b/Shared/Code/Blocks/GlassPane.cs similarity index 70% rename from Blocktest/Code/Blocks/GlassPane.cs rename to Shared/Code/Blocks/GlassPane.cs index 24d2002..b45d0dd 100644 --- a/Blocktest/Code/Blocks/GlassPane.cs +++ b/Shared/Code/Blocks/GlassPane.cs @@ -1,11 +1,11 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class GlassPane : Block + public class GlassPane : BlockShared { public override void Initialize() { blockName = "Glass Pane"; - blockID = 5; + blockID = 4; blockSmoothing = true; smoothSelf = true; base.Initialize(); diff --git a/Blocktest/Code/Blocks/Grass.cs b/Shared/Code/Blocks/Grass.cs similarity index 76% rename from Blocktest/Code/Blocks/Grass.cs rename to Shared/Code/Blocks/Grass.cs index f813b67..ebe5ae5 100644 --- a/Blocktest/Code/Blocks/Grass.cs +++ b/Shared/Code/Blocks/Grass.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class Grass : Block + public class Grass : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/Blocks/LargeStoneBrick.cs b/Shared/Code/Blocks/LargeStoneBrick.cs similarity index 66% rename from Blocktest/Code/Blocks/LargeStoneBrick.cs rename to Shared/Code/Blocks/LargeStoneBrick.cs index 3cfe0cb..9d2ef78 100644 --- a/Blocktest/Code/Blocks/LargeStoneBrick.cs +++ b/Shared/Code/Blocks/LargeStoneBrick.cs @@ -1,11 +1,11 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class LargeStoneBrick : Block + public class LargeStoneBrick : BlockShared { public override void Initialize() { blockName = "Large Stone Brick"; - blockID = 15; + blockID = 5; blockSmoothing = true; base.Initialize(); } diff --git a/Blocktest/Code/Blocks/Log.cs b/Shared/Code/Blocks/Log.cs similarity index 77% rename from Blocktest/Code/Blocks/Log.cs rename to Shared/Code/Blocks/Log.cs index 8974d10..5153049 100644 --- a/Blocktest/Code/Blocks/Log.cs +++ b/Shared/Code/Blocks/Log.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class Log : Block + public class Log : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/Blocks/Pykrete.cs b/Shared/Code/Blocks/Pykrete.cs similarity index 76% rename from Blocktest/Code/Blocks/Pykrete.cs rename to Shared/Code/Blocks/Pykrete.cs index 80145d7..ce412c6 100644 --- a/Blocktest/Code/Blocks/Pykrete.cs +++ b/Shared/Code/Blocks/Pykrete.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class Pykrete : Block + public class Pykrete : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/Blocks/SmoothMetal.cs b/Shared/Code/Blocks/SmoothMetal.cs similarity index 75% rename from Blocktest/Code/Blocks/SmoothMetal.cs rename to Shared/Code/Blocks/SmoothMetal.cs index fb8a3c3..b9e79f1 100644 --- a/Blocktest/Code/Blocks/SmoothMetal.cs +++ b/Shared/Code/Blocks/SmoothMetal.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class SmoothMetal : Block + public class SmoothMetal : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/Blocks/Stone.cs b/Shared/Code/Blocks/Stone.cs similarity index 76% rename from Blocktest/Code/Blocks/Stone.cs rename to Shared/Code/Blocks/Stone.cs index c0fac41..a340364 100644 --- a/Blocktest/Code/Blocks/Stone.cs +++ b/Shared/Code/Blocks/Stone.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class Stone : Block + public class Stone : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/Blocks/StoneBrick.cs b/Shared/Code/Blocks/StoneBrick.cs similarity index 75% rename from Blocktest/Code/Blocks/StoneBrick.cs rename to Shared/Code/Blocks/StoneBrick.cs index 6737249..91fb616 100644 --- a/Blocktest/Code/Blocks/StoneBrick.cs +++ b/Shared/Code/Blocks/StoneBrick.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class StoneBrick : Block + public class StoneBrick : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/Blocks/StonePathBrick.cs b/Shared/Code/Blocks/StonePathBrick.cs similarity index 75% rename from Blocktest/Code/Blocks/StonePathBrick.cs rename to Shared/Code/Blocks/StonePathBrick.cs index dc60ed5..ffb13f5 100644 --- a/Blocktest/Code/Blocks/StonePathBrick.cs +++ b/Shared/Code/Blocks/StonePathBrick.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class StonePathBrick : Block + public class StonePathBrick : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/Blocks/Wood.cs b/Shared/Code/Blocks/Wood.cs similarity index 76% rename from Blocktest/Code/Blocks/Wood.cs rename to Shared/Code/Blocks/Wood.cs index 7131ab0..6ff1405 100644 --- a/Blocktest/Code/Blocks/Wood.cs +++ b/Shared/Code/Blocks/Wood.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class Wood : Block + public class Wood : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/Blocks/WoodPanel.cs b/Shared/Code/Blocks/WoodPanel.cs similarity index 76% rename from Blocktest/Code/Blocks/WoodPanel.cs rename to Shared/Code/Blocks/WoodPanel.cs index a1c0a35..06238c7 100644 --- a/Blocktest/Code/Blocks/WoodPanel.cs +++ b/Shared/Code/Blocks/WoodPanel.cs @@ -1,6 +1,6 @@ -namespace Blocktest.Blocks +namespace Shared.Blocks { - public class WoodPanel : Block + public class WoodPanel : BlockShared { public override void Initialize() { diff --git a/Blocktest/Code/BuildSystem.cs b/Shared/Code/BuildSystem.cs similarity index 83% rename from Blocktest/Code/BuildSystem.cs rename to Shared/Code/BuildSystem.cs index 13e6410..91a1f18 100644 --- a/Blocktest/Code/BuildSystem.cs +++ b/Shared/Code/BuildSystem.cs @@ -1,11 +1,14 @@ -namespace Blocktest +using System.Collections.Generic; +using Microsoft.Xna.Framework; + +namespace Shared { public static class BuildSystem { /// /// An array containing an entry for every block in the world. Used for saving games. /// - private static readonly int[,,] currentWorld = new int[Globals.maxX, Globals.maxY, 2]; + private static readonly int[,,] currentWorld = new int[GlobalsShared.maxX, GlobalsShared.maxY, 2]; /// /// The method called whenever an object is removed. @@ -21,7 +24,7 @@ public static class BuildSystem /// The position of the block to destroy (grid coords) public static void BreakBlockCell(bool foreground, Vector2Int tilePosition) { - Tilemap tilemap = foreground ? Globals.ForegroundTilemap : Globals.BackgroundTilemap; + TilemapShared tilemap = foreground ? GlobalsShared.ForegroundTilemap : GlobalsShared.BackgroundTilemap; if (tilemap.HasTile(tilePosition)) { @@ -58,18 +61,18 @@ public static void BreakBlockCell(bool foreground, Vector2Int tilePosition) /// The block type to place. /// Whether or not the block should be placed in the foreground. /// The position of the placed block. (Grid coords) - public static void PlaceBlockCell(Block toPlace, bool foreground, Vector2Int tilePosition) + public static void PlaceBlockCell(BlockShared toPlace, bool foreground, Vector2Int tilePosition) { - Tile newTile = new(toPlace, tilePosition); + TileShared newTile = new(toPlace, tilePosition); toPlace.OnPlace(tilePosition, foreground); if (foreground) { //newTile.colliderType = Tile.ColliderType.Grid; - Globals.ForegroundTilemap.SetTile(tilePosition, newTile); + GlobalsShared.ForegroundTilemap.SetTile(tilePosition, newTile); currentWorld[tilePosition.X, tilePosition.Y, 0] = toPlace.blockID + 1; } else if (toPlace.canPlaceBackground) { newTile.color = new Color(0.5f, 0.5f, 0.5f, 1f); - Globals.BackgroundTilemap.SetTile(tilePosition, newTile); + GlobalsShared.BackgroundTilemap.SetTile(tilePosition, newTile); currentWorld[tilePosition.X, tilePosition.Y, 1] = toPlace.blockID + 1; } } @@ -80,7 +83,7 @@ public static void PlaceBlockCell(Block toPlace, bool foreground, Vector2Int til /// The block type to place. /// Whether or not the block should be placed in the foreground. /// The position of the placed block. (Grid coords) - public static void PlaceBlockCell(Block toPlace, bool foreground, Vector2 tilePosition) => PlaceBlockCell(toPlace, foreground, (Vector2Int)tilePosition); + public static void PlaceBlockCell(BlockShared toPlace, bool foreground, Vector2 tilePosition) => PlaceBlockCell(toPlace, foreground, (Vector2Int)tilePosition); } } \ No newline at end of file diff --git a/Blocktest/Code/Math.cs b/Shared/Code/Math.cs similarity index 98% rename from Blocktest/Code/Math.cs rename to Shared/Code/Math.cs index 41e0f63..d501584 100644 --- a/Blocktest/Code/Math.cs +++ b/Shared/Code/Math.cs @@ -1,4 +1,6 @@ -namespace Blocktest +using Microsoft.Xna.Framework; + +namespace Shared { /// /// Represents a vector with two integer values rather than two floating-point values. diff --git a/Shared/GlobalUsings.cs b/Shared/GlobalUsings.cs new file mode 100644 index 0000000..911a584 --- /dev/null +++ b/Shared/GlobalUsings.cs @@ -0,0 +1 @@ +global using System; \ No newline at end of file diff --git a/Shared/Globals.cs b/Shared/Globals.cs new file mode 100644 index 0000000..2cfb8c9 --- /dev/null +++ b/Shared/Globals.cs @@ -0,0 +1,29 @@ +using Shared; + +namespace Shared +{ + public static class GlobalsShared + { + + /// Tilemap for foreground objects. + private static TilemapShared foregroundTilemap; + /// Tilemap for foreground objects. + public static TilemapShared ForegroundTilemap { get => foregroundTilemap; set => foregroundTilemap = value; } + + /// Tilemap for background (non-dense) objects. + private static TilemapShared backgroundTilemap; + /// Tilemap for background (non-dense) objects. + public static TilemapShared BackgroundTilemap { get => backgroundTilemap; set => backgroundTilemap = value; } + + /// The maximum world size. (Width) + public static readonly int maxX = 255; + /// The maximum world size. (Height) + public static readonly int maxY = 255; + + /// The size of the grid the game is played on. + public static readonly Vector2Int gridSize = new(8, 8); + + //public static BlockManager blockManager = new(); + + } +} diff --git a/Shared/Shared.csproj b/Shared/Shared.csproj new file mode 100644 index 0000000..0b502d7 --- /dev/null +++ b/Shared/Shared.csproj @@ -0,0 +1,9 @@ + + + net7.0 + enable + + + + + From 27df3ee1b35d9984ad13a4df0c04a5bf454d556c Mon Sep 17 00:00:00 2001 From: SuperYodeler <51685082+Superyodeler@users.noreply.github.com> Date: Wed, 13 Sep 2023 12:59:02 -0400 Subject: [PATCH 2/9] Adding packets and working on rollback --- Blocktest/Blocktest.csproj | 1 + Blocktest/Code/Globals.cs | 5 ++- Blocktest/Code/Networking/Client.cs | 28 +++++++++++++ Blocktest/Code/Scenes/GameScene.cs | 18 ++++---- Blocktest/packages.lock.json | 7 ++++ DedicatedServer/DedicatedServer.csproj | 8 ++++ Shared/Code/Blocks/Glass.cs | 2 +- Shared/Code/BuildSystem.cs | 58 ++++++++++++++++++++++---- Shared/Code/Networking/Client.cs | 0 Shared/Code/Networking/Tick.cs | 44 +++++++++++++++++++ Shared/Code/Networking/TickBuffer.cs | 32 ++++++++++++++ Shared/Code/Packets/BreakTile.cs | 43 +++++++++++++++++++ Shared/Code/Packets/Packet.cs | 20 +++++++++ Shared/Code/Packets/TileChange.cs | 46 ++++++++++++++++++++ Shared/Code/Packets/WorldDownload.cs | 54 ++++++++++++++++++++++++ Shared/Globals.cs | 4 +- Shared/Shared.csproj | 1 + 17 files changed, 349 insertions(+), 22 deletions(-) create mode 100644 Blocktest/Code/Networking/Client.cs create mode 100644 Shared/Code/Networking/Client.cs create mode 100644 Shared/Code/Networking/Tick.cs create mode 100644 Shared/Code/Networking/TickBuffer.cs create mode 100644 Shared/Code/Packets/BreakTile.cs create mode 100644 Shared/Code/Packets/Packet.cs create mode 100644 Shared/Code/Packets/TileChange.cs create mode 100644 Shared/Code/Packets/WorldDownload.cs diff --git a/Blocktest/Blocktest.csproj b/Blocktest/Blocktest.csproj index 3fd825e..df3aee1 100644 --- a/Blocktest/Blocktest.csproj +++ b/Blocktest/Blocktest.csproj @@ -22,6 +22,7 @@ true + diff --git a/Blocktest/Code/Globals.cs b/Blocktest/Code/Globals.cs index 4dcfcb7..d379490 100644 --- a/Blocktest/Code/Globals.cs +++ b/Blocktest/Code/Globals.cs @@ -1,4 +1,6 @@ -namespace Blocktest +using Microsoft.VisualBasic; + +namespace Blocktest { public static class Globals { @@ -12,6 +14,7 @@ public static class Globals private static TilemapSprites backgroundTilemapSprites; /// Tilemap for background (non-dense) objects. public static TilemapSprites BackgroundTilemapSprites { get => backgroundTilemapSprites; set => backgroundTilemapSprites = value; } + } } diff --git a/Blocktest/Code/Networking/Client.cs b/Blocktest/Code/Networking/Client.cs new file mode 100644 index 0000000..b710510 --- /dev/null +++ b/Blocktest/Code/Networking/Client.cs @@ -0,0 +1,28 @@ +using LiteNetLib; +using LiteNetLib.Utils; + +namespace Blocktest.Networking +{ + public class Client + { + private EventBasedNetListener listener; + + private NetManager manager; + private NetPeer? server; + + public Client(string ip, int port, string key) + { + listener = new(); + manager = new(listener); + manager.Connect(ip, port, key); + } + + protected void networkRecieveEvent(NetPeer peer, NetPacketReader packerReader, byte channelNumber, DeliveryMethod deliveryMethod) + { + if(server == null) + { + server = peer; + } + } + } +} \ No newline at end of file diff --git a/Blocktest/Code/Scenes/GameScene.cs b/Blocktest/Code/Scenes/GameScene.cs index 62584fe..3f8d0f7 100644 --- a/Blocktest/Code/Scenes/GameScene.cs +++ b/Blocktest/Code/Scenes/GameScene.cs @@ -91,7 +91,7 @@ public void Draw(GameTime gameTime, GraphicsDevice graphicsDevice) { String fps = string.Format("FPS: {0}", _frameCounter.AverageFramesPerSecond); - Console.WriteLine(fps); + //Console.WriteLine(fps); if (buildMode) _spriteBatch.Draw(BlockSpritesManager.AllBlocksSprites[blockSelected].blockSprite.Texture, @@ -111,15 +111,15 @@ public GameScene(BlocktestGame game) { Globals.BackgroundTilemapSprites = new(GlobalsShared.BackgroundTilemap); Globals.ForegroundTilemapSprites = new(GlobalsShared.ForegroundTilemap); + int[,,] newWorld = new int[GlobalsShared.maxX, GlobalsShared.maxY, 2]; for (int i = 0; i < GlobalsShared.maxX; i++) { - BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[2], true, new Vector2Int(i, 5)); - BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[0], true, new Vector2Int(i, 4)); - BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[0], true, new Vector2Int(i, 3)); - BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[0], true, new Vector2Int(i, 2)); - BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[0], true, new Vector2Int(i, 1)); - BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[1], true, new Vector2Int(i, 0)); + newWorld[i, 5, 1] = 3; + newWorld[i, 4, 1] = 1; + newWorld[i, 3, 1] = 1; + newWorld[i, 2, 1] = 1; + newWorld[i, 1, 1] = 1; + newWorld[i, 0, 1] = 2; } - - BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[0], true, new Vector2Int(20, 20)); + BuildSystem.LoadNewWorld(newWorld); } } \ No newline at end of file diff --git a/Blocktest/packages.lock.json b/Blocktest/packages.lock.json index beb8aa6..666688e 100644 --- a/Blocktest/packages.lock.json +++ b/Blocktest/packages.lock.json @@ -2,6 +2,12 @@ "version": 1, "dependencies": { "net7.0": { + "LiteNetLib": { + "type": "Direct", + "requested": "[1.1.0, )", + "resolved": "1.1.0", + "contentHash": "GavpDPs65Y4vvAeECbApWXynTOn7f7IVIHmRKpPmzLWSf3vllcxHN4XPN+Tu3YFqIwOYUdgI8fhkCMhn4FLQCw==" + }, "MonoGame.Content.Builder.Task": { "type": "Direct", "requested": "[3.8.*, )", @@ -23,6 +29,7 @@ "shared": { "type": "Project", "dependencies": { + "LiteNetLib": "[1.1.0, )", "MonoGame.Framework.DesktopGL": "[3.8.1.303, )" } } diff --git a/DedicatedServer/DedicatedServer.csproj b/DedicatedServer/DedicatedServer.csproj index f02677b..2f400b9 100644 --- a/DedicatedServer/DedicatedServer.csproj +++ b/DedicatedServer/DedicatedServer.csproj @@ -1,5 +1,13 @@ + + + + + + + + Exe net7.0 diff --git a/Shared/Code/Blocks/Glass.cs b/Shared/Code/Blocks/Glass.cs index 00c6269..df67db3 100644 --- a/Shared/Code/Blocks/Glass.cs +++ b/Shared/Code/Blocks/Glass.cs @@ -6,7 +6,7 @@ public class Glass : BlockShared public override void Initialize() { blockName = "Glass"; - blockID = 16; + blockID = -1; // Needs to be changed if this is fixed blockSmoothing = false; base.Initialize(); } diff --git a/Shared/Code/BuildSystem.cs b/Shared/Code/BuildSystem.cs index 91a1f18..01a22b4 100644 --- a/Shared/Code/BuildSystem.cs +++ b/Shared/Code/BuildSystem.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Microsoft.Xna.Framework; +using Shared.Networking; namespace Shared { @@ -28,23 +29,16 @@ public static void BreakBlockCell(bool foreground, Vector2Int tilePosition) if (tilemap.HasTile(tilePosition)) { + int z = foreground ? 1 : 0; // Convert foreground bool to int tilemap.GetTile(tilePosition).SourceBlock.OnBreak(tilePosition, true); tilemap.SetTile(tilePosition, null); - currentWorld[tilePosition.X, tilePosition.Y, 0] = 0; + currentWorld[tilePosition.X, tilePosition.Y, z] = 0; } else { return; } - - foreach (Vector2Int loc in new List() { Vector2Int.Up, Vector2Int.Down, Vector2Int.Left, Vector2Int.Right }) { // Refreshes all blocks in cardinal dirs - if ((tilePosition + loc).X >= 0 && (tilePosition + loc).X < tilemap.tilemapSize.X && (tilePosition + loc).Y >= 0 && (tilePosition + loc).Y < tilemap.tilemapSize.Y && (tilemap.HasTile(tilePosition + loc))) - { - tilemap.GetTile(tilePosition + loc).UpdateAdjacencies(tilePosition + loc, tilemap); - } - } - } /// @@ -85,5 +79,51 @@ public static void PlaceBlockCell(BlockShared toPlace, bool foreground, Vector2I /// The position of the placed block. (Grid coords) public static void PlaceBlockCell(BlockShared toPlace, bool foreground, Vector2 tilePosition) => PlaceBlockCell(toPlace, foreground, (Vector2Int)tilePosition); + /// + /// Loads a new world into the tilemaps and currentWorld. + /// + /// An array containing an entry for every block in the world. Used for loading games. MUST be the same dimensions as currentWorld + public static void LoadNewWorld(int[,,] newWorld) + { + for(int x = 0; x < GlobalsShared.maxX; x++) + { + for(int y = 0; y < GlobalsShared.maxY; y++) + { + for(int z = 0; z < 2; z++) + { + Vector2Int tilePosition = new(x,y); + int blockNum = newWorld[x,y,z]; + LoadNewBlock(blockNum, tilePosition, z); + } + } + } + } + + /// + /// Loads a new world into the tilemaps and currentWorld. + /// + /// Incoming + public static void LoadNewWorld(WorldDownload packet) => LoadNewWorld(packet.world); + + /// + /// Loads a new block from an int + /// + /// The blockid + 1 + /// The position of the tile in the tilemap + /// Whether the block is in the foreground, expressed as an int + private static void LoadNewBlock(int blockNum, Vector2Int tilePosition, int foregroundInt) + { + currentWorld[tilePosition.X, tilePosition.Y, foregroundInt] = blockNum; + bool foreground = Convert.ToBoolean(foregroundInt); + if(blockNum > 0) + { + BlockShared newBlock = BlockManagerShared.AllBlocks[blockNum - 1]; + PlaceBlockCell(newBlock, foreground, tilePosition); + } + else + { + BreakBlockCell(foreground, tilePosition); + } + } } } \ No newline at end of file diff --git a/Shared/Code/Networking/Client.cs b/Shared/Code/Networking/Client.cs new file mode 100644 index 0000000..e69de29 diff --git a/Shared/Code/Networking/Tick.cs b/Shared/Code/Networking/Tick.cs new file mode 100644 index 0000000..15477db --- /dev/null +++ b/Shared/Code/Networking/Tick.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; + +namespace Shared.Networking +{ + public class Tick + { + /// + /// Time at the beginning of the tick. + /// + //public long time; + public TilemapShared foreground; + public TilemapShared background; + public List packets; + + public Tick(TilemapShared newForeground, TilemapShared newBackground) + { + foreground = newForeground; + background = newBackground; + packets = new(); + } + + /// + /// Process all packets taking action on this tick. + /// + public void ProcessStartTick() + { + Array.Copy(foreground.tileGrid, GlobalsShared.ForegroundTilemap.tileGrid, GlobalsShared.maxX * GlobalsShared.maxY); + Array.Copy(background.tileGrid, GlobalsShared.BackgroundTilemap.tileGrid, GlobalsShared.maxX * GlobalsShared.maxY); + foreach(Packet packet in packets) + { + packet.Process(); + } + } + public void ProcessTick() + { + Array.Copy(GlobalsShared.ForegroundTilemap.tileGrid, foreground.tileGrid, GlobalsShared.maxX * GlobalsShared.maxY); + Array.Copy(GlobalsShared.BackgroundTilemap.tileGrid, background.tileGrid, GlobalsShared.maxX * GlobalsShared.maxY); + foreach(Packet packet in packets) + { + packet.Process(); + } + } + } +} \ No newline at end of file diff --git a/Shared/Code/Networking/TickBuffer.cs b/Shared/Code/Networking/TickBuffer.cs new file mode 100644 index 0000000..3fe0dee --- /dev/null +++ b/Shared/Code/Networking/TickBuffer.cs @@ -0,0 +1,32 @@ +using System.Security.Cryptography; + +namespace Shared.Networking +{ + public class TickBuffer + { + private ushort currTick; + private Tick[] tickBuffer = new Tick[GlobalsShared.MaxTicksStored]; + + public TickBuffer(ushort newTick) + { + currTick = newTick; + } + /// + /// Add additional tick + /// + public void IncrCurrTick(Tick newTick) + { + currTick++; + if(currTick == GlobalsShared.MaxTicksStored) + { + currTick = 0; + } + tickBuffer[currTick] = newTick; + } + + public void AddPacket(ushort tickNum, Packet newPacket) + { + + } + } +} \ No newline at end of file diff --git a/Shared/Code/Packets/BreakTile.cs b/Shared/Code/Packets/BreakTile.cs new file mode 100644 index 0000000..60f4e27 --- /dev/null +++ b/Shared/Code/Packets/BreakTile.cs @@ -0,0 +1,43 @@ +using LiteNetLib; +using LiteNetLib.Utils; + +namespace Shared.Networking +{ + /// + /// Packet for handling tile breaking. Planned to be used with + /// + /// + /// Should be reworked when chunks are added. + /// + public class BreakTile : Packet + { + public ushort tickNum; + public Vector2Int position; + public bool foreground; + public ushort GetTickNum() + { + return tickNum; + } + public void Process() + { + BuildSystem.BreakBlockCell(foreground, position); + } + public void Serialize(NetDataWriter writer) + { + writer.Put(tickNum); + writer.Put(position.X); + writer.Put(position.Y); + writer.Put(foreground); + } + + public void Deserialize(NetDataReader reader) + { + tickNum = reader.GetUShort(); + int x = reader.GetInt(); + int y = reader.GetInt(); + foreground = reader.GetBool(); + + position = new(x, y); + } + } +} \ No newline at end of file diff --git a/Shared/Code/Packets/Packet.cs b/Shared/Code/Packets/Packet.cs new file mode 100644 index 0000000..b3399d8 --- /dev/null +++ b/Shared/Code/Packets/Packet.cs @@ -0,0 +1,20 @@ +using LiteNetLib; +using LiteNetLib.Utils; + +namespace Shared.Networking +{ + public interface Packet : INetSerializable + { + /// + /// Handles all processing for the packet. + /// + public abstract void Process(); + + /// + /// Returns the tick number that the simulation must rewind to. + /// + /// The number of the tick this packet applies to. + public abstract ushort GetTickNum(); + } + +} \ No newline at end of file diff --git a/Shared/Code/Packets/TileChange.cs b/Shared/Code/Packets/TileChange.cs new file mode 100644 index 0000000..416dddc --- /dev/null +++ b/Shared/Code/Packets/TileChange.cs @@ -0,0 +1,46 @@ +using LiteNetLib; +using LiteNetLib.Utils; + +namespace Shared.Networking +{ + /// + /// Packet for handling tile changes. Planned to be used with + /// + /// + /// Should be reworked when chunks are added. + /// + public class TileChange : Packet + { + public ushort tickNum; + public Vector2Int position; + public bool foreground; + public int blockId; + public ushort GetTickNum() + { + return tickNum; + } + public void Process() + { + BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[blockId], foreground, position); + } + public void Serialize(NetDataWriter writer) + { + writer.Put(tickNum); + writer.Put(position.X); + writer.Put(position.Y); + writer.Put(foreground); + writer.Put(blockId); + } + + public void Deserialize(NetDataReader reader) + { + tickNum = reader.GetUShort(); + int x = reader.GetInt(); + int y = reader.GetInt(); + foreground = reader.GetBool(); + blockId = reader.GetInt(); + + position = new(x, y); + } + } +} \ No newline at end of file diff --git a/Shared/Code/Packets/WorldDownload.cs b/Shared/Code/Packets/WorldDownload.cs new file mode 100644 index 0000000..741fce2 --- /dev/null +++ b/Shared/Code/Packets/WorldDownload.cs @@ -0,0 +1,54 @@ +using LiteNetLib; +using LiteNetLib.Utils; + +namespace Shared.Networking +{ + /// + /// Packet for handling initial world download. Should be used with + /// + /// + /// Should be replaced when chunks are added. + /// + public class WorldDownload : Packet + { + public ushort tickNum; + public int[,,] world = new int[GlobalsShared.maxX, GlobalsShared.maxY, 2]; + public ushort GetTickNum() + { + return tickNum; + } + public void Process() + { + BuildSystem.LoadNewWorld(this); + } + public void Serialize(NetDataWriter writer) + { + writer.Put(tickNum); + for(int x = 0; x < GlobalsShared.maxX; x++) + { + for(int y = 0; y < GlobalsShared.maxY; y++) + { + for(int z = 0; z < 2; z++) + { + writer.Put(world[x,y,z]); + } + } + } + } + + public void Deserialize(NetDataReader reader) + { + tickNum = reader.GetUShort(); + for(int x = 0; x < GlobalsShared.maxX; x++) + { + for(int y = 0; y < GlobalsShared.maxY; y++) + { + for(int z = 0; z < 2; z++) + { + world[x,y,z] = reader.GetInt(); + } + } + } + } + } +} \ No newline at end of file diff --git a/Shared/Globals.cs b/Shared/Globals.cs index 2cfb8c9..23caf73 100644 --- a/Shared/Globals.cs +++ b/Shared/Globals.cs @@ -23,7 +23,7 @@ public static class GlobalsShared /// The size of the grid the game is played on. public static readonly Vector2Int gridSize = new(8, 8); - //public static BlockManager blockManager = new(); - + /// The total number of ticks stored. 10 secs for now. + public const int MaxTicksStored = 600; } } diff --git a/Shared/Shared.csproj b/Shared/Shared.csproj index 0b502d7..7565042 100644 --- a/Shared/Shared.csproj +++ b/Shared/Shared.csproj @@ -4,6 +4,7 @@ enable + From e3b8890c74a72c04da75b5952ce0473cf8f8c210 Mon Sep 17 00:00:00 2001 From: SuperYodeler <51685082+Superyodeler@users.noreply.github.com> Date: Mon, 18 Sep 2023 12:28:04 -0400 Subject: [PATCH 3/9] Added Air block, started work on Dedicated Server, more work on networking --- Blocktest/Code/Block System/BlockSprites.cs | 4 +- Blocktest/Code/Block System/TilemapSprites.cs | 16 +++- Blocktest/Code/Globals.cs | 3 +- Blocktest/Code/Networking/Client.cs | 27 ++++++- Blocktest/Code/Scenes/GameScene.cs | 36 ++++++--- Blocktest/Content/Graphics/Blocks/air.png | Bin 0 -> 101 bytes DedicatedServer/Code/Globals.cs | 9 +++ DedicatedServer/Code/Misc/FrameCounter.cs | 36 +++++++++ DedicatedServer/Code/Networking/Server.cs | 57 +++++++++++++ .../Code/Networking/ServerPlayerManager.cs | 38 +++++++++ DedicatedServer/Code/WorldHandler.cs | 69 ++++++++++++++++ DedicatedServer/Program.cs | 7 +- Shared/Code/Block System/TilemapShared.cs | 24 +++--- Shared/Code/Blocks/Air.cs | 13 +++ Shared/Code/Blocks/Asphalt.cs | 2 +- Shared/Code/Blocks/Brick.cs | 2 +- Shared/Code/Blocks/Concrete.cs | 2 +- Shared/Code/Blocks/Dirt.cs | 2 +- Shared/Code/Blocks/GlassPane.cs | 2 +- Shared/Code/Blocks/Grass.cs | 2 +- Shared/Code/Blocks/LargeStoneBrick.cs | 2 +- Shared/Code/Blocks/Log.cs | 2 +- Shared/Code/Blocks/Pykrete.cs | 2 +- Shared/Code/Blocks/SmoothMetal.cs | 2 +- Shared/Code/Blocks/Stone.cs | 2 +- Shared/Code/Blocks/StoneBrick.cs | 2 +- Shared/Code/Blocks/StonePathBrick.cs | 2 +- Shared/Code/Blocks/WhiteSand.cs | 2 +- Shared/Code/Blocks/Wood.cs | 2 +- Shared/Code/Blocks/WoodPanel.cs | 2 +- Shared/Code/BuildSystem.cs | 22 ++++- Shared/Code/Networking/TickBuffer.cs | 75 +++++++++++++++++- Shared/Globals.cs | 7 +- 33 files changed, 413 insertions(+), 62 deletions(-) create mode 100644 Blocktest/Content/Graphics/Blocks/air.png create mode 100644 DedicatedServer/Code/Globals.cs create mode 100644 DedicatedServer/Code/Misc/FrameCounter.cs create mode 100644 DedicatedServer/Code/Networking/Server.cs create mode 100644 DedicatedServer/Code/Networking/ServerPlayerManager.cs create mode 100644 DedicatedServer/Code/WorldHandler.cs create mode 100644 Shared/Code/Blocks/Air.cs diff --git a/Blocktest/Code/Block System/BlockSprites.cs b/Blocktest/Code/Block System/BlockSprites.cs index 8ce65f0..6bac89f 100644 --- a/Blocktest/Code/Block System/BlockSprites.cs +++ b/Blocktest/Code/Block System/BlockSprites.cs @@ -35,9 +35,9 @@ public virtual void LoadSprite(ContentManager content) string path = @"Graphics\Blocks\" + blockShared.blockName.ToLower().Replace(" ", ""); try { blockSprite = new Drawable(path, new Rectangle(1, 1, 10, 10)); //this might need to be expanded in the future in case we decide to make use of the full 12x12 tiles on our spritesheets - if (!blockShared.blockSmoothing) { + /*if (!blockShared.blockSmoothing) { return; - } + }*/ spriteSheet = new SpriteSheet(path, 4, 4, 1); if (spriteSheet.OrderedSprites.Length <= 1) { Console.WriteLine("Block " + this + " is marked as smoothable, but a sprite sheet could not be found at " + path + "!"); diff --git a/Blocktest/Code/Block System/TilemapSprites.cs b/Blocktest/Code/Block System/TilemapSprites.cs index 8dc0e78..597fe89 100644 --- a/Blocktest/Code/Block System/TilemapSprites.cs +++ b/Blocktest/Code/Block System/TilemapSprites.cs @@ -26,13 +26,23 @@ public TilemapSprites(TilemapShared newTilemap) /// quickly so the codebase split causes fewer issues for others. /// /// The spritebatch to draw the tilemap tiles' sprite on. - public void Draw(SpriteBatch spriteBatch) + public void DrawAllTiles(SpriteBatch spriteBatch) { - foreach (TileShared tile in tilemap.allTiles) { + for(int x = 0; x < tilemap.tilemapSize.X; x++) + { + for(int y = 0; y < tilemap.tilemapSize.Y; y++) + { + TileShared? tile = tilemap.tileGrid[x, y]; + BlockSprites blockSprites = BlockSpritesManager.AllBlocksSprites[tile.SourceBlock.blockID]; + Drawable sprite = blockSprites.spriteSheet.OrderedSprites[tile.bitmask]; + spriteBatch.Draw(sprite.Texture, new Vector2(tile.rectangle.X, tile.rectangle.Y), sprite.Bounds, tile.color); + } + } + /*foreach (TileShared tile in tilemap.allTiles) { BlockSprites blockSprites = BlockSpritesManager.AllBlocksSprites[tile.SourceBlock.blockID]; Drawable sprite = blockSprites.spriteSheet.OrderedSprites[tile.bitmask]; spriteBatch.Draw(sprite.Texture, new Vector2(tile.rectangle.X, tile.rectangle.Y), sprite.Bounds, tile.color); - } + }*/ } } } diff --git a/Blocktest/Code/Globals.cs b/Blocktest/Code/Globals.cs index d379490..e591610 100644 --- a/Blocktest/Code/Globals.cs +++ b/Blocktest/Code/Globals.cs @@ -1,4 +1,5 @@ using Microsoft.VisualBasic; +using Shared.Networking; namespace Blocktest { @@ -15,6 +16,6 @@ public static class Globals /// Tilemap for background (non-dense) objects. public static TilemapSprites BackgroundTilemapSprites { get => backgroundTilemapSprites; set => backgroundTilemapSprites = value; } - + public static TickBuffer clientTickBuffer = new(0); } } diff --git a/Blocktest/Code/Networking/Client.cs b/Blocktest/Code/Networking/Client.cs index b710510..0e69637 100644 --- a/Blocktest/Code/Networking/Client.cs +++ b/Blocktest/Code/Networking/Client.cs @@ -1,27 +1,48 @@ using LiteNetLib; using LiteNetLib.Utils; +using Shared.Networking; namespace Blocktest.Networking { public class Client { private EventBasedNetListener listener; - private NetManager manager; private NetPeer? server; - public Client(string ip, int port, string key) + public Client() { listener = new(); manager = new(listener); + listener.NetworkReceiveEvent += NetworkRecieveEvent; + manager.Start(); + } + + public void Start(string ip, int port, string key) + { manager.Connect(ip, port, key); } - protected void networkRecieveEvent(NetPeer peer, NetPacketReader packerReader, byte channelNumber, DeliveryMethod deliveryMethod) + public void Update() + { + manager.PollEvents(); + } + + protected void NetworkRecieveEvent(NetPeer peer, NetPacketReader packetReader, byte channelNumber, DeliveryMethod deliveryMethod) { if(server == null) { + Console.WriteLine("Got first packet"); server = peer; + WorldDownload worldPacket = new(); + worldPacket.Deserialize(packetReader); + Packet[] starterPacket = {worldPacket}; + Globals.clientTickBuffer = new(worldPacket.GetTickNum()); + Globals.clientTickBuffer.AddPackets(starterPacket); + } + else + { + Console.WriteLine("Wrong packet"); } } } diff --git a/Blocktest/Code/Scenes/GameScene.cs b/Blocktest/Code/Scenes/GameScene.cs index 3f8d0f7..2013302 100644 --- a/Blocktest/Code/Scenes/GameScene.cs +++ b/Blocktest/Code/Scenes/GameScene.cs @@ -1,4 +1,6 @@ +using Blocktest.Networking; using Microsoft.Xna.Framework.Input; +using Shared.Networking; namespace Blocktest.Scenes; public class GameScene : Scene { @@ -6,17 +8,21 @@ public class GameScene : Scene { private readonly SpriteBatch _spriteBatch; private FrameCounter _frameCounter = new FrameCounter(); private readonly SpriteFont _spriteFont; + + private Client networkingClient = new(); //TODO - Add config or vars bool latch = false; //latch for button pressing private bool latchBlockSelect = false; //same but for block selection bool buildMode = true; //true for build, false for destroy - private int blockSelected = 0; //ID of the block to place + private int blockSelected = 1; //ID of the block to place public void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) { _game.Exit(); } + networkingClient.Update(); + //press E to toggle build/destroy if (Keyboard.GetState().IsKeyUp(Keys.E)) { @@ -41,7 +47,7 @@ public void Update(GameTime gameTime) { blockSelected++; if (blockSelected >= BlockManagerShared.AllBlocks.Length) { - blockSelected = 0; + blockSelected = 1; } latchBlockSelect = true; @@ -74,7 +80,7 @@ public void Update(GameTime gameTime) { MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY))); } } - + Globals.clientTickBuffer.IncrCurrTick(); } public void Draw(GameTime gameTime, GraphicsDevice graphicsDevice) { @@ -82,8 +88,8 @@ public void Draw(GameTime gameTime, GraphicsDevice graphicsDevice) { _spriteBatch.Begin(); - Globals.BackgroundTilemapSprites.Draw(_spriteBatch); - Globals.ForegroundTilemapSprites.Draw(_spriteBatch); + Globals.BackgroundTilemapSprites.DrawAllTiles(_spriteBatch); + Globals.ForegroundTilemapSprites.DrawAllTiles(_spriteBatch); var deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; @@ -111,15 +117,21 @@ public GameScene(BlocktestGame game) { Globals.BackgroundTilemapSprites = new(GlobalsShared.BackgroundTilemap); Globals.ForegroundTilemapSprites = new(GlobalsShared.ForegroundTilemap); + networkingClient.Start("localhost", 9050, "testKey"); + + /*WorldDownload testDownload = new(); + int[,,] newWorld = new int[GlobalsShared.maxX, GlobalsShared.maxY, 2]; for (int i = 0; i < GlobalsShared.maxX; i++) { - newWorld[i, 5, 1] = 3; - newWorld[i, 4, 1] = 1; - newWorld[i, 3, 1] = 1; - newWorld[i, 2, 1] = 1; - newWorld[i, 1, 1] = 1; - newWorld[i, 0, 1] = 2; + newWorld[i, 5, 1] = 4; + newWorld[i, 4, 1] = 2; + newWorld[i, 3, 1] = 2; + newWorld[i, 2, 1] = 2; + newWorld[i, 1, 1] = 2; + newWorld[i, 0, 1] = 3; } - BuildSystem.LoadNewWorld(newWorld); + testDownload.world = newWorld; + testDownload.tickNum = 1; + testDownload.Process();*/ } } \ No newline at end of file diff --git a/Blocktest/Content/Graphics/Blocks/air.png b/Blocktest/Content/Graphics/Blocks/air.png new file mode 100644 index 0000000000000000000000000000000000000000..c1d1a38619c3f04f08fce926a76712a2deffadd5 GIT binary patch literal 101 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC#^NA%Cx&(BWL^R}@}4e^AsLNt o4>B?Wc})uc*XMaSfS6#Q&!%F)z}WZtKst!)>FVdQ&MBb@0Qor _sampleBuffer = new(); + + public void Update(float deltaTime) + { + CurrentFramesPerSecond = 1.0f / deltaTime; + + _sampleBuffer.Enqueue(CurrentFramesPerSecond); + + if (_sampleBuffer.Count > MaximumSamples) + { + _sampleBuffer.Dequeue(); + AverageFramesPerSecond = _sampleBuffer.Average(i => i); + } + else + { + AverageFramesPerSecond = CurrentFramesPerSecond; + } + + TotalFrames++; + TotalSeconds += deltaTime; + } + } +} \ No newline at end of file diff --git a/DedicatedServer/Code/Networking/Server.cs b/DedicatedServer/Code/Networking/Server.cs new file mode 100644 index 0000000..8afba21 --- /dev/null +++ b/DedicatedServer/Code/Networking/Server.cs @@ -0,0 +1,57 @@ +using System.Net.Sockets; +using LiteNetLib; +using LiteNetLib.Utils; +using Shared; +using Shared.Networking; + +namespace Blocktest.Networking +{ + public class Server + { + private EventBasedNetListener listener = new(); + private NetManager manager; + private ServerPlayerManager playerManager; + + public Server() + { + manager = new(listener); + playerManager = new(GlobalsShared.MaxPlayers); + listener.ConnectionRequestEvent += NewConnection; + listener.PeerConnectedEvent += NewPeer; + } + + public void Start() + { + manager.Start(9050); + } + public void Update() + { + manager.PollEvents(); + } + + protected void NewConnection(ConnectionRequest request) + { + Console.WriteLine("New Connection"); + if(playerManager.playerCount < GlobalsShared.MaxPlayers) + { + request.AcceptIfKey("testKey"); + } + else + { + request.Reject(); + } + } + + protected void NewPeer(NetPeer peer) + { + Console.WriteLine("New Peer"); + playerManager.addPlayer(peer); + NetDataWriter writer = new(); + WorldDownload worldDownload = new(); + worldDownload.world = BuildSystem.getCurrentWorld(); + worldDownload.tickNum = GlobalsServer.serverTickBuffer.currTick; + writer.Put(worldDownload); + peer.Send(writer, DeliveryMethod.ReliableOrdered); + } + } +} \ No newline at end of file diff --git a/DedicatedServer/Code/Networking/ServerPlayerManager.cs b/DedicatedServer/Code/Networking/ServerPlayerManager.cs new file mode 100644 index 0000000..294bc4c --- /dev/null +++ b/DedicatedServer/Code/Networking/ServerPlayerManager.cs @@ -0,0 +1,38 @@ +using LiteNetLib; +using LiteNetLib.Utils; +using System.Collections; +using System.Collections.Generic; + +namespace Blocktest.Networking +{ + public class ServerPlayerManager : IEnumerable + { + private NetPeer[] playerList; + public int playerCount; + private int playerNum = 0; + + public ServerPlayerManager(int maxPlayers) + { + playerList = new NetPeer[maxPlayers]; + } + + public IEnumerator GetEnumerator() + { + for(int i = 0; i < playerCount; i++) + { + yield return playerList[i]; + } + } + + public void addPlayer(NetPeer newPlayer) + { + playerList[playerNum] = newPlayer; + playerNum++; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/DedicatedServer/Code/WorldHandler.cs b/DedicatedServer/Code/WorldHandler.cs new file mode 100644 index 0000000..79fab8d --- /dev/null +++ b/DedicatedServer/Code/WorldHandler.cs @@ -0,0 +1,69 @@ +using System; +using System.Diagnostics; +using System.Threading; +using Blocktest.Networking; + +namespace Blocktest +{ + class WorldHandler + { + private readonly object locker = new(); + private int counter = 0; + private Stopwatch stopwatch; + private TimeSpan targetTime = TimeSpan.FromTicks(166667); + private TimeSpan currentTime = TimeSpan.Zero; + private FrameCounter _frameCounter = new FrameCounter(); + + private Server server; + + private int continueRun = 1; + private long previousTicks = 0; + private long currentTicks = 0; + private bool continueWait = true; + + public WorldHandler() + { + server = new(); + stopwatch = new(); + } + + public void Run() + { + server.Start(); + stopwatch.Start(); + Loop(); + } + + protected void Loop() + { + System.Threading.Timer timer = new(Tick, _frameCounter, TimeSpan.Zero, targetTime); + //System.Threading.Timer timer = new(Tick, _frameCounter, 16, 16); + while(Interlocked.Exchange(ref continueRun, 1) == 1) + { + //Tick(); + //WaitHandler(); + Thread.Sleep(1000); + } + } + + protected void Tick(Object? state) + { + lock(locker) + { + /*currentTicks = stopwatch.ElapsedTicks; + long test = currentTicks - previousTicks; + Console.WriteLine("CurrentMilliseconds = " + test / 1000000); + Console.WriteLine("Current Tick = " + GlobalsServer.serverTickBuffer.currTick); + previousTicks = currentTicks; + counter++;*/ + server.Update(); + GlobalsServer.serverTickBuffer.IncrCurrTick(); + } + } + + public void Stop() + { + Interlocked.Exchange(ref continueRun, 0); + } + } +} \ No newline at end of file diff --git a/DedicatedServer/Program.cs b/DedicatedServer/Program.cs index 3751555..08c7b80 100644 --- a/DedicatedServer/Program.cs +++ b/DedicatedServer/Program.cs @@ -1,2 +1,5 @@ -// See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); +using Blocktest; + +//private TimeSpan _targetElapsedTime = TimeSpan.FromTicks(166667) +WorldHandler worldHandler = new(); +worldHandler.Run(); \ No newline at end of file diff --git a/Shared/Code/Block System/TilemapShared.cs b/Shared/Code/Block System/TilemapShared.cs index b95c100..95c0f8b 100644 --- a/Shared/Code/Block System/TilemapShared.cs +++ b/Shared/Code/Block System/TilemapShared.cs @@ -13,10 +13,6 @@ public class TilemapShared /// public TileShared?[,] tileGrid; /// - /// A list of all the tiles currently on the tilemap. - /// - public readonly List allTiles = new(); - /// /// The size of the tilemap in tiles. /// public readonly Vector2Int tilemapSize; @@ -39,6 +35,13 @@ public TilemapShared(int sizeX, int sizeY) { tilemapSize = new(sizeX, sizeY); tileGrid = new TileShared[sizeX, sizeY]; + for(int x = 0; x < sizeX; x++) + { + for(int y = 0; y < sizeY; y++) + { + tileGrid[x, y] = new TileShared(BlockManagerShared.AllBlocks[0], new Vector2Int(x, y)); //Fill with air + } + } } /// @@ -55,16 +58,9 @@ public TilemapShared(int sizeX, int sizeY) public TileShared SetTile(Vector2Int location, TileShared newTile) { TileShared oldTile = GetTile(location); - if (oldTile != null) { - allTiles.Remove(oldTile); - } tileGrid[location.X, location.Y] = newTile; - if (newTile != null) { - allTiles.Add(newTile); - } - foreach (Vector2Int dir in adjacencies) { if (location.X + dir.X < 0 || location.X + dir.X >= tilemapSize.X || location.Y + dir.Y < 0 || location.Y + dir.Y >= tilemapSize.Y) { continue; } tileGrid[location.X + dir.X, location.Y + dir.Y]?.UpdateAdjacencies(location + dir, this); @@ -136,7 +132,7 @@ public class TileShared /// /// The size of the tile square's edges, in pixels (Default 8) /// - protected int size = 8; + protected byte size = 8; /// /// The rectangle of the tile, used for sprite rendering and collisions. /// @@ -148,7 +144,7 @@ public class TileShared /// /// Used for bitmask smoothing, should MAYBE not be here. /// - public int bitmask = 0; + public byte bitmask = 0; /// /// Creates a . @@ -196,7 +192,7 @@ private bool HasSmoothableTile(Vector2Int position, TilemapShared tilemap) { TileShared otherTile = tilemap.GetTile(position); if (SourceBlock.smoothSelf) { return IsSameTileType(otherTile); } - return otherTile != null; + return otherTile != null && otherTile.SourceBlock.blockID != 0; // Don't smooth with air, possibly find nicer way to do this later. } /// diff --git a/Shared/Code/Blocks/Air.cs b/Shared/Code/Blocks/Air.cs new file mode 100644 index 0000000..b4c07fd --- /dev/null +++ b/Shared/Code/Blocks/Air.cs @@ -0,0 +1,13 @@ +namespace Shared.Blocks +{ + public class Air : BlockShared + { + public override void Initialize() + { + blockName = "Air"; + blockID = 0; + blockSmoothing = false; + base.Initialize(); + } + } +} \ No newline at end of file diff --git a/Shared/Code/Blocks/Asphalt.cs b/Shared/Code/Blocks/Asphalt.cs index 0236f79..502b8e9 100644 --- a/Shared/Code/Blocks/Asphalt.cs +++ b/Shared/Code/Blocks/Asphalt.cs @@ -5,7 +5,7 @@ public class Asphalt : BlockShared public override void Initialize() { blockName = "Asphalt"; - blockID = 9; + blockID = 10; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/Brick.cs b/Shared/Code/Blocks/Brick.cs index a40d4bf..8b2e7b4 100644 --- a/Shared/Code/Blocks/Brick.cs +++ b/Shared/Code/Blocks/Brick.cs @@ -5,7 +5,7 @@ public class Brick : BlockShared public override void Initialize() { blockName = "Brick"; - blockID = 10; + blockID = 11; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/Concrete.cs b/Shared/Code/Blocks/Concrete.cs index bc73ca5..1c03e04 100644 --- a/Shared/Code/Blocks/Concrete.cs +++ b/Shared/Code/Blocks/Concrete.cs @@ -5,7 +5,7 @@ public class Concrete : BlockShared public override void Initialize() { blockName = "Concrete"; - blockID = 14; + blockID = 15; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/Dirt.cs b/Shared/Code/Blocks/Dirt.cs index 1747627..35bacc0 100644 --- a/Shared/Code/Blocks/Dirt.cs +++ b/Shared/Code/Blocks/Dirt.cs @@ -5,7 +5,7 @@ public class Dirt : BlockShared public override void Initialize() { blockName = "Dirt"; - blockID = 0; + blockID = 1; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/GlassPane.cs b/Shared/Code/Blocks/GlassPane.cs index b45d0dd..47c0d3c 100644 --- a/Shared/Code/Blocks/GlassPane.cs +++ b/Shared/Code/Blocks/GlassPane.cs @@ -5,7 +5,7 @@ public class GlassPane : BlockShared public override void Initialize() { blockName = "Glass Pane"; - blockID = 4; + blockID = 5; blockSmoothing = true; smoothSelf = true; base.Initialize(); diff --git a/Shared/Code/Blocks/Grass.cs b/Shared/Code/Blocks/Grass.cs index ebe5ae5..75f25b9 100644 --- a/Shared/Code/Blocks/Grass.cs +++ b/Shared/Code/Blocks/Grass.cs @@ -5,7 +5,7 @@ public class Grass : BlockShared public override void Initialize() { blockName = "Grass"; - blockID = 1; + blockID = 2; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/LargeStoneBrick.cs b/Shared/Code/Blocks/LargeStoneBrick.cs index 9d2ef78..9cfbff3 100644 --- a/Shared/Code/Blocks/LargeStoneBrick.cs +++ b/Shared/Code/Blocks/LargeStoneBrick.cs @@ -5,7 +5,7 @@ public class LargeStoneBrick : BlockShared public override void Initialize() { blockName = "Large Stone Brick"; - blockID = 5; + blockID = 6; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/Log.cs b/Shared/Code/Blocks/Log.cs index 5153049..6cfac05 100644 --- a/Shared/Code/Blocks/Log.cs +++ b/Shared/Code/Blocks/Log.cs @@ -5,7 +5,7 @@ public class Log : BlockShared public override void Initialize() { blockName = "Log"; - blockID = 6; + blockID = 7; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/Pykrete.cs b/Shared/Code/Blocks/Pykrete.cs index ce412c6..ed3c707 100644 --- a/Shared/Code/Blocks/Pykrete.cs +++ b/Shared/Code/Blocks/Pykrete.cs @@ -5,7 +5,7 @@ public class Pykrete : BlockShared public override void Initialize() { blockName = "Pykrete"; - blockID = 8; + blockID = 9; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/SmoothMetal.cs b/Shared/Code/Blocks/SmoothMetal.cs index b9e79f1..50380b4 100644 --- a/Shared/Code/Blocks/SmoothMetal.cs +++ b/Shared/Code/Blocks/SmoothMetal.cs @@ -5,7 +5,7 @@ public class SmoothMetal : BlockShared public override void Initialize() { blockName = "Smooth Metal"; - blockID = 12; + blockID = 13; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/Stone.cs b/Shared/Code/Blocks/Stone.cs index a340364..ff90295 100644 --- a/Shared/Code/Blocks/Stone.cs +++ b/Shared/Code/Blocks/Stone.cs @@ -5,7 +5,7 @@ public class Stone : BlockShared public override void Initialize() { blockName = "Stone"; - blockID = 2; + blockID = 3; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/StoneBrick.cs b/Shared/Code/Blocks/StoneBrick.cs index 91fb616..ce08eba 100644 --- a/Shared/Code/Blocks/StoneBrick.cs +++ b/Shared/Code/Blocks/StoneBrick.cs @@ -5,7 +5,7 @@ public class StoneBrick : BlockShared public override void Initialize() { blockName = "Stone Brick"; - blockID = 7; + blockID = 8; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/StonePathBrick.cs b/Shared/Code/Blocks/StonePathBrick.cs index ffb13f5..223c3da 100644 --- a/Shared/Code/Blocks/StonePathBrick.cs +++ b/Shared/Code/Blocks/StonePathBrick.cs @@ -5,7 +5,7 @@ public class StonePathBrick : BlockShared public override void Initialize() { blockName = "Stone Path Brick"; - blockID = 13; + blockID = 14; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/WhiteSand.cs b/Shared/Code/Blocks/WhiteSand.cs index 7a1b622..c903674 100644 --- a/Shared/Code/Blocks/WhiteSand.cs +++ b/Shared/Code/Blocks/WhiteSand.cs @@ -5,7 +5,7 @@ public class WhiteSand : BlockShared public override void Initialize() { blockName = "White Sand"; - blockID = 15; + blockID = 16; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/Wood.cs b/Shared/Code/Blocks/Wood.cs index 6ff1405..487278a 100644 --- a/Shared/Code/Blocks/Wood.cs +++ b/Shared/Code/Blocks/Wood.cs @@ -5,7 +5,7 @@ public class Wood : BlockShared public override void Initialize() { blockName = "Wood"; - blockID = 3; + blockID = 4; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/Blocks/WoodPanel.cs b/Shared/Code/Blocks/WoodPanel.cs index 06238c7..8c46e0d 100644 --- a/Shared/Code/Blocks/WoodPanel.cs +++ b/Shared/Code/Blocks/WoodPanel.cs @@ -5,7 +5,7 @@ public class WoodPanel : BlockShared public override void Initialize() { blockName = "Wood Panel"; - blockID = 11; + blockID = 12; blockSmoothing = true; base.Initialize(); } diff --git a/Shared/Code/BuildSystem.cs b/Shared/Code/BuildSystem.cs index 01a22b4..eabfbe5 100644 --- a/Shared/Code/BuildSystem.cs +++ b/Shared/Code/BuildSystem.cs @@ -25,15 +25,22 @@ public static class BuildSystem /// The position of the block to destroy (grid coords) public static void BreakBlockCell(bool foreground, Vector2Int tilePosition) { + if(tilePosition.X >= GlobalsShared.maxX || tilePosition.Y >= GlobalsShared.maxY) + { + return; + } TilemapShared tilemap = foreground ? GlobalsShared.ForegroundTilemap : GlobalsShared.BackgroundTilemap; + + BlockShared toPlace = BlockManagerShared.AllBlocks[0]; + TileShared newTile = new(toPlace, tilePosition); if (tilemap.HasTile(tilePosition)) { int z = foreground ? 1 : 0; // Convert foreground bool to int tilemap.GetTile(tilePosition).SourceBlock.OnBreak(tilePosition, true); - tilemap.SetTile(tilePosition, null); - currentWorld[tilePosition.X, tilePosition.Y, z] = 0; + tilemap.SetTile(tilePosition, newTile); + currentWorld[tilePosition.X, tilePosition.Y, z] = 1; } else { @@ -57,6 +64,10 @@ public static void BreakBlockCell(bool foreground, Vector2Int tilePosition) /// The position of the placed block. (Grid coords) public static void PlaceBlockCell(BlockShared toPlace, bool foreground, Vector2Int tilePosition) { + if(tilePosition.X >= GlobalsShared.maxX || tilePosition.Y >= GlobalsShared.maxY) + { + return; + } TileShared newTile = new(toPlace, tilePosition); toPlace.OnPlace(tilePosition, foreground); @@ -115,7 +126,7 @@ private static void LoadNewBlock(int blockNum, Vector2Int tilePosition, int fore { currentWorld[tilePosition.X, tilePosition.Y, foregroundInt] = blockNum; bool foreground = Convert.ToBoolean(foregroundInt); - if(blockNum > 0) + if(blockNum > 1) { BlockShared newBlock = BlockManagerShared.AllBlocks[blockNum - 1]; PlaceBlockCell(newBlock, foreground, tilePosition); @@ -125,5 +136,10 @@ private static void LoadNewBlock(int blockNum, Vector2Int tilePosition, int fore BreakBlockCell(foreground, tilePosition); } } + + public static int[,,] getCurrentWorld() + { + return currentWorld; + } } } \ No newline at end of file diff --git a/Shared/Code/Networking/TickBuffer.cs b/Shared/Code/Networking/TickBuffer.cs index 3fe0dee..8ad4ad5 100644 --- a/Shared/Code/Networking/TickBuffer.cs +++ b/Shared/Code/Networking/TickBuffer.cs @@ -4,18 +4,24 @@ namespace Shared.Networking { public class TickBuffer { - private ushort currTick; + public ushort currTick; + private int currentDistance; private Tick[] tickBuffer = new Tick[GlobalsShared.MaxTicksStored]; public TickBuffer(ushort newTick) { currTick = newTick; + /*for(int i = 0; i < GlobalsShared.MaxTicksStored; i++) + { + tickBuffer[i] = new(GlobalsShared.ForegroundTilemap, GlobalsShared.BackgroundTilemap); + }*/ } /// /// Add additional tick /// - public void IncrCurrTick(Tick newTick) + public void IncrCurrTick() { + Tick newTick = new(GlobalsShared.ForegroundTilemap, GlobalsShared.BackgroundTilemap); currTick++; if(currTick == GlobalsShared.MaxTicksStored) { @@ -23,10 +29,71 @@ public void IncrCurrTick(Tick newTick) } tickBuffer[currTick] = newTick; } + + public void AddPackets(Packet[] newPackets) + { + currentDistance = 600; + ushort currentRecent = 0; + foreach(Packet packet in newPackets) + { + if(CheckRecentTick(packet.GetTickNum())) + { + currentRecent = packet.GetTickNum(); + } + AddPacket(packet); + } + ProcessTicks(currentRecent); + } - public void AddPacket(ushort tickNum, Packet newPacket) + private bool CheckRecentTick(ushort newTickNum) { - + int newTickDistance; + if(newTickNum < currTick) + { + newTickDistance = GlobalsShared.MaxTicksStored - currTick + newTickNum; + } + else + { + newTickDistance = newTickNum - currTick; + } + if(newTickDistance < currentDistance) + { + currentDistance = newTickDistance; + return true; + } + else + { + return false; + } + } + + public void ProcessTicks(ushort startTick) + { + if(startTick == currTick){return;} + Tick tick = tickBuffer[startTick]; + tick.ProcessStartTick(); + for(int i = startTick + 1; i != (currTick + 1); i++) + { + if(i == GlobalsShared.MaxTicksStored) + { + i = 0; + } + tick = tickBuffer[i]; + tick.ProcessTick(); + } + } + + private void AddPacket(Packet newPacket) + { + Console.WriteLine("Begin AddPacket"); + ushort tickNum = newPacket.GetTickNum(); + Console.WriteLine("Got ticknum"); + if(tickBuffer[tickNum] == null) + { + tickBuffer[tickNum] = new(GlobalsShared.ForegroundTilemap, GlobalsShared.BackgroundTilemap); + } + tickBuffer[tickNum].packets.Add(newPacket); + Console.WriteLine("End AddPacket"); } } } \ No newline at end of file diff --git a/Shared/Globals.cs b/Shared/Globals.cs index 23caf73..2cd16a2 100644 --- a/Shared/Globals.cs +++ b/Shared/Globals.cs @@ -1,4 +1,5 @@ using Shared; +using Shared.Networking; namespace Shared { @@ -16,14 +17,16 @@ public static class GlobalsShared public static TilemapShared BackgroundTilemap { get => backgroundTilemap; set => backgroundTilemap = value; } /// The maximum world size. (Width) - public static readonly int maxX = 255; + public static readonly int maxX = 100; /// The maximum world size. (Height) - public static readonly int maxY = 255; + public static readonly int maxY = 60; /// The size of the grid the game is played on. public static readonly Vector2Int gridSize = new(8, 8); /// The total number of ticks stored. 10 secs for now. public const int MaxTicksStored = 600; + + public const int MaxPlayers = 10; } } From 0689851bb3591f4cff942b5636e277533b07a44b Mon Sep 17 00:00:00 2001 From: SuperYodeler <51685082+Superyodeler@users.noreply.github.com> Date: Mon, 18 Sep 2023 19:59:16 -0400 Subject: [PATCH 4/9] Bugfixing, now able to transfer initial world download --- DedicatedServer/Code/WorldHandler.cs | 22 ++++++++++++++++++++++ Shared/Code/Networking/TickBuffer.cs | 4 ++-- Shared/Code/Packets/WorldDownload.cs | 2 ++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/DedicatedServer/Code/WorldHandler.cs b/DedicatedServer/Code/WorldHandler.cs index 79fab8d..0c70ffe 100644 --- a/DedicatedServer/Code/WorldHandler.cs +++ b/DedicatedServer/Code/WorldHandler.cs @@ -1,6 +1,9 @@ using System; using System.Diagnostics; using System.Threading; +using Shared; +using Shared.Networking; +using Blocktest; using Blocktest.Networking; namespace Blocktest @@ -23,8 +26,27 @@ class WorldHandler public WorldHandler() { + BlockManagerShared.Initialize(); + GlobalsShared.BackgroundTilemap = new TilemapShared(GlobalsShared.maxX, GlobalsShared.maxY); + GlobalsShared.ForegroundTilemap = new TilemapShared(GlobalsShared.maxX, GlobalsShared.maxY); + + WorldDownload testDownload = new(); + int[,,] newWorld = new int[GlobalsShared.maxX, GlobalsShared.maxY, 2]; + for (int i = 0; i < GlobalsShared.maxX; i++) { + newWorld[i, 5, 1] = 4; + newWorld[i, 4, 1] = 2; + newWorld[i, 3, 1] = 2; + newWorld[i, 2, 1] = 2; + newWorld[i, 1, 1] = 2; + newWorld[i, 0, 1] = 3; + } + testDownload.world = newWorld; + testDownload.tickNum = 1; + testDownload.Process(); + server = new(); stopwatch = new(); + } public void Run() diff --git a/Shared/Code/Networking/TickBuffer.cs b/Shared/Code/Networking/TickBuffer.cs index 8ad4ad5..a06427e 100644 --- a/Shared/Code/Networking/TickBuffer.cs +++ b/Shared/Code/Networking/TickBuffer.cs @@ -69,10 +69,10 @@ private bool CheckRecentTick(ushort newTickNum) public void ProcessTicks(ushort startTick) { - if(startTick == currTick){return;} + //if(startTick == currTick){return;} Tick tick = tickBuffer[startTick]; tick.ProcessStartTick(); - for(int i = startTick + 1; i != (currTick + 1); i++) + for(int i = startTick + 1; i != (currTick + 1); i++) // We want to process ticks if we start at a ticknum higher than the current { if(i == GlobalsShared.MaxTicksStored) { diff --git a/Shared/Code/Packets/WorldDownload.cs b/Shared/Code/Packets/WorldDownload.cs index 741fce2..862e65f 100644 --- a/Shared/Code/Packets/WorldDownload.cs +++ b/Shared/Code/Packets/WorldDownload.cs @@ -19,7 +19,9 @@ public ushort GetTickNum() } public void Process() { + Console.WriteLine("Begin Process"); BuildSystem.LoadNewWorld(this); + Console.WriteLine("End Process"); } public void Serialize(NetDataWriter writer) { From 7c0d348f97a8cd54183dfb838fa78115c5ccbad3 Mon Sep 17 00:00:00 2001 From: SuperYodeler <51685082+Superyodeler@users.noreply.github.com> Date: Sun, 24 Sep 2023 21:02:26 -0400 Subject: [PATCH 5/9] Finally in a good enough state to pr, just need to handle the merge conflicts now. --- Blocktest/BlocktestGame.cs | 18 ++- Blocktest/Code/Globals.cs | 1 + Blocktest/Code/Networking/Client.cs | 74 ++++++++++- Blocktest/Code/Scenes/GameScene.cs | 142 ++++++++++++++++------ Blocktest/Program.cs | 24 +++- DedicatedServer/Code/Networking/Server.cs | 62 +++++++++- DedicatedServer/Code/WorldHandler.cs | 2 +- README.md | 8 +- Shared/Code/BuildSystem.cs | 12 +- Shared/Code/Networking/Client.cs | 0 Shared/Code/Networking/TickBuffer.cs | 46 +++---- Shared/Code/Packets/Packet.cs | 7 ++ Shared/Globals.cs | 3 + 13 files changed, 312 insertions(+), 87 deletions(-) delete mode 100644 Shared/Code/Networking/Client.cs diff --git a/Blocktest/BlocktestGame.cs b/Blocktest/BlocktestGame.cs index ab46833..1c59e38 100644 --- a/Blocktest/BlocktestGame.cs +++ b/Blocktest/BlocktestGame.cs @@ -8,14 +8,30 @@ public class BlocktestGame : Game { private GraphicsDeviceManager _graphics; private Scene? _currentScene; + private bool connect; + private string ip; + /// public BlocktestGame() { + connect = false; + ip = ""; + _graphics = new GraphicsDeviceManager(this); + Content.RootDirectory = "Content"; + IsMouseVisible = true; + TargetElapsedTime = TimeSpan.FromMilliseconds(16); + } + + public BlocktestGame(string newIp) + { + connect = true; + ip = newIp; _graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; IsMouseVisible = true; + TargetElapsedTime = TimeSpan.FromMilliseconds(16); } /// @@ -29,7 +45,7 @@ protected override void LoadContent() { Drawable.ContentManager = Content; BlockSpritesManager.LoadBlockSprites(Content); - _currentScene = new GameScene(this); + _currentScene = new GameScene(this, connect, ip); } /// diff --git a/Blocktest/Code/Globals.cs b/Blocktest/Code/Globals.cs index e591610..7c1c97c 100644 --- a/Blocktest/Code/Globals.cs +++ b/Blocktest/Code/Globals.cs @@ -17,5 +17,6 @@ public static class Globals public static TilemapSprites BackgroundTilemapSprites { get => backgroundTilemapSprites; set => backgroundTilemapSprites = value; } public static TickBuffer clientTickBuffer = new(0); + } } diff --git a/Blocktest/Code/Networking/Client.cs b/Blocktest/Code/Networking/Client.cs index 0e69637..75b9959 100644 --- a/Blocktest/Code/Networking/Client.cs +++ b/Blocktest/Code/Networking/Client.cs @@ -28,22 +28,84 @@ public void Update() manager.PollEvents(); } + /// + /// Recieve network events from LiteNetLib + /// + /// The server the packet is coming from. + /// Contains the packet from the server. + /// + /// The delivery method used to deliver this packet. protected void NetworkRecieveEvent(NetPeer peer, NetPacketReader packetReader, byte channelNumber, DeliveryMethod deliveryMethod) { if(server == null) { - Console.WriteLine("Got first packet"); server = peer; WorldDownload worldPacket = new(); - worldPacket.Deserialize(packetReader); - Packet[] starterPacket = {worldPacket}; - Globals.clientTickBuffer = new(worldPacket.GetTickNum()); - Globals.clientTickBuffer.AddPackets(starterPacket); + byte packetByte = packetReader.GetByte(); + PacketType packetType = (PacketType)packetByte; + if(packetType == PacketType.WorldDownload) + { + worldPacket.Deserialize(packetReader); + Globals.clientTickBuffer = new(worldPacket.GetTickNum()); + Globals.clientTickBuffer.AddPacket(worldPacket); + } } else { - Console.WriteLine("Wrong packet"); + HandlePackets(packetReader); } } + + /// + /// Handles packets after the first. + /// + /// Contains the packet sent by the server. + public void HandlePackets(NetPacketReader packetReader) + { + byte packetByte = packetReader.GetByte(); + PacketType packetType = (PacketType)packetByte; + switch (packetType) + { + case PacketType.TileChange: + HandleTileChange(packetReader); + break; + case PacketType.BreakTile: + HandleBreakTile(packetReader); + break; + default: + Console.WriteLine("Bad packet!!!"); + break; + } + } + + private void HandleTileChange(NetPacketReader packetReader) + { + TileChange tileChange = new(); + tileChange.Deserialize(packetReader); + Globals.clientTickBuffer.AddPacket(tileChange); + } + + private void HandleBreakTile(NetPacketReader packetReader) + { + BreakTile breakTile = new(); + breakTile.Deserialize(packetReader); + Globals.clientTickBuffer.AddPacket(breakTile); + } + + public void SendTileChange(TileChange tileChange) + { + NetDataWriter writer = new(); + writer.Put((byte)PacketType.TileChange); + writer.Put(tileChange); + server.Send(writer, DeliveryMethod.ReliableUnordered); + } + + public void SendBreakTile(BreakTile breakTile) + { + NetDataWriter writer = new(); + writer.Put((byte)PacketType.BreakTile); + writer.Put(breakTile); + server.Send(writer, DeliveryMethod.ReliableUnordered); + } } } \ No newline at end of file diff --git a/Blocktest/Code/Scenes/GameScene.cs b/Blocktest/Code/Scenes/GameScene.cs index 2013302..6aaf2af 100644 --- a/Blocktest/Code/Scenes/GameScene.cs +++ b/Blocktest/Code/Scenes/GameScene.cs @@ -1,4 +1,5 @@ using Blocktest.Networking; +using LiteNetLib; using Microsoft.Xna.Framework.Input; using Shared.Networking; namespace Blocktest.Scenes; @@ -8,8 +9,8 @@ public class GameScene : Scene { private readonly SpriteBatch _spriteBatch; private FrameCounter _frameCounter = new FrameCounter(); private readonly SpriteFont _spriteFont; - - private Client networkingClient = new(); //TODO - Add config or vars + private bool connect; + private Client networkingClient = new(); bool latch = false; //latch for button pressing private bool latchBlockSelect = false; //same but for block selection @@ -21,28 +22,31 @@ public void Update(GameTime gameTime) { _game.Exit(); } - networkingClient.Update(); + if(connect) + { + networkingClient.Update(); + } + + //for block placement + MouseState currentState = Mouse.GetState(); //press E to toggle build/destroy if (Keyboard.GetState().IsKeyUp(Keys.E)) { latch = false; } - else if (latch == false) + else if (latch == false && CheckWindowActive(currentState)) { buildMode = !buildMode; latch = true; } - //for block placement - MouseState currentState = Mouse.GetState(); - //Q changes which block you have selected if (Keyboard.GetState().IsKeyUp(Keys.Q)) { latchBlockSelect = false; } - else if (latchBlockSelect == false) + else if (latchBlockSelect == false && CheckWindowActive(currentState)) { blockSelected++; if (blockSelected >= BlockManagerShared.AllBlocks.Length) @@ -56,28 +60,62 @@ public void Update(GameTime gameTime) { //build and destroy mode if (buildMode) { - if(currentState.LeftButton == ButtonState.Pressed) + if(currentState.LeftButton == ButtonState.Pressed && CheckWindowActive(currentState)) { - BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[blockSelected], true, - new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), - MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY))); - } else if (currentState.RightButton == ButtonState.Pressed) { - BuildSystem.PlaceBlockCell(BlockManagerShared.AllBlocks[blockSelected], false, - new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), - MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY))); + TileChange testChange = new() + { + tickNum = Globals.clientTickBuffer.currTick, + position = new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), + foreground = true, + blockId = blockSelected + }; + Globals.clientTickBuffer.AddPacket(testChange); + if(connect) + { + networkingClient.SendTileChange(testChange); + } + } else if (currentState.RightButton == ButtonState.Pressed && CheckWindowActive(currentState)) { + TileChange testChange = new() + { + tickNum = Globals.clientTickBuffer.currTick, + position = new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), + foreground = false, + blockId = blockSelected + }; + Globals.clientTickBuffer.AddPacket(testChange); + if(connect) + { + networkingClient.SendTileChange(testChange); + } } } else { - if(currentState.LeftButton == ButtonState.Pressed) + if(currentState.LeftButton == ButtonState.Pressed && CheckWindowActive(currentState)) { - BuildSystem.BreakBlockCell( true, - new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), - MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY))); - } else if (currentState.RightButton == ButtonState.Pressed) { - BuildSystem.BreakBlockCell( false, - new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), - MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY))); + BreakTile testBreak = new() + { + tickNum = Globals.clientTickBuffer.currTick, + position = new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), + foreground = true + }; + Globals.clientTickBuffer.AddPacket(testBreak); + if(connect) + { + networkingClient.SendBreakTile(testBreak); + } + } else if (currentState.RightButton == ButtonState.Pressed && CheckWindowActive(currentState)) { + BreakTile testBreak = new() + { + tickNum = Globals.clientTickBuffer.currTick, + position = new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), + foreground = false + }; + Globals.clientTickBuffer.AddPacket(testBreak); + if(connect) + { + networkingClient.SendBreakTile(testBreak); + } } } Globals.clientTickBuffer.IncrCurrTick(); @@ -108,7 +146,8 @@ public void Draw(GameTime gameTime, GraphicsDevice graphicsDevice) { _spriteBatch.End(); } - public GameScene(BlocktestGame game) { + public GameScene(BlocktestGame game, bool doConnect, string ip) { + connect = doConnect; _spriteBatch = new SpriteBatch(game.GraphicsDevice); _game = game; @@ -117,21 +156,46 @@ public GameScene(BlocktestGame game) { Globals.BackgroundTilemapSprites = new(GlobalsShared.BackgroundTilemap); Globals.ForegroundTilemapSprites = new(GlobalsShared.ForegroundTilemap); - networkingClient.Start("localhost", 9050, "testKey"); - - /*WorldDownload testDownload = new(); + if(connect) + { + //networkingClient.Start("localhost", 9050, "testKey"); + networkingClient.Start(ip, 9050, "testKey"); + } + else + { + WorldDownload testDownload = new(); + + int[,,] newWorld = new int[GlobalsShared.maxX, GlobalsShared.maxY, 2]; + for (int i = 0; i < GlobalsShared.maxX; i++) { + newWorld[i, 5, 1] = 4; + newWorld[i, 4, 1] = 2; + newWorld[i, 3, 1] = 2; + newWorld[i, 2, 1] = 2; + newWorld[i, 1, 1] = 2; + newWorld[i, 0, 1] = 3; + } + testDownload.world = newWorld; + testDownload.tickNum = 1; + testDownload.Process(); + } + + } - int[,,] newWorld = new int[GlobalsShared.maxX, GlobalsShared.maxY, 2]; - for (int i = 0; i < GlobalsShared.maxX; i++) { - newWorld[i, 5, 1] = 4; - newWorld[i, 4, 1] = 2; - newWorld[i, 3, 1] = 2; - newWorld[i, 2, 1] = 2; - newWorld[i, 1, 1] = 2; - newWorld[i, 0, 1] = 3; + /// + /// Checks if the window is active and the mouse is within the window. + /// + /// The current state of the mouse + /// True if the window is active and the mouse is within the window. + private bool CheckWindowActive(MouseState mouse) + { + Point pos = new(mouse.X, mouse.Y); + if(_game.IsActive && _game.GraphicsDevice.Viewport.Bounds.Contains(pos)) + { + return true; + } + else + { + return false; } - testDownload.world = newWorld; - testDownload.tickNum = 1; - testDownload.Process();*/ } } \ No newline at end of file diff --git a/Blocktest/Program.cs b/Blocktest/Program.cs index 106e490..73f7f09 100644 --- a/Blocktest/Program.cs +++ b/Blocktest/Program.cs @@ -1,4 +1,24 @@ using Blocktest; -using BlocktestGame game = new(); -game.Run(); \ No newline at end of file +public class Program +{ + static public void Main(String[] args) + { + int argLength = args.Length; + if(argLength == 2) + { + String argument = args[0]; // This can be cleaned up, may want to use a config object + String value = args[1]; + if(argument.Equals("connect")) + { + using BlocktestGame game = new(value); + game.Run(); + } + } + else + { + using BlocktestGame game = new(); + game.Run(); + } + } +} diff --git a/DedicatedServer/Code/Networking/Server.cs b/DedicatedServer/Code/Networking/Server.cs index 8afba21..aaade08 100644 --- a/DedicatedServer/Code/Networking/Server.cs +++ b/DedicatedServer/Code/Networking/Server.cs @@ -18,6 +18,7 @@ public Server() playerManager = new(GlobalsShared.MaxPlayers); listener.ConnectionRequestEvent += NewConnection; listener.PeerConnectedEvent += NewPeer; + listener.NetworkReceiveEvent += NetworkRecieveEvent; } public void Start() @@ -42,16 +43,71 @@ protected void NewConnection(ConnectionRequest request) } } + /// + /// Adds a new player to the playerManager and sends them the current world. + /// + /// The new player protected void NewPeer(NetPeer peer) { Console.WriteLine("New Peer"); playerManager.addPlayer(peer); NetDataWriter writer = new(); - WorldDownload worldDownload = new(); - worldDownload.world = BuildSystem.getCurrentWorld(); - worldDownload.tickNum = GlobalsServer.serverTickBuffer.currTick; + WorldDownload worldDownload = new() + { + world = BuildSystem.getCurrentWorld(), + tickNum = GlobalsServer.serverTickBuffer.currTick + }; + writer.Put((byte)PacketType.WorldDownload); writer.Put(worldDownload); peer.Send(writer, DeliveryMethod.ReliableOrdered); } + + /// + /// Recieve network events from LiteNetLib + /// + /// The client the packet is coming from. + /// Contains the packet from the client. + /// + /// The delivery method used to deliver this packet. + private void NetworkRecieveEvent(NetPeer peer, NetPacketReader packetReader, byte channelNumber, DeliveryMethod deliveryMethod) + { + byte packetByte = packetReader.GetByte(); + PacketType packetType = (PacketType) packetByte; + switch (packetType) + { + case PacketType.TileChange: + HandleTileChange(packetReader, peer); + break; + case PacketType.BreakTile: + HandleBreakTile(packetReader, peer); + break; + default: + Console.WriteLine("Bad packet!!!"); + break; + } + } + + private void HandleTileChange(NetPacketReader packetReader, NetPeer peer) + { + TileChange tileChange = new(); + tileChange.Deserialize(packetReader); + GlobalsServer.serverTickBuffer.AddPacket(tileChange); + + NetDataWriter writer = new(); + writer.Put((byte)PacketType.TileChange); + writer.Put(tileChange); + manager.SendToAll(writer, DeliveryMethod.ReliableUnordered, peer); // For now, just exclude the one who sent it. + } + + private void HandleBreakTile(NetPacketReader packetReader, NetPeer peer) + { + BreakTile breakTile = new(); + breakTile.Deserialize(packetReader); + GlobalsServer.serverTickBuffer.AddPacket(breakTile); + NetDataWriter writer = new(); + writer.Put((byte)PacketType.BreakTile); + writer.Put(breakTile); + manager.SendToAll(writer, DeliveryMethod.ReliableUnordered, peer); // For now, just exclude the one who sent it. + } } } \ No newline at end of file diff --git a/DedicatedServer/Code/WorldHandler.cs b/DedicatedServer/Code/WorldHandler.cs index 0c70ffe..edbdb11 100644 --- a/DedicatedServer/Code/WorldHandler.cs +++ b/DedicatedServer/Code/WorldHandler.cs @@ -13,7 +13,7 @@ class WorldHandler private readonly object locker = new(); private int counter = 0; private Stopwatch stopwatch; - private TimeSpan targetTime = TimeSpan.FromTicks(166667); + private TimeSpan targetTime = TimeSpan.FromMilliseconds(16); private TimeSpan currentTime = TimeSpan.Zero; private FrameCounter _frameCounter = new FrameCounter(); diff --git a/README.md b/README.md index 6ad5d07..120c712 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,10 @@ A currently highly indev project aiming to give the experience of games like Ter Find the latest releases [here](https://github.com/blocktest-game/blocktest-MonoGame/releases). All you need to do is download the correct file for your system, unzip the file, and run the executable. +## Running the game + +Blocktest will run in local mode by default. To connect to a server, it must be run with the arguments "connect \". For localhost this is "connect localhost". + ## Contributing 1. Follow MonoGame's [getting started guide](https://docs.monogame.net/articles/getting_started/0_getting_started.html) @@ -23,8 +27,8 @@ Find the latest releases [here](https://github.com/blocktest-game/blocktest-Mono 3. Clone your fork with [git](https://git-scm.com) 4. Open solution file (Blocktest.sln) in Visual Studio 5. Edit the code -5. Commit and push all the changes you want with git -6. Make a pull request! +6. Commit and push all the changes you want with git +7. Make a pull request! ## Reporting issues diff --git a/Shared/Code/BuildSystem.cs b/Shared/Code/BuildSystem.cs index eabfbe5..d764154 100644 --- a/Shared/Code/BuildSystem.cs +++ b/Shared/Code/BuildSystem.cs @@ -68,17 +68,17 @@ public static void PlaceBlockCell(BlockShared toPlace, bool foreground, Vector2I { return; } - TileShared newTile = new(toPlace, tilePosition); + TileShared newTile = new(toPlace, tilePosition); // TODO - remove new toPlace.OnPlace(tilePosition, foreground); if (foreground) { //newTile.colliderType = Tile.ColliderType.Grid; GlobalsShared.ForegroundTilemap.SetTile(tilePosition, newTile); - currentWorld[tilePosition.X, tilePosition.Y, 0] = toPlace.blockID + 1; + currentWorld[tilePosition.X, tilePosition.Y, 1] = toPlace.blockID + 1; } else if (toPlace.canPlaceBackground) { - newTile.color = new Color(0.5f, 0.5f, 0.5f, 1f); + newTile.color = GlobalsShared.backgroundColor; GlobalsShared.BackgroundTilemap.SetTile(tilePosition, newTile); - currentWorld[tilePosition.X, tilePosition.Y, 1] = toPlace.blockID + 1; + currentWorld[tilePosition.X, tilePosition.Y, 0] = toPlace.blockID + 1; } } @@ -121,7 +121,9 @@ public static void LoadNewWorld(int[,,] newWorld) /// /// The blockid + 1 /// The position of the tile in the tilemap - /// Whether the block is in the foreground, expressed as an int + /// Whether the blo + //Console.WriteLine("Current tick: " + currTick); + //Console.WriteLine("i: " + i);ck is in the foreground, expressed as an int private static void LoadNewBlock(int blockNum, Vector2Int tilePosition, int foregroundInt) { currentWorld[tilePosition.X, tilePosition.Y, foregroundInt] = blockNum; diff --git a/Shared/Code/Networking/Client.cs b/Shared/Code/Networking/Client.cs deleted file mode 100644 index e69de29..0000000 diff --git a/Shared/Code/Networking/TickBuffer.cs b/Shared/Code/Networking/TickBuffer.cs index a06427e..f50f543 100644 --- a/Shared/Code/Networking/TickBuffer.cs +++ b/Shared/Code/Networking/TickBuffer.cs @@ -6,21 +6,26 @@ public class TickBuffer { public ushort currTick; private int currentDistance; + private ushort currentRecent; private Tick[] tickBuffer = new Tick[GlobalsShared.MaxTicksStored]; public TickBuffer(ushort newTick) { currTick = newTick; - /*for(int i = 0; i < GlobalsShared.MaxTicksStored; i++) + for(int i = 0; i < GlobalsShared.MaxTicksStored; i++) { tickBuffer[i] = new(GlobalsShared.ForegroundTilemap, GlobalsShared.BackgroundTilemap); - }*/ + } + currentDistance = 0; + currentRecent = currTick; } /// /// Add additional tick /// public void IncrCurrTick() { + //tickBuffer[currTick].ProcessStartTick(); + ProcessTicks(currentRecent); Tick newTick = new(GlobalsShared.ForegroundTilemap, GlobalsShared.BackgroundTilemap); currTick++; if(currTick == GlobalsShared.MaxTicksStored) @@ -28,37 +33,25 @@ public void IncrCurrTick() currTick = 0; } tickBuffer[currTick] = newTick; - } - - public void AddPackets(Packet[] newPackets) - { - currentDistance = 600; - ushort currentRecent = 0; - foreach(Packet packet in newPackets) - { - if(CheckRecentTick(packet.GetTickNum())) - { - currentRecent = packet.GetTickNum(); - } - AddPacket(packet); - } - ProcessTicks(currentRecent); + currentDistance = 0; + currentRecent = currTick; } - private bool CheckRecentTick(ushort newTickNum) + private bool CheckFurthestTick(ushort newTickNum) { int newTickDistance; - if(newTickNum < currTick) + if(newTickNum > currTick) { - newTickDistance = GlobalsShared.MaxTicksStored - currTick + newTickNum; + newTickDistance = GlobalsShared.MaxTicksStored - newTickNum + currTick; } else { - newTickDistance = newTickNum - currTick; + newTickDistance = currTick - newTickNum; } - if(newTickDistance < currentDistance) + if(newTickDistance > currentDistance) { currentDistance = newTickDistance; + currentRecent = newTickNum; return true; } else @@ -69,10 +62,9 @@ private bool CheckRecentTick(ushort newTickNum) public void ProcessTicks(ushort startTick) { - //if(startTick == currTick){return;} Tick tick = tickBuffer[startTick]; tick.ProcessStartTick(); - for(int i = startTick + 1; i != (currTick + 1); i++) // We want to process ticks if we start at a ticknum higher than the current + for(int i = startTick + 1; i != (currTick + 1); i++) { if(i == GlobalsShared.MaxTicksStored) { @@ -83,17 +75,15 @@ public void ProcessTicks(ushort startTick) } } - private void AddPacket(Packet newPacket) + public void AddPacket(Packet newPacket) { - Console.WriteLine("Begin AddPacket"); + CheckFurthestTick(newPacket.GetTickNum()); ushort tickNum = newPacket.GetTickNum(); - Console.WriteLine("Got ticknum"); if(tickBuffer[tickNum] == null) { tickBuffer[tickNum] = new(GlobalsShared.ForegroundTilemap, GlobalsShared.BackgroundTilemap); } tickBuffer[tickNum].packets.Add(newPacket); - Console.WriteLine("End AddPacket"); } } } \ No newline at end of file diff --git a/Shared/Code/Packets/Packet.cs b/Shared/Code/Packets/Packet.cs index b3399d8..b8e9fdf 100644 --- a/Shared/Code/Packets/Packet.cs +++ b/Shared/Code/Packets/Packet.cs @@ -3,6 +3,13 @@ namespace Shared.Networking { + public enum PacketType : byte + { + WorldDownload, + BreakTile, + TileChange + } + public interface Packet : INetSerializable { /// diff --git a/Shared/Globals.cs b/Shared/Globals.cs index 2cd16a2..5cb8cac 100644 --- a/Shared/Globals.cs +++ b/Shared/Globals.cs @@ -1,3 +1,4 @@ +using Microsoft.Xna.Framework; using Shared; using Shared.Networking; @@ -16,6 +17,8 @@ public static class GlobalsShared /// Tilemap for background (non-dense) objects. public static TilemapShared BackgroundTilemap { get => backgroundTilemap; set => backgroundTilemap = value; } + public static Color backgroundColor = new Color(0.5f, 0.5f, 0.5f, 1f); + /// The maximum world size. (Width) public static readonly int maxX = 100; /// The maximum world size. (Height) From 0f47341b88b403454b5c830ad91dae4e81b99add Mon Sep 17 00:00:00 2001 From: SuperYodeler <51685082+Superyodeler@users.noreply.github.com> Date: Sun, 24 Sep 2023 21:30:53 -0400 Subject: [PATCH 6/9] Adds a bit of info to the readme and corrects the world generation for the server. Also removes a couple of logging statements. --- DedicatedServer/Code/WorldHandler.cs | 12 ++++++------ README.md | 4 ++++ Shared/Code/Packets/WorldDownload.cs | 2 -- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/DedicatedServer/Code/WorldHandler.cs b/DedicatedServer/Code/WorldHandler.cs index edbdb11..178ad7d 100644 --- a/DedicatedServer/Code/WorldHandler.cs +++ b/DedicatedServer/Code/WorldHandler.cs @@ -33,12 +33,12 @@ public WorldHandler() WorldDownload testDownload = new(); int[,,] newWorld = new int[GlobalsShared.maxX, GlobalsShared.maxY, 2]; for (int i = 0; i < GlobalsShared.maxX; i++) { - newWorld[i, 5, 1] = 4; - newWorld[i, 4, 1] = 2; - newWorld[i, 3, 1] = 2; - newWorld[i, 2, 1] = 2; - newWorld[i, 1, 1] = 2; - newWorld[i, 0, 1] = 3; + newWorld[i, 59, 1] = 4; + newWorld[i, 58, 1] = 2; + newWorld[i, 57, 1] = 2; + newWorld[i, 56, 1] = 2; + newWorld[i, 55, 1] = 2; + newWorld[i, 54, 1] = 3; } testDownload.world = newWorld; testDownload.tickNum = 1; diff --git a/README.md b/README.md index 120c712..8bc20a1 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,10 @@ Blocktest will run in local mode by default. To connect to a server, it must be 6. Commit and push all the changes you want with git 7. Make a pull request! +### Compiling after making change to shared folder + +After making a change to the shared project, you may need to use the "dotnet clean" and "dotnet build" commands on the shared project to make the changes appear in your dev environment. + ## Reporting issues To report an issue, please fill out a bug report [here](https://github.com/blocktest-game/blocktest-MonoGame/issues/new?assignees=&labels=bug&template=bug_report.md&title=%5BBUG%5D) so that developers can quickly respond to the bug. diff --git a/Shared/Code/Packets/WorldDownload.cs b/Shared/Code/Packets/WorldDownload.cs index 862e65f..741fce2 100644 --- a/Shared/Code/Packets/WorldDownload.cs +++ b/Shared/Code/Packets/WorldDownload.cs @@ -19,9 +19,7 @@ public ushort GetTickNum() } public void Process() { - Console.WriteLine("Begin Process"); BuildSystem.LoadNewWorld(this); - Console.WriteLine("End Process"); } public void Serialize(NetDataWriter writer) { From 8f000fa991ead3a9c8b6ba672ff1d9c6bc55e012 Mon Sep 17 00:00:00 2001 From: SuperYodeler <51685082+Superyodeler@users.noreply.github.com> Date: Wed, 27 Sep 2023 21:18:26 -0400 Subject: [PATCH 7/9] Monogame.extended camera --- Blocktest/Blocktest.csproj | 1 + Blocktest/BlocktestGame.cs | 10 ++- Blocktest/Code/Block System/TilemapSprites.cs | 5 -- Blocktest/Code/Scenes/GameScene.cs | 67 ++++++++++++++++--- Blocktest/packages.lock.json | 14 ++++ Shared/Code/BuildSystem.cs | 16 ----- 6 files changed, 81 insertions(+), 32 deletions(-) diff --git a/Blocktest/Blocktest.csproj b/Blocktest/Blocktest.csproj index df3aee1..4fd0f73 100644 --- a/Blocktest/Blocktest.csproj +++ b/Blocktest/Blocktest.csproj @@ -23,6 +23,7 @@ + diff --git a/Blocktest/BlocktestGame.cs b/Blocktest/BlocktestGame.cs index 1c59e38..161b802 100644 --- a/Blocktest/BlocktestGame.cs +++ b/Blocktest/BlocktestGame.cs @@ -1,11 +1,14 @@ using Blocktest.Rendering; using Blocktest.Scenes; +using MonoGame.Extended; +using MonoGame.Extended.ViewportAdapters; namespace Blocktest { /// public class BlocktestGame : Game { + private OrthographicCamera _camera; private GraphicsDeviceManager _graphics; private Scene? _currentScene; private bool connect; @@ -43,9 +46,14 @@ protected override void Initialize() { /// protected override void LoadContent() { + + BoxingViewportAdapter viewportAdapter = new(Window, GraphicsDevice, 800, 480); + _camera = new(viewportAdapter); + Console.WriteLine("Camera init"); Drawable.ContentManager = Content; BlockSpritesManager.LoadBlockSprites(Content); - _currentScene = new GameScene(this, connect, ip); + Console.WriteLine("LoadContent"); + _currentScene = new GameScene(this, _camera, connect, ip); } /// diff --git a/Blocktest/Code/Block System/TilemapSprites.cs b/Blocktest/Code/Block System/TilemapSprites.cs index 597fe89..b23e8d5 100644 --- a/Blocktest/Code/Block System/TilemapSprites.cs +++ b/Blocktest/Code/Block System/TilemapSprites.cs @@ -38,11 +38,6 @@ public void DrawAllTiles(SpriteBatch spriteBatch) spriteBatch.Draw(sprite.Texture, new Vector2(tile.rectangle.X, tile.rectangle.Y), sprite.Bounds, tile.color); } } - /*foreach (TileShared tile in tilemap.allTiles) { - BlockSprites blockSprites = BlockSpritesManager.AllBlocksSprites[tile.SourceBlock.blockID]; - Drawable sprite = blockSprites.spriteSheet.OrderedSprites[tile.bitmask]; - spriteBatch.Draw(sprite.Texture, new Vector2(tile.rectangle.X, tile.rectangle.Y), sprite.Bounds, tile.color); - }*/ } } } diff --git a/Blocktest/Code/Scenes/GameScene.cs b/Blocktest/Code/Scenes/GameScene.cs index a94c763..35d4e15 100644 --- a/Blocktest/Code/Scenes/GameScene.cs +++ b/Blocktest/Code/Scenes/GameScene.cs @@ -2,10 +2,13 @@ using LiteNetLib; using Microsoft.Xna.Framework.Input; using Shared.Networking; +using MonoGame.Extended; +using MonoGame.Extended.ViewportAdapters; namespace Blocktest.Scenes; public class GameScene : Scene { private readonly BlocktestGame _game; + private OrthographicCamera _camera; private readonly SpriteBatch _spriteBatch; private FrameCounter _frameCounter = new FrameCounter(); private readonly SpriteFont _spriteFont; @@ -29,9 +32,13 @@ public void Update(GameTime gameTime) { //for block placement MouseState currentState = Mouse.GetState(); + KeyboardState keyboardState = Keyboard.GetState(); + Vector2 _worldPosition = _camera.ScreenToWorld(new Vector2(currentState.X, currentState.Y)); + + _camera.Move(CameraMovement(keyboardState)); //press E to toggle build/destroy - if (Keyboard.GetState().IsKeyUp(Keys.E)) + if (keyboardState.IsKeyUp(Keys.E)) { latch = false; } @@ -42,7 +49,7 @@ public void Update(GameTime gameTime) { } //Q changes which block you have selected - if (Keyboard.GetState().IsKeyUp(Keys.Q)) + if (keyboardState.IsKeyUp(Keys.Q)) { latchBlockSelect = false; } @@ -65,7 +72,7 @@ public void Update(GameTime gameTime) { TileChange testChange = new() { tickNum = Globals.clientTickBuffer.currTick, - position = new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), + position = new Vector2Int(MathHelper.Clamp(_worldPosition.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(_worldPosition.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), foreground = true, blockId = blockSelected }; @@ -78,7 +85,7 @@ public void Update(GameTime gameTime) { TileChange testChange = new() { tickNum = Globals.clientTickBuffer.currTick, - position = new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), + position = new Vector2Int(MathHelper.Clamp(_worldPosition.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(_worldPosition.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), foreground = false, blockId = blockSelected }; @@ -96,7 +103,7 @@ public void Update(GameTime gameTime) { BreakTile testBreak = new() { tickNum = Globals.clientTickBuffer.currTick, - position = new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), + position = new Vector2Int(MathHelper.Clamp(_worldPosition.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(_worldPosition.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), foreground = true }; Globals.clientTickBuffer.AddPacket(testBreak); @@ -108,7 +115,7 @@ public void Update(GameTime gameTime) { BreakTile testBreak = new() { tickNum = Globals.clientTickBuffer.currTick, - position = new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), + position = new Vector2Int(MathHelper.Clamp(_worldPosition.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(_worldPosition.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), foreground = false }; Globals.clientTickBuffer.AddPacket(testBreak); @@ -123,12 +130,22 @@ public void Update(GameTime gameTime) { public void Draw(GameTime gameTime, GraphicsDevice graphicsDevice) { graphicsDevice.Clear(Color.CornflowerBlue); + + if(_camera == null) + { + Console.WriteLine("Camera is null"); + } + if(_spriteBatch == null) + { + Console.WriteLine("SpriteBatch is null"); + } - _spriteBatch.Begin(); + _spriteBatch.Begin(transformMatrix: _camera.GetViewMatrix()); Globals.BackgroundTilemapSprites.DrawAllTiles(_spriteBatch); Globals.ForegroundTilemapSprites.DrawAllTiles(_spriteBatch); + /* var deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; _frameCounter.Update(deltaTime); @@ -136,20 +153,25 @@ public void Draw(GameTime gameTime, GraphicsDevice graphicsDevice) { String fps = string.Format("FPS: {0}", _frameCounter.AverageFramesPerSecond); //Console.WriteLine(fps); + */ + + MouseState currentState = Mouse.GetState(); + Vector2 _worldPosition = _camera.ScreenToWorld(new Vector2(currentState.X, currentState.Y)); if (buildMode) _spriteBatch.Draw(BlockSpritesManager.AllBlocksSprites[blockSelected].blockSprite.Texture, - new Vector2Int(Mouse.GetState().X - (Mouse.GetState().X % 8), - (Mouse.GetState().Y - Mouse.GetState().Y % 8)), + new Vector2Int(_worldPosition.X - (_worldPosition.X % 8), + (_worldPosition.Y - _worldPosition.Y % 8)), new Rectangle(1, 1, 10, 10), Color.DimGray); _spriteBatch.End(); } - public GameScene(BlocktestGame game, bool doConnect, string ip) { + public GameScene(BlocktestGame game, OrthographicCamera newCamera, bool doConnect, string ip) { connect = doConnect; _spriteBatch = new SpriteBatch(game.GraphicsDevice); _game = game; + _camera = newCamera; GlobalsShared.BackgroundTilemap = new TilemapShared(GlobalsShared.maxX, GlobalsShared.maxY); GlobalsShared.ForegroundTilemap = new TilemapShared(GlobalsShared.maxX, GlobalsShared.maxY); @@ -198,4 +220,29 @@ private bool CheckWindowActive(MouseState mouse) return false; } } + + private Vector2 CameraMovement(KeyboardState keyboardState) + { + Vector2 movementDirection = Vector2.Zero; + if (keyboardState.IsKeyDown(Keys.S)) + { + movementDirection += Vector2.UnitY; + } + if (keyboardState.IsKeyDown(Keys.W)) + { + movementDirection -= Vector2.UnitY; + } + if (keyboardState.IsKeyDown(Keys.A)) + { + movementDirection -= Vector2.UnitX; + } + if (keyboardState.IsKeyDown(Keys.D)) + { + movementDirection += Vector2.UnitX; + } + if (keyboardState.IsKeyDown(Keys.LeftShift) || keyboardState.IsKeyDown(Keys.RightShift)) { + movementDirection *= 4; + } + return movementDirection; + } } \ No newline at end of file diff --git a/Blocktest/packages.lock.json b/Blocktest/packages.lock.json index 666688e..595fedc 100644 --- a/Blocktest/packages.lock.json +++ b/Blocktest/packages.lock.json @@ -14,6 +14,15 @@ "resolved": "3.8.1.303", "contentHash": "9Ilzzje62LhWElbPNEl7vh7XsRSbze+lvCJdZtTZUGu48FRgvYN6THURwIB9PN98EI33/Wnf6iuShNUtD7hL4Q==" }, + "MonoGame.Extended": { + "type": "Direct", + "requested": "[3.8.0, )", + "resolved": "3.8.0", + "contentHash": "FDPoUOFtslGNHCWSqjKD0C67RYN6Stb6NWnn+rkCmtkPBZlE6LvwuGyQBkHUkAMANO3LzO/Wsz9etMhwZLInqg==", + "dependencies": { + "Newtonsoft.Json": "12.0.3" + } + }, "MonoGame.Framework.DesktopGL": { "type": "Direct", "requested": "[3.8.*, )", @@ -26,6 +35,11 @@ "resolved": "2.2.0", "contentHash": "u06nYzGcXCBcnF7cRe8Xa0KxBxGx8grhujZmb3PUiMVbds8d/I6qJ+waGn0IeC7Tdwmt0P6l3v7MqdYog5rJQg==" }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "12.0.3", + "contentHash": "6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg==" + }, "shared": { "type": "Project", "dependencies": { diff --git a/Shared/Code/BuildSystem.cs b/Shared/Code/BuildSystem.cs index d764154..c272bab 100644 --- a/Shared/Code/BuildSystem.cs +++ b/Shared/Code/BuildSystem.cs @@ -11,13 +11,6 @@ public static class BuildSystem /// private static readonly int[,,] currentWorld = new int[GlobalsShared.maxX, GlobalsShared.maxY, 2]; - /// - /// The method called whenever an object is removed. - /// - /// Whether or not the block to be destroyed is in the foreground. - /// The position of the block to destroy (world coords) - //public static void BreakBlockWorld(bool foreground, Vector2 position) => BreakBlockCell(foreground, Globals.foreground.WorldToCell(position)); - /// /// The method called whenever an object is removed. /// @@ -48,14 +41,6 @@ public static void BreakBlockCell(bool foreground, Vector2Int tilePosition) } } - /// - /// The method called whenever a block is placed. - /// - /// The block type to place. - /// Whether or not the block should be placed in the foreground. - /// The position of the placed block. (World coords) - //public static void PlaceBlockWorld(Block toPlace, bool foreground, Vector2 position) => PlaceBlockCell(toPlace, foreground, Globals.foreground.WorldToCell(position)); - /// /// The method called whenever a block is placed. /// @@ -72,7 +57,6 @@ public static void PlaceBlockCell(BlockShared toPlace, bool foreground, Vector2I toPlace.OnPlace(tilePosition, foreground); if (foreground) { - //newTile.colliderType = Tile.ColliderType.Grid; GlobalsShared.ForegroundTilemap.SetTile(tilePosition, newTile); currentWorld[tilePosition.X, tilePosition.Y, 1] = toPlace.blockID + 1; } else if (toPlace.canPlaceBackground) { From bd9154fb9fc979ed1652e51d3838d1ea13200eb2 Mon Sep 17 00:00:00 2001 From: SuperYodeler <51685082+Superyodeler@users.noreply.github.com> Date: Thu, 28 Sep 2023 21:18:32 -0400 Subject: [PATCH 8/9] Revert "Monogame.extended camera" This reverts commit 8f000fa991ead3a9c8b6ba672ff1d9c6bc55e012. --- Blocktest/Blocktest.csproj | 1 - Blocktest/BlocktestGame.cs | 10 +-- Blocktest/Code/Block System/TilemapSprites.cs | 5 ++ Blocktest/Code/Scenes/GameScene.cs | 67 +++---------------- Blocktest/packages.lock.json | 14 ---- Shared/Code/BuildSystem.cs | 16 +++++ 6 files changed, 32 insertions(+), 81 deletions(-) diff --git a/Blocktest/Blocktest.csproj b/Blocktest/Blocktest.csproj index 4fd0f73..df3aee1 100644 --- a/Blocktest/Blocktest.csproj +++ b/Blocktest/Blocktest.csproj @@ -23,7 +23,6 @@ - diff --git a/Blocktest/BlocktestGame.cs b/Blocktest/BlocktestGame.cs index 161b802..1c59e38 100644 --- a/Blocktest/BlocktestGame.cs +++ b/Blocktest/BlocktestGame.cs @@ -1,14 +1,11 @@ using Blocktest.Rendering; using Blocktest.Scenes; -using MonoGame.Extended; -using MonoGame.Extended.ViewportAdapters; namespace Blocktest { /// public class BlocktestGame : Game { - private OrthographicCamera _camera; private GraphicsDeviceManager _graphics; private Scene? _currentScene; private bool connect; @@ -46,14 +43,9 @@ protected override void Initialize() { /// protected override void LoadContent() { - - BoxingViewportAdapter viewportAdapter = new(Window, GraphicsDevice, 800, 480); - _camera = new(viewportAdapter); - Console.WriteLine("Camera init"); Drawable.ContentManager = Content; BlockSpritesManager.LoadBlockSprites(Content); - Console.WriteLine("LoadContent"); - _currentScene = new GameScene(this, _camera, connect, ip); + _currentScene = new GameScene(this, connect, ip); } /// diff --git a/Blocktest/Code/Block System/TilemapSprites.cs b/Blocktest/Code/Block System/TilemapSprites.cs index b23e8d5..597fe89 100644 --- a/Blocktest/Code/Block System/TilemapSprites.cs +++ b/Blocktest/Code/Block System/TilemapSprites.cs @@ -38,6 +38,11 @@ public void DrawAllTiles(SpriteBatch spriteBatch) spriteBatch.Draw(sprite.Texture, new Vector2(tile.rectangle.X, tile.rectangle.Y), sprite.Bounds, tile.color); } } + /*foreach (TileShared tile in tilemap.allTiles) { + BlockSprites blockSprites = BlockSpritesManager.AllBlocksSprites[tile.SourceBlock.blockID]; + Drawable sprite = blockSprites.spriteSheet.OrderedSprites[tile.bitmask]; + spriteBatch.Draw(sprite.Texture, new Vector2(tile.rectangle.X, tile.rectangle.Y), sprite.Bounds, tile.color); + }*/ } } } diff --git a/Blocktest/Code/Scenes/GameScene.cs b/Blocktest/Code/Scenes/GameScene.cs index 35d4e15..a94c763 100644 --- a/Blocktest/Code/Scenes/GameScene.cs +++ b/Blocktest/Code/Scenes/GameScene.cs @@ -2,13 +2,10 @@ using LiteNetLib; using Microsoft.Xna.Framework.Input; using Shared.Networking; -using MonoGame.Extended; -using MonoGame.Extended.ViewportAdapters; namespace Blocktest.Scenes; public class GameScene : Scene { private readonly BlocktestGame _game; - private OrthographicCamera _camera; private readonly SpriteBatch _spriteBatch; private FrameCounter _frameCounter = new FrameCounter(); private readonly SpriteFont _spriteFont; @@ -32,13 +29,9 @@ public void Update(GameTime gameTime) { //for block placement MouseState currentState = Mouse.GetState(); - KeyboardState keyboardState = Keyboard.GetState(); - Vector2 _worldPosition = _camera.ScreenToWorld(new Vector2(currentState.X, currentState.Y)); - - _camera.Move(CameraMovement(keyboardState)); //press E to toggle build/destroy - if (keyboardState.IsKeyUp(Keys.E)) + if (Keyboard.GetState().IsKeyUp(Keys.E)) { latch = false; } @@ -49,7 +42,7 @@ public void Update(GameTime gameTime) { } //Q changes which block you have selected - if (keyboardState.IsKeyUp(Keys.Q)) + if (Keyboard.GetState().IsKeyUp(Keys.Q)) { latchBlockSelect = false; } @@ -72,7 +65,7 @@ public void Update(GameTime gameTime) { TileChange testChange = new() { tickNum = Globals.clientTickBuffer.currTick, - position = new Vector2Int(MathHelper.Clamp(_worldPosition.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(_worldPosition.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), + position = new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), foreground = true, blockId = blockSelected }; @@ -85,7 +78,7 @@ public void Update(GameTime gameTime) { TileChange testChange = new() { tickNum = Globals.clientTickBuffer.currTick, - position = new Vector2Int(MathHelper.Clamp(_worldPosition.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(_worldPosition.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), + position = new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), foreground = false, blockId = blockSelected }; @@ -103,7 +96,7 @@ public void Update(GameTime gameTime) { BreakTile testBreak = new() { tickNum = Globals.clientTickBuffer.currTick, - position = new Vector2Int(MathHelper.Clamp(_worldPosition.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(_worldPosition.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), + position = new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), foreground = true }; Globals.clientTickBuffer.AddPacket(testBreak); @@ -115,7 +108,7 @@ public void Update(GameTime gameTime) { BreakTile testBreak = new() { tickNum = Globals.clientTickBuffer.currTick, - position = new Vector2Int(MathHelper.Clamp(_worldPosition.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(_worldPosition.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), + position = new Vector2Int(MathHelper.Clamp(currentState.X / GlobalsShared.gridSize.X, 0, GlobalsShared.maxX), MathHelper.Clamp(currentState.Y / GlobalsShared.gridSize.Y, 0, GlobalsShared.maxY)), foreground = false }; Globals.clientTickBuffer.AddPacket(testBreak); @@ -130,22 +123,12 @@ public void Update(GameTime gameTime) { public void Draw(GameTime gameTime, GraphicsDevice graphicsDevice) { graphicsDevice.Clear(Color.CornflowerBlue); - - if(_camera == null) - { - Console.WriteLine("Camera is null"); - } - if(_spriteBatch == null) - { - Console.WriteLine("SpriteBatch is null"); - } - _spriteBatch.Begin(transformMatrix: _camera.GetViewMatrix()); + _spriteBatch.Begin(); Globals.BackgroundTilemapSprites.DrawAllTiles(_spriteBatch); Globals.ForegroundTilemapSprites.DrawAllTiles(_spriteBatch); - /* var deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; _frameCounter.Update(deltaTime); @@ -153,25 +136,20 @@ public void Draw(GameTime gameTime, GraphicsDevice graphicsDevice) { String fps = string.Format("FPS: {0}", _frameCounter.AverageFramesPerSecond); //Console.WriteLine(fps); - */ - - MouseState currentState = Mouse.GetState(); - Vector2 _worldPosition = _camera.ScreenToWorld(new Vector2(currentState.X, currentState.Y)); if (buildMode) _spriteBatch.Draw(BlockSpritesManager.AllBlocksSprites[blockSelected].blockSprite.Texture, - new Vector2Int(_worldPosition.X - (_worldPosition.X % 8), - (_worldPosition.Y - _worldPosition.Y % 8)), + new Vector2Int(Mouse.GetState().X - (Mouse.GetState().X % 8), + (Mouse.GetState().Y - Mouse.GetState().Y % 8)), new Rectangle(1, 1, 10, 10), Color.DimGray); _spriteBatch.End(); } - public GameScene(BlocktestGame game, OrthographicCamera newCamera, bool doConnect, string ip) { + public GameScene(BlocktestGame game, bool doConnect, string ip) { connect = doConnect; _spriteBatch = new SpriteBatch(game.GraphicsDevice); _game = game; - _camera = newCamera; GlobalsShared.BackgroundTilemap = new TilemapShared(GlobalsShared.maxX, GlobalsShared.maxY); GlobalsShared.ForegroundTilemap = new TilemapShared(GlobalsShared.maxX, GlobalsShared.maxY); @@ -220,29 +198,4 @@ private bool CheckWindowActive(MouseState mouse) return false; } } - - private Vector2 CameraMovement(KeyboardState keyboardState) - { - Vector2 movementDirection = Vector2.Zero; - if (keyboardState.IsKeyDown(Keys.S)) - { - movementDirection += Vector2.UnitY; - } - if (keyboardState.IsKeyDown(Keys.W)) - { - movementDirection -= Vector2.UnitY; - } - if (keyboardState.IsKeyDown(Keys.A)) - { - movementDirection -= Vector2.UnitX; - } - if (keyboardState.IsKeyDown(Keys.D)) - { - movementDirection += Vector2.UnitX; - } - if (keyboardState.IsKeyDown(Keys.LeftShift) || keyboardState.IsKeyDown(Keys.RightShift)) { - movementDirection *= 4; - } - return movementDirection; - } } \ No newline at end of file diff --git a/Blocktest/packages.lock.json b/Blocktest/packages.lock.json index 595fedc..666688e 100644 --- a/Blocktest/packages.lock.json +++ b/Blocktest/packages.lock.json @@ -14,15 +14,6 @@ "resolved": "3.8.1.303", "contentHash": "9Ilzzje62LhWElbPNEl7vh7XsRSbze+lvCJdZtTZUGu48FRgvYN6THURwIB9PN98EI33/Wnf6iuShNUtD7hL4Q==" }, - "MonoGame.Extended": { - "type": "Direct", - "requested": "[3.8.0, )", - "resolved": "3.8.0", - "contentHash": "FDPoUOFtslGNHCWSqjKD0C67RYN6Stb6NWnn+rkCmtkPBZlE6LvwuGyQBkHUkAMANO3LzO/Wsz9etMhwZLInqg==", - "dependencies": { - "Newtonsoft.Json": "12.0.3" - } - }, "MonoGame.Framework.DesktopGL": { "type": "Direct", "requested": "[3.8.*, )", @@ -35,11 +26,6 @@ "resolved": "2.2.0", "contentHash": "u06nYzGcXCBcnF7cRe8Xa0KxBxGx8grhujZmb3PUiMVbds8d/I6qJ+waGn0IeC7Tdwmt0P6l3v7MqdYog5rJQg==" }, - "Newtonsoft.Json": { - "type": "Transitive", - "resolved": "12.0.3", - "contentHash": "6mgjfnRB4jKMlzHSl+VD+oUc1IebOZabkbyWj2RiTgWwYPPuaK1H97G1sHqGwPlS5npiF5Q0OrxN1wni2n5QWg==" - }, "shared": { "type": "Project", "dependencies": { diff --git a/Shared/Code/BuildSystem.cs b/Shared/Code/BuildSystem.cs index c272bab..d764154 100644 --- a/Shared/Code/BuildSystem.cs +++ b/Shared/Code/BuildSystem.cs @@ -11,6 +11,13 @@ public static class BuildSystem /// private static readonly int[,,] currentWorld = new int[GlobalsShared.maxX, GlobalsShared.maxY, 2]; + /// + /// The method called whenever an object is removed. + /// + /// Whether or not the block to be destroyed is in the foreground. + /// The position of the block to destroy (world coords) + //public static void BreakBlockWorld(bool foreground, Vector2 position) => BreakBlockCell(foreground, Globals.foreground.WorldToCell(position)); + /// /// The method called whenever an object is removed. /// @@ -41,6 +48,14 @@ public static void BreakBlockCell(bool foreground, Vector2Int tilePosition) } } + /// + /// The method called whenever a block is placed. + /// + /// The block type to place. + /// Whether or not the block should be placed in the foreground. + /// The position of the placed block. (World coords) + //public static void PlaceBlockWorld(Block toPlace, bool foreground, Vector2 position) => PlaceBlockCell(toPlace, foreground, Globals.foreground.WorldToCell(position)); + /// /// The method called whenever a block is placed. /// @@ -57,6 +72,7 @@ public static void PlaceBlockCell(BlockShared toPlace, bool foreground, Vector2I toPlace.OnPlace(tilePosition, foreground); if (foreground) { + //newTile.colliderType = Tile.ColliderType.Grid; GlobalsShared.ForegroundTilemap.SetTile(tilePosition, newTile); currentWorld[tilePosition.X, tilePosition.Y, 1] = toPlace.blockID + 1; } else if (toPlace.canPlaceBackground) { From cda307d707c7d6b033d5b02442eee741c08cd8d6 Mon Sep 17 00:00:00 2001 From: SuperYodeler <51685082+Superyodeler@users.noreply.github.com> Date: Thu, 28 Sep 2023 21:37:57 -0400 Subject: [PATCH 9/9] Revert "Merge pull request #15 from blocktest-game/camera" This reverts commit 22da09caefc15add91d2cd4b454cd382325e7efa, reversing changes made to 9701ae48e375c887a23d7a20b4feffbcfab08e5a. --- Blocktest/BlocktestGame.cs | 3 +- Blocktest/Code/Block System/Tilemap.cs | 90 ++++++++++++---- Blocktest/Code/BuildSystem.cs | 30 +++++- Blocktest/Code/Rendering/Camera.cs | 62 ----------- Blocktest/Code/Rendering/Renderable.cs | 32 ------ Blocktest/Code/Rendering/Transform.cs | 15 --- Blocktest/Code/Scenes/GameScene.cs | 136 +++++++------------------ 7 files changed, 138 insertions(+), 230 deletions(-) delete mode 100644 Blocktest/Code/Rendering/Camera.cs delete mode 100644 Blocktest/Code/Rendering/Renderable.cs delete mode 100644 Blocktest/Code/Rendering/Transform.cs diff --git a/Blocktest/BlocktestGame.cs b/Blocktest/BlocktestGame.cs index 23078b0..7e08bf9 100644 --- a/Blocktest/BlocktestGame.cs +++ b/Blocktest/BlocktestGame.cs @@ -15,7 +15,6 @@ public BlocktestGame() _graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; IsMouseVisible = true; - Window.AllowUserResizing = true; } /// @@ -36,7 +35,7 @@ protected override void LoadContent() protected override void Update(GameTime gameTime) { _currentScene?.Update(gameTime); - + base.Update(gameTime); } diff --git a/Blocktest/Code/Block System/Tilemap.cs b/Blocktest/Code/Block System/Tilemap.cs index e19989b..1654cc3 100644 --- a/Blocktest/Code/Block System/Tilemap.cs +++ b/Blocktest/Code/Block System/Tilemap.cs @@ -19,25 +19,43 @@ public class Tilemap /// public readonly Vector2Int tilemapSize; /// + /// The size of each cell (in pixels) in the tilemap's grid. + /// + public readonly Vector2Int gridSize = new(8, 8); + /// /// A list of s that specify which blocks should be refreshed when a tile is placed/destroyed. Defaults to the changed block and all cardinal directions. /// - private static readonly List adjacencies = new() { Vector2Int.Zero, Vector2Int.Up, Vector2Int.Down, Vector2Int.Left, Vector2Int.Right }; + private readonly List adjacencies = new() { Vector2Int.Zero, Vector2Int.Up, Vector2Int.Down, Vector2Int.Left, Vector2Int.Right }; - private readonly Camera _camera; /// /// Creates a . /// /// The width of the tilemap in tiles. /// The height of the tilemap in tiles. - /// The camera to render tiles on - public Tilemap(int sizeX, int sizeY, Camera camera) + public Tilemap(int sizeX, int sizeY) { - _camera = camera; tilemapSize = new(sizeX, sizeY); tileGrid = new Tile[sizeX, sizeY]; } + /// + /// Called from the main draw loop, calls on each tile in the tilemap. + /// + /// The spritebatch to draw the tilemap tiles' sprite on. + public void Draw(SpriteBatch spriteBatch) + { + foreach (Tile tile in allTiles) { + tile.Draw(spriteBatch); + } + } + + /// + /// Sets a Tile at the given XYZ coordinates of a cell in the tile map to a specific type. + /// + /// Location the new Block will be placed. + /// Block type to be placed in the cell. + public Tile SetBlock(Vector2Int location, Block newBlock) => SetTile(location, new Tile(newBlock, location)); /// /// Sets a Tile at the given XYZ coordinates of a cell in the tile map to a specific type. /// @@ -48,14 +66,12 @@ public Tile SetTile(Vector2Int location, Tile newTile) Tile oldTile = GetTile(location); if (oldTile != null) { allTiles.Remove(oldTile); - _camera.RenderedComponents.Remove(oldTile.Renderable); } tileGrid[location.X, location.Y] = newTile; if (newTile != null) { allTiles.Add(newTile); - _camera.RenderedComponents.Add(newTile.Renderable); } foreach (Vector2Int dir in adjacencies) { @@ -77,13 +93,37 @@ public Tile SetTile(Vector2Int location, Tile newTile) /// /// Location of the Tile on the Tilemap to check. /// placed at the cell. - public Tile? GetTile(Vector2Int location) { - if (location.X < 0 || location.Y < 0 || location.X >= tilemapSize.X || location.Y >= tilemapSize.Y) { + public Tile? GetTile(Vector2Int location) => GetTile(location.X, location.Y); + + /// + /// Gets the at a specific location on a . + /// + /// X position of the Tile on the Tilemap to check. + /// Y position of the Tile on the Tilemap to check. + /// placed at the cell. + public Tile? GetTile(int x, int y) { + if (x < 0 || y < 0 || x >= tilemapSize.X || y >= tilemapSize.Y) { return null; } - return tileGrid[location.X, location.Y]; + return tileGrid[x, y]; } + /// + /// Gets the at a specific location on a . + /// + /// The subtype of Tile to return. + /// Location of the Tile on the Tilemap to check. + /// of type T placed at the cell. + public T? GetTile(Vector2Int location) where T : Tile => (T?)GetTile(location.X, location.Y); + /// + /// Gets the at a specific location on a . + /// + /// The subtype of Tile to return. + /// X position of the Tile on the Tilemap to check. + /// Y position of the Tile on the Tilemap to check. + /// of type T placed at the cell. + public T? GetTile(int x, int y) where T : Tile => (T?)GetTile(x, y); + /// /// Returns whether there is a at the location specified. /// @@ -110,18 +150,25 @@ public class Tile /// The size of the tile square's edges, in pixels (Default 8) /// protected int size = 8; - - public Renderable Renderable; + /// + /// Color of the tile. + /// + public Color color = Color.White; + /// + /// The rectangle of the tile, used for sprite rendering and collisions. + /// + public Rectangle rectangle; /// /// Creates a . /// /// The type of block the new tile should be. /// The position in a tilemap the tile will be. - public Tile(Block newBlock, Vector2Int position, Layer layer = Layer.ForegroundBlocks) + public Tile(Block newBlock, Vector2Int position) { SourceBlock = newBlock; - Renderable = new Renderable(new Transform(new Vector2(Globals.gridSize.X * position.X, Globals.gridSize.Y * position.Y)), layer, SourceBlock.blockSprite); + sprite = SourceBlock.blockSprite; + rectangle = new Rectangle(Globals.gridSize.X * position.X, Globals.gridSize.Y * position.Y, size, size); // HACK: This can probably be done better } /// @@ -136,10 +183,10 @@ public void UpdateAdjacencies(Vector2Int position, Tilemap tilemap) int bitmask = 0; // Using bitmask smoothing, look it up if (HasSmoothableTile(position + Vector2Int.Up, tilemap)) { - bitmask += 1; + bitmask += 2; } if (HasSmoothableTile(position + Vector2Int.Down, tilemap)) { - bitmask += 2; + bitmask += 1; } if (HasSmoothableTile(position + Vector2Int.Right, tilemap)) { bitmask += 4; @@ -148,7 +195,7 @@ public void UpdateAdjacencies(Vector2Int position, Tilemap tilemap) bitmask += 8; } - Renderable.Appearance = SourceBlock.spriteSheet.OrderedSprites[bitmask]; + sprite = SourceBlock.spriteSheet.OrderedSprites[bitmask]; } /// @@ -164,6 +211,15 @@ private bool HasSmoothableTile(Vector2Int position, Tilemap tilemap) return otherTile != null; } + /// + /// Called from the main draw loop. + /// + /// The spritebatch to draw the tile's sprite on. + public void Draw(SpriteBatch spriteBatch) + { + spriteBatch.Draw(sprite.Texture, new Vector2(rectangle.X, rectangle.Y), sprite.Bounds, Color.White); + } + /// /// If the tile provided is the same type (references the same block) as the current tile. /// diff --git a/Blocktest/Code/BuildSystem.cs b/Blocktest/Code/BuildSystem.cs index ce4de2d..13e6410 100644 --- a/Blocktest/Code/BuildSystem.cs +++ b/Blocktest/Code/BuildSystem.cs @@ -1,5 +1,3 @@ -using Blocktest.Rendering; - namespace Blocktest { public static class BuildSystem @@ -9,6 +7,13 @@ public static class BuildSystem /// private static readonly int[,,] currentWorld = new int[Globals.maxX, Globals.maxY, 2]; + /// + /// The method called whenever an object is removed. + /// + /// Whether or not the block to be destroyed is in the foreground. + /// The position of the block to destroy (world coords) + //public static void BreakBlockWorld(bool foreground, Vector2 position) => BreakBlockCell(foreground, Globals.foreground.WorldToCell(position)); + /// /// The method called whenever an object is removed. /// @@ -39,6 +44,14 @@ public static void BreakBlockCell(bool foreground, Vector2Int tilePosition) } + /// + /// The method called whenever a block is placed. + /// + /// The block type to place. + /// Whether or not the block should be placed in the foreground. + /// The position of the placed block. (World coords) + //public static void PlaceBlockWorld(Block toPlace, bool foreground, Vector2 position) => PlaceBlockCell(toPlace, foreground, Globals.foreground.WorldToCell(position)); + /// /// The method called whenever a block is placed. /// @@ -47,7 +60,7 @@ public static void BreakBlockCell(bool foreground, Vector2Int tilePosition) /// The position of the placed block. (Grid coords) public static void PlaceBlockCell(Block toPlace, bool foreground, Vector2Int tilePosition) { - Tile newTile = new(toPlace, tilePosition, foreground ? Layer.ForegroundBlocks : Layer.BackgroundBlocks); + Tile newTile = new(toPlace, tilePosition); toPlace.OnPlace(tilePosition, foreground); if (foreground) { @@ -55,10 +68,19 @@ public static void PlaceBlockCell(Block toPlace, bool foreground, Vector2Int til Globals.ForegroundTilemap.SetTile(tilePosition, newTile); currentWorld[tilePosition.X, tilePosition.Y, 0] = toPlace.blockID + 1; } else if (toPlace.canPlaceBackground) { - newTile.Renderable.RenderColor = new Color(0.5f, 0.5f, 0.5f, 1f); + newTile.color = new Color(0.5f, 0.5f, 0.5f, 1f); Globals.BackgroundTilemap.SetTile(tilePosition, newTile); currentWorld[tilePosition.X, tilePosition.Y, 1] = toPlace.blockID + 1; } } + + /// + /// The method called whenever a block is placed. + /// + /// The block type to place. + /// Whether or not the block should be placed in the foreground. + /// The position of the placed block. (Grid coords) + public static void PlaceBlockCell(Block toPlace, bool foreground, Vector2 tilePosition) => PlaceBlockCell(toPlace, foreground, (Vector2Int)tilePosition); + } } \ No newline at end of file diff --git a/Blocktest/Code/Rendering/Camera.cs b/Blocktest/Code/Rendering/Camera.cs deleted file mode 100644 index 71eacc8..0000000 --- a/Blocktest/Code/Rendering/Camera.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Collections; -namespace Blocktest.Rendering; - -public sealed class Camera { - private readonly Color _backgroundColor; - private readonly Vector2 _size; - - public readonly List RenderedComponents = new(); - - public Rectangle RenderLocation; - public readonly RenderTarget2D RenderTarget; - public Vector2 Position; - - public Camera(Vector2 position, Vector2 size, GraphicsDevice graphicsDevice, Color? backgroundColor = null) { - Position = position; - _size = size; - _backgroundColor = backgroundColor ?? Color.CornflowerBlue; - RenderTarget = new RenderTarget2D(graphicsDevice, (int)size.X, (int)size.Y, false, SurfaceFormat.Color, DepthFormat.None, 0, RenderTargetUsage.DiscardContents); - } - - public void Draw(GraphicsDevice graphics, SpriteBatch spriteBatch) { - graphics.SetRenderTarget(RenderTarget); - graphics.Clear(_backgroundColor); - - spriteBatch.Begin(); - - foreach (Renderable component in RenderedComponents) { - if (component.Appearance == null) { - continue; - } - - Vector2 worldPosition = component.Transform.Position; - Vector2 cameraPosition = worldPosition - Position; - - if (worldPosition.X + component.Appearance.Bounds.Width < Position.X && - worldPosition.X > Position.X + _size.X && - worldPosition.Y + component.Appearance.Bounds.Height < Position.Y && - worldPosition.Y > Position.Y + _size.Y) { - continue; - } - - Vector2 flippedPosition = new(cameraPosition.X, RenderTarget.Height - cameraPosition.Y - component.Appearance.Bounds.Height); - - Rectangle positionBounds = new((int)flippedPosition.X, (int)flippedPosition.Y, (int)(component.Appearance.Bounds.Width * component.Transform.Scale.X), - (int)(component.Appearance.Bounds.Height * component.Transform.Scale.Y)); - - spriteBatch.Draw(component.Appearance.Texture, positionBounds, component.Appearance.Bounds, - component.RenderColor, component.Transform.Rotation, component.Transform.Origin, SpriteEffects.None, (float)component.Layer / EnumCount); - } - - spriteBatch.End(); - - graphics.SetRenderTarget(null); - } - - private static readonly int EnumCount = Enum.GetValues(typeof(Layer)).Length; - - public Vector2 CameraToWorldPos(Vector2 mouseState) { - return new((mouseState.X - RenderLocation.X) / RenderLocation.Width * RenderTarget.Width + Position.X, Position.Y + RenderTarget.Height - - (mouseState.Y - RenderLocation.Y) / RenderLocation.Height * RenderTarget.Height); - } -} \ No newline at end of file diff --git a/Blocktest/Code/Rendering/Renderable.cs b/Blocktest/Code/Rendering/Renderable.cs deleted file mode 100644 index 0b59fdf..0000000 --- a/Blocktest/Code/Rendering/Renderable.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Blocktest.Rendering; - -public enum Layer { - Top = 0, - Player = 1, - Default = 2, - ForegroundBlocks = 3, - BackgroundBlocks = 4 -} - -public sealed class Renderable { - public readonly Transform Transform; - public Drawable? Appearance; - public Color RenderColor; - public Layer Layer; - - public Renderable(Transform transform, Layer layer = Layer.Default, Drawable? appearance = null, Color? renderColor = null) { - Transform = transform; - Layer = layer; - Appearance = appearance; - RenderColor = renderColor ?? Color.White; - } - - public void Draw(SpriteBatch spriteBatch, Vector2 cameraPosition) { - if (Appearance == null) { - return; - } - - spriteBatch.Draw(Appearance.Texture, Transform.Position - cameraPosition, Appearance.Bounds, RenderColor, Transform.Rotation, Transform.Origin, Transform.Scale, - SpriteEffects.None, 0); - } -} \ No newline at end of file diff --git a/Blocktest/Code/Rendering/Transform.cs b/Blocktest/Code/Rendering/Transform.cs deleted file mode 100644 index c2b5050..0000000 --- a/Blocktest/Code/Rendering/Transform.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Blocktest.Rendering; - -public sealed class Transform { - public Vector2 Position; - public float Rotation; - public Vector2 Scale; - public Vector2 Origin; - - public Transform(Vector2 position, Vector2? scale = null, float rotation = 0, Vector2? origin = null) { - Position = position; - Scale = scale ?? Vector2.One; - Rotation = rotation; - Origin = origin ?? Vector2.Zero; - } -} \ No newline at end of file diff --git a/Blocktest/Code/Scenes/GameScene.cs b/Blocktest/Code/Scenes/GameScene.cs index 34e7f0b..cee338b 100644 --- a/Blocktest/Code/Scenes/GameScene.cs +++ b/Blocktest/Code/Scenes/GameScene.cs @@ -1,4 +1,3 @@ -using Blocktest.Rendering; using Microsoft.Xna.Framework.Input; namespace Blocktest.Scenes; @@ -10,18 +9,14 @@ public class GameScene : Scene { private bool latchBlockSelect = false; //same but for block selection bool buildMode = true; //true for build, false for destroy private int blockSelected = 0; //ID of the block to place - private Camera _camera; public void Update(GameTime gameTime) { - MouseState mouseState = Mouse.GetState(); - KeyboardState keyState = Keyboard.GetState(); - - if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || keyState.IsKeyDown(Keys.Escape)) { + if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) { _game.Exit(); } //press E to toggle build/destroy - if (keyState.IsKeyUp(Keys.E)) + if (Keyboard.GetState().IsKeyUp(Keys.E)) { latch = false; } @@ -31,8 +26,11 @@ public void Update(GameTime gameTime) { latch = true; } + //for block placement + MouseState currentState = Mouse.GetState(); + //Q changes which block you have selected - if (keyState.IsKeyUp(Keys.Q)) + if (Keyboard.GetState().IsKeyUp(Keys.Q)) { latchBlockSelect = false; } @@ -47,124 +45,66 @@ public void Update(GameTime gameTime) { latchBlockSelect = true; } - var moveValue = 2.5f; - if (keyState.IsKeyDown(Keys.LeftShift) || keyState.IsKeyDown(Keys.RightShift)) { - moveValue *= 4; - } - - if (keyState.IsKeyDown(Keys.A)) { - _camera.Position.X -= moveValue; - } else if (keyState.IsKeyDown(Keys.D)) { - _camera.Position.X += moveValue; - } - - if (keyState.IsKeyDown(Keys.W)) { - _camera.Position.Y += moveValue; - } else if (keyState.IsKeyDown(Keys.S)) { - _camera.Position.Y -= moveValue; - } - - if (!_camera.RenderLocation.Contains(mouseState.Position)) { - return; - } - - var mousePos = _camera.CameraToWorldPos(new(mouseState.X, mouseState.Y)); //build and destroy mode if (buildMode) { - if(mouseState.LeftButton == ButtonState.Pressed) + if(currentState.LeftButton == ButtonState.Pressed) { BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[blockSelected], true, - new Vector2Int(MathHelper.Clamp(mousePos.X / Globals.gridSize.X, 0, Globals.maxX), - MathHelper.Clamp(mousePos.Y / Globals.gridSize.Y, 0, Globals.maxY))); - } else if (mouseState.RightButton == ButtonState.Pressed) { + new Vector2Int(MathHelper.Clamp(currentState.X / Globals.gridSize.X, 0, Globals.maxX), + MathHelper.Clamp(currentState.Y / Globals.gridSize.Y, 0, Globals.maxY))); + } else if (currentState.RightButton == ButtonState.Pressed) { BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[blockSelected], false, - new Vector2Int(MathHelper.Clamp(mousePos.X / Globals.gridSize.X, 0, Globals.maxX), - MathHelper.Clamp(mousePos.Y / Globals.gridSize.Y, 0, Globals.maxY))); + new Vector2Int(MathHelper.Clamp(currentState.X / Globals.gridSize.X, 0, Globals.maxX), + MathHelper.Clamp(currentState.Y / Globals.gridSize.Y, 0, Globals.maxY))); } } else { - if(mouseState.LeftButton == ButtonState.Pressed) + if(currentState.LeftButton == ButtonState.Pressed) { BuildSystem.BreakBlockCell( true, - new Vector2Int(MathHelper.Clamp(mousePos.X / Globals.gridSize.X, 0, Globals.maxX), - MathHelper.Clamp(mousePos.Y / Globals.gridSize.Y, 0, Globals.maxY))); - } else if (mouseState.RightButton == ButtonState.Pressed) { + new Vector2Int(MathHelper.Clamp(currentState.X / Globals.gridSize.X, 0, Globals.maxX), + MathHelper.Clamp(currentState.Y / Globals.gridSize.Y, 0, Globals.maxY))); + } else if (currentState.RightButton == ButtonState.Pressed) { BuildSystem.BreakBlockCell( false, - new Vector2Int(MathHelper.Clamp(mousePos.X / Globals.gridSize.X, 0, Globals.maxX), - MathHelper.Clamp(mousePos.Y / Globals.gridSize.Y, 0, Globals.maxY))); + new Vector2Int(MathHelper.Clamp(currentState.X / Globals.gridSize.X, 0, Globals.maxX), + MathHelper.Clamp(currentState.Y / Globals.gridSize.Y, 0, Globals.maxY))); } - } + } + } public void Draw(GameTime gameTime, GraphicsDevice graphicsDevice) { + graphicsDevice.Clear(Color.CornflowerBlue); - - _camera.Draw(graphicsDevice, _spriteBatch); - - const bool pixelPerfect = false; - - var destinationRectangle = pixelPerfect ? GetPixelPerfectRect() : GetFitRect(); - _camera.RenderLocation = destinationRectangle; + _spriteBatch.Begin(); + Globals.BackgroundTilemap.Draw(_spriteBatch); + Globals.ForegroundTilemap.Draw(_spriteBatch); + // placement preview + if (buildMode) + _spriteBatch.Draw(BlockManager.AllBlocks[blockSelected].blockSprite.Texture, + new Vector2Int(Mouse.GetState().X - (Mouse.GetState().X % 8), + (Mouse.GetState().Y - Mouse.GetState().Y % 8)), + new Rectangle(1, 1, 10, 10), Color.DimGray); - graphicsDevice.Clear(Color.DarkGray); - - _spriteBatch.Begin(samplerState: pixelPerfect ? SamplerState.PointClamp : null); - _spriteBatch.Draw(_camera.RenderTarget, destinationRectangle, Color.White); _spriteBatch.End(); } - private Rectangle GetPixelPerfectRect() { - int multiplier = int.Min(_game.GraphicsDevice.Viewport.Height / _camera.RenderTarget.Height, - _game.GraphicsDevice.Viewport.Width / _camera.RenderTarget.Width); - - int width = _camera.RenderTarget.Width * multiplier; - int height = _camera.RenderTarget.Height * multiplier; - - int x = (_game.GraphicsDevice.Viewport.Width - width) / 2; - int y = (_game.GraphicsDevice.Viewport.Height - height) / 2; - - return new Rectangle(x, y, width, height); - } - - private Rectangle GetFitRect() { - float aspectRatio = (float)_game.GraphicsDevice.Viewport.Width / _game.GraphicsDevice.Viewport.Height; - float renderTargetAspectRatio = (float)_camera.RenderTarget.Width / _camera.RenderTarget.Height; - - int width, height; - if (aspectRatio > renderTargetAspectRatio) { - width = (int)(_game.GraphicsDevice.Viewport.Height * renderTargetAspectRatio); - height = _game.GraphicsDevice.Viewport.Height; - } - else { - width = _game.GraphicsDevice.Viewport.Width; - height = (int)(_game.GraphicsDevice.Viewport.Width / renderTargetAspectRatio); - } - - int x = (_game.GraphicsDevice.Viewport.Width - width) / 2; - int y = (_game.GraphicsDevice.Viewport.Height - height) / 2; - - return new Rectangle(x, y, width, height); - } - - - public GameScene(BlocktestGame game) { _spriteBatch = new SpriteBatch(game.GraphicsDevice); _game = game; - _camera = new Camera(new Vector2(0, 0), new Vector2(512, 256), _game.GraphicsDevice); - Globals.BackgroundTilemap = new Tilemap(Globals.maxX, Globals.maxY, _camera); - Globals.ForegroundTilemap = new Tilemap(Globals.maxX, Globals.maxY, _camera); + Globals.BackgroundTilemap = new Tilemap(Globals.maxX, Globals.maxY); + Globals.ForegroundTilemap = new Tilemap(Globals.maxX, Globals.maxY); for (int i = 0; i < Globals.maxX; i++) { - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[1], true, new Vector2Int(i, 5)); - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(i, 4)); - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(i, 3)); - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(i, 2)); - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(i, 1)); - BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[2], true, new Vector2Int(i, 0)); + BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[2], true, new Vector2Int(i, 59)); + BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(i, 58)); + BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(i, 57)); + BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(i, 56)); + BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[0], true, new Vector2Int(i, 55)); + BuildSystem.PlaceBlockCell(BlockManager.AllBlocks[1], true, new Vector2Int(i, 54)); } } } \ No newline at end of file