added basic world gen and more debug

This commit is contained in:
MasterGordon 2022-12-30 15:05:50 +01:00
parent 072c4de56c
commit 6bc5748bc9
17 changed files with 397 additions and 55 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

View File

@ -1,3 +1,5 @@
using Mine2d.game;
namespace Mine2d.engine;
public abstract class Game
@ -6,6 +8,7 @@ public abstract class Game
private readonly bool running = true;
private readonly Queue<int> fpsQueue = new();
private DateTime nextFpsUpdate = DateTime.Now;
protected abstract void Update(double dt);
protected abstract void Draw();
@ -24,6 +27,12 @@ public abstract class Game
{
this.fpsQueue.Dequeue();
}
if (this.nextFpsUpdate < DateTime.Now && this.fpsQueue.Count > 0)
{
var avgFps = this.fpsQueue.Sum() / this.fpsQueue.Count;
SDL_SetWindowTitle(Context.Get().Window.GetRaw(), "Mine2d - debug - " + avgFps + "fps");
this.nextFpsUpdate = DateTime.Now.AddMilliseconds(200);
}
while (tAcc >= TimeSpan.FromSeconds(1.0 / Tps))
{

View File

@ -0,0 +1,164 @@
// https://gist.github.com/jstanden/1489447
namespace Mine2d.engine.lib;
public class OpenSimplexNoise
{
private readonly int[] a = new int[3];
private float s, u, v, w;
private int i, j, k;
private readonly float onethird = 0.333333333f;
private readonly float onesixth = 0.166666667f;
private readonly int[] t;
public OpenSimplexNoise()
{
if (this.t == null)
{
var rand = new Random();
this.t = new int[8];
for (var q = 0; q < 8; q++)
{
this.t[q] = rand.Next();
}
}
}
public OpenSimplexNoise(string seed)
{
this.t = new int[8];
var seed_parts = seed.Split(new char[] { ' ' });
for (var q = 0; q < 8; q++)
{
int b;
try
{
b = int.Parse(seed_parts[q]);
}
catch
{
b = 0x0;
}
this.t[q] = b;
}
}
public OpenSimplexNoise(int[] seed)
{ // {0x16, 0x38, 0x32, 0x2c, 0x0d, 0x13, 0x07, 0x2a}
this.t = seed;
}
public string GetSeed()
{
var seed = "";
for (var q = 0; q < 8; q++)
{
seed += this.t[q].ToString();
if (q < 7)
seed += " ";
}
return seed;
}
public float coherentNoise(float x, float y, float z, int octaves = 1, int multiplier = 25, float amplitude = 0.5f, float lacunarity = 2, float persistence = 0.9f)
{
var v3 = new Vector3(x, y, z) / multiplier;
float val = 0;
for (var n = 0; n < octaves; n++)
{
val += this.noise(v3.X, v3.Y, v3.Z) * amplitude;
v3 *= lacunarity;
amplitude *= persistence;
}
return val;
}
private static int Lerp(int a, int b, float t)
{
return (int)(a + (t * (b - a)));
}
public int getDensity(Vector3 loc)
{
var val = this.coherentNoise(loc.X, loc.Y, loc.Z);
return Lerp(0, 255, val);
}
// Simplex Noise Generator
public float noise(float x, float y, float z)
{
this.s = (x + y + z) * this.onethird;
this.i = fastfloor(x + this.s);
this.j = fastfloor(y + this.s);
this.k = fastfloor(z + this.s);
this.s = (this.i + this.j + this.k) * this.onesixth;
this.u = x - this.i + this.s;
this.v = y - this.j + this.s;
this.w = z - this.k + this.s;
this.a[0] = 0; this.a[1] = 0; this.a[2] = 0;
var hi = this.u >= this.w ? this.u >= this.v
? 0
: 1 : this.v >= this.w ? 1 : 2;
var lo = this.u < this.w ? this.u < this.v
? 0
: 1 : this.v < this.w ? 1 : 2;
return this.kay(hi) + this.kay(3 - hi - lo) + this.kay(lo) + this.kay(0);
}
private float kay(int a)
{
this.s = (this.a[0] + this.a[1] + this.a[2]) * this.onesixth;
var x = this.u - this.a[0] + this.s;
var y = this.v - this.a[1] + this.s;
var z = this.w - this.a[2] + this.s;
var t = 0.6f - (x * x) - (y * y) - (z * z);
var h = this.shuffle(this.i + this.a[0], this.j + this.a[1], this.k + this.a[2]);
this.a[a]++;
if (t < 0)
{
return 0;
}
var b5 = h >> 5 & 1;
var b4 = h >> 4 & 1;
var b3 = h >> 3 & 1;
var b2 = h >> 2 & 1;
var b1 = h & 3;
var p = b1 == 1 ? x : b1 == 2 ? y : z;
var q = b1 == 1 ? y : b1 == 2 ? z : x;
var r = b1 == 1 ? z : b1 == 2 ? x : y;
p = b5 == b3 ? -p : p;
q = b5 == b4 ? -q : q;
r = b5 != (b4 ^ b3) ? -r : r;
t *= t;
return 8 * t * t * (p + (b1 == 0 ? q + r : b2 == 0 ? q : r));
}
private int shuffle(int i, int j, int k)
{
return this.b(i, j, k, 0) + this.b(j, k, i, 1) + this.b(k, i, j, 2) + this.b(i, j, k, 3) + this.b(j, k, i, 4) + this.b(k, i, j, 5) + this.b(i, j, k, 6) + this.b(j, k, i, 7);
}
private int b(int i, int j, int k, int B)
{
return this.t[b(i, B) << 2 | b(j, B) << 1 | b(k, B)];
}
private static int b(int N, int B)
{
return N >> B & 1;
}
private static int fastfloor(float n)
{
return n > 0 ? (int)n : (int)n - 1;
}
}

View File

@ -2,6 +2,7 @@ using Mine2d.engine.extensions;
using Mine2d.engine.system.annotations;
using Mine2d.game.backend.network.packets;
using Mine2d.game.core;
using Mine2d.game.core.data;
namespace Mine2d.game.backend.interactor;
@ -23,20 +24,19 @@ public class DebugCommandHandler
[Interaction(InteractorKind.Hybrid, PacketType.DebugCommand)]
public static void HandleHelpDebugCommand(DebugCommandPacket packet)
{
if (packet.Command == DebugCommand.Help)
{
var enumType = typeof(DebugCommand);
Enum.GetValues<DebugCommand>()
.Where(command => command != DebugCommand.Unknown)
.ForEach(command =>
{
var memberInfo = enumType.GetMember(command.ToString());
var enumValueMemberInfo = memberInfo[0];
var valueAttributes = enumValueMemberInfo.GetCustomAttributes(typeof(DebugCommandAttribute), false);
var attribute = (DebugCommandAttribute)valueAttributes[0];
Debugger.Print(command.ToString().ToLower() + attribute.Usage + " - " + attribute.Desc);
});
}
if (packet.Command != DebugCommand.Help) return;
var enumType = typeof(DebugCommand);
Enum.GetValues<DebugCommand>()
.Where(command => command != DebugCommand.Unknown)
.ForEach(command =>
{
var memberInfo = enumType.GetMember(command.ToString());
var enumValueMemberInfo = memberInfo[0];
var valueAttributes = enumValueMemberInfo.GetCustomAttributes(typeof(DebugCommandAttribute), false);
var attribute = (DebugCommandAttribute)valueAttributes[0];
Debugger.Print(command.ToString().ToLower() + attribute.Usage + " - " + attribute.Desc);
});
}
[Interaction(InteractorKind.Hybrid, PacketType.DebugCommand)]
@ -49,4 +49,71 @@ public class DebugCommandHandler
Debugger.Print("noclip: " + ds.NoClip);
}
}
[Interaction(InteractorKind.Hybrid, PacketType.DebugCommand)]
public static void HandleNoFogDebugCommand(DebugCommandPacket packet)
{
if (packet.Command == DebugCommand.NoFog)
{
var ds = Context.Get().FrontendGameState.DebugState;
ds.NoFog = !ds.NoFog;
Debugger.Print("nofog: " + ds.NoFog);
}
}
[Interaction(InteractorKind.Hybrid, PacketType.DebugCommand)]
public static void HandleOverlayDebugCommand(DebugCommandPacket packet)
{
if (packet.Command == DebugCommand.Overlay)
{
if (packet.Args.Length == 0)
{
Debugger.Print("Usage: overlay <kind>");
return;
}
var ds = Context.Get().FrontendGameState.DebugState;
ds.Overlay = packet.Args[0];
Debugger.Print("overlay: " + ds.Overlay);
}
}
[Interaction(InteractorKind.Hybrid, PacketType.DebugCommand)]
public static void HandleGameScaleDebugCommand(DebugCommandPacket packet)
{
if (packet.Command == DebugCommand.GameScale)
{
if (packet.Args.Length == 0)
{
Debugger.Print("Usage: gamescale <scale>");
return;
}
var scale = int.Parse(packet.Args[0]);
var ds = Context.Get().FrontendGameState.Settings;
ds.GameScale = scale;
Debugger.Print("gamescale: " + ds.GameScale);
}
}
[Interaction(InteractorKind.Hybrid, PacketType.DebugCommand)]
public static void HandleGiveCommand(DebugCommandPacket packet)
{
if (packet.Command != DebugCommand.Give) return;
if (packet.Args.Length == 0)
{
Debugger.Print("Usage 'give <item> [amount]'");
return;
}
var ctx = Context.Get();
var item = int.Parse(packet.Args[0]);
var amount = packet.Args.Length > 1 ? int.Parse(packet.Args[1]) : 1;
if (!Enum.IsDefined(typeof(ItemId), item))
{
Debugger.Print("Unknown item!");
return;
}
var itemId = (ItemId)Enum.ToObject(typeof(ItemId), item);
PlayerEntity.GetSelf().Inventory.PickupItemStack(new ItemStack(itemId, amount));
var registeredItem = ctx.ItemRegistry.GetItem(itemId);
Debugger.Print("Gave "+amount+"x "+registeredItem.Name);
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Mine2d.engine.system.annotations;
using Mine2d.game.backend.network.packets;
namespace Mine2d.game.backend.interactor;
[Interactor]
public class InventoryHandler
{
[Interaction(InteractorKind.Server, PacketType.Tick)]
public static void onServerTick() {
var ctx = Context.Get();
var players = ctx.GameState.Players;
foreach(var player in players) {
var inventory = player.Inventory.Inventory;
var hotbar = player.Inventory.Hotbar;
// Remove empty stacks
for(var i = 0; i < hotbar.Length; i++) {
if(hotbar[i]?.Count <= 0) {
hotbar[i] = null;
}
}
for (var i = 0; i< inventory.Length; i++) {
if(inventory[i]?.Count <= 0) {
inventory[i] = null;
}
}
}
}
}

View File

@ -4,7 +4,6 @@ using Mine2d.game.core;
using Mine2d.game.core.data;
using Mine2d.game.core.tiles;
using Mine2d.game.frontend.inventory;
using Mine2d.game.state;
namespace Mine2d.game.backend.interactor;
@ -20,35 +19,11 @@ public class Place
{
return;
}
if ((player.GetCenter() - packet.Target).LengthSquared() > Constants.BreakDistance * Constants.BreakDistance)
var stack = player.Inventory.Hotbar[packet.Slot];
if(stack == null || stack.Count <= 0)
{
return;
}
if (PlayerEntity.HasCollisionWithAnyPlayer(packet.Target))
{
return;
}
if (ctx.GameState.World.HasChunkAt(packet.Target))
{
var chunk = ctx.GameState.World.GetChunkAt(packet.Target);
var tile = chunk.GetTileAt(packet.Target);
var tileId = tile.Id;
if(tileId == (int)Tiles.Workbench) {
ctx.FrontendGameState.OpenInventory = InventoryKind.Workbench;
}
if (tileId != 0 || player.Inventory.Hotbar[packet.Slot] == null || player.Inventory.Hotbar[packet.Slot]?.Count <= 0)
{
return;
}
player.Inventory.Hotbar[packet.Slot].Count--;
var itemId = player.Inventory.Hotbar[packet.Slot].Id;
if (player.Inventory.Hotbar[packet.Slot].Count <= 0)
{
player.Inventory.Hotbar[packet.Slot] = null;
}
var itemTileId = ctx.TileRegistry.GetTileIdByItemId(itemId);
chunk.SetTileAt(packet.Target, STile.From(itemTileId));
}
ctx.ItemRegistry.GetItem(stack.Id).Interact(stack, packet.Target, player);
}
}

View File

@ -22,9 +22,18 @@ public enum DebugCommand {
[DebugCommand("", "Disables gravity and collision")]
NoClip,
[DebugCommand(" <item> <amount>", "Gives you an item")]
[DebugCommand("<scale>", "Sets the scale of the world")]
GameScale,
[DebugCommand("", "Disables fog")]
NoFog,
[DebugCommand(" <item> [amount]", "Gives you an item")]
Give,
[DebugCommand("<kind>", "Toggles the debug overlay")]
Overlay,
[DebugCommand("", "Lists all commands")]
Help,

View File

@ -26,8 +26,8 @@ public class PlayerEntity
if (ds.NoClip)
{
player.Position += new Vector2(
inputState.GetAxis(InputAxis.Horizontal) * 2,
inputState.GetAxis(InputAxis.Vertical) * 2
inputState.GetAxis(InputAxis.Horizontal) * 4,
inputState.GetAxis(InputAxis.Vertical) * 4
);
return;
}

View File

@ -0,0 +1,43 @@
using Mine2d.game.core.data;
using Mine2d.game.state;
namespace Mine2d.game.core.items;
public class BlockItem : Item
{
public BlockItem(ItemId id, string name, string[] textureName) : base(id, name, textureName)
{
}
public BlockItem(ItemId id, string name, string textureName) : base(id, name, textureName)
{
}
public override void Interact(ItemStack stack, Vector2 target, Player player)
{
var ctx = Context.Get();
if ((player.GetCenter() - target).LengthSquared() > Constants.BreakDistance * Constants.BreakDistance)
{
return;
}
if (PlayerEntity.HasCollisionWithAnyPlayer(target))
{
return;
}
if (ctx.GameState.World.HasChunkAt(target))
{
var chunk = ctx.GameState.World.GetChunkAt(target);
var tile = chunk.GetTileAt(target);
var tileId = tile.Id;
if (tileId != 0)
{
return;
}
stack.Count--;
var itemId = stack.Id;
var itemTileId = ctx.TileRegistry.GetTileIdByItemId(itemId);
chunk.SetTileAt(target, STile.From(itemTileId));
}
}
}

View File

@ -1,4 +1,5 @@
using Mine2d.game.core.data;
using Mine2d.game.state;
namespace Mine2d.game.core.items;
@ -27,7 +28,7 @@ public class Item
var ctx = Context.Get();
var renderer = ctx.Renderer;
var scale = ctx.FrontendGameState.Settings.GameScale;
var targetPos = (position - ctx.FrontendGameState.Camera.Position) * scale -
var targetPos = ((position - ctx.FrontendGameState.Camera.Position) * scale) -
new Vector2(4 * scale, 6 * scale);
renderer.DrawTexture(this.texture, (int)targetPos.X, (int)targetPos.Y, 8 * scale, 8 * scale);
}
@ -36,4 +37,7 @@ public class Item
{
return this.texture;
}
public virtual void Interact(ItemStack stack, Vector2 position, Player player) {
}
}

View File

@ -8,8 +8,8 @@ public class ItemRegistry
public void RegisterItems()
{
this.Register(ItemId.Stone, new Item(ItemId.Stone, "Stone", new[] { "stone" }));
this.Register(ItemId.Workbench, new Item(ItemId.Workbench, "Workbench", new[] { "workbench" }));
this.Register(ItemId.Stone, new BlockItem(ItemId.Stone, "Stone", new[] { "stone" }));
this.Register(ItemId.Workbench, new BlockItem(ItemId.Workbench, "Workbench", new[] { "workbench" }));
this.Register(ItemId.RawIron, new Item(ItemId.RawCobalt, "Raw Iron", "items.raw-iron" ));
this.Register(ItemId.RawCopper, new Item(ItemId.RawCopper, "Raw Copper", "items.raw-copper" ));
this.Register(ItemId.RawTin, new Item(ItemId.RawTin, "Raw Tin", "items.raw-tin" ));

View File

@ -1,3 +1,4 @@
using Mine2d.engine.lib;
using Mine2d.game.core.data;
using Mine2d.game.core.tiles;
@ -19,6 +20,7 @@ public class ChunkGenerator
return chunk;
}
public static readonly OpenSimplexNoise Noise = new();
public static Chunk CreateChunk(int x, int y)
{
var fill = new STile
@ -30,7 +32,10 @@ public class ChunkGenerator
{
for (var j = 0; j < Constants.ChunkSize; j++)
{
fill.Id = (int)wg.GetRandomOreAt(j + y*32);
var n = (Noise.coherentNoise(i + (x * 32), j + (y * 32), 0, 1, 25, 0.5f, 0.9f));
// Console.WriteLine(i * (x * 32) + " "+ j * (y * 32));
if(n > 0.08) continue;
fill.Id = (int)wg.GetRandomOreAt(j + (y * 32));
chunk.SetTile(i, j, fill);
}
}

View File

@ -1,3 +1,4 @@
using Mine2d.engine.lib;
using Mine2d.game.core.tiles;
namespace Mine2d.game.core.world;

View File

@ -47,6 +47,9 @@ public class DebugInput
"give" => DebugCommand.Give,
"help" => DebugCommand.Help,
"noclip" => DebugCommand.NoClip,
"nofog" => DebugCommand.NoFog,
"overlay" => DebugCommand.Overlay,
"gamescale" => DebugCommand.GameScale,
_ => DebugCommand.Unknown
};
var Args = split.Length > 1 ? split[1..] : Array.Empty<string>();

View File

@ -1,5 +1,6 @@
using Mine2d.engine;
using Mine2d.game.core;
using Mine2d.game.core.world;
namespace Mine2d.game.frontend.renderer;
@ -41,8 +42,17 @@ public class WorldRenderer : IRenderer
var scale = ctx.FrontendGameState.Settings.GameScale;
var camera = Context.Get().FrontendGameState.Camera;
Renderer.ProcessStatus(SDL_SetTextureBlendMode(this.light, SDL_BlendMode.SDL_BLENDMODE_BLEND));
var player = PlayerEntity.GetSelf();
foreach (var (_, chunk) in world.Chunks)
{
if (player == null)
{
continue;
}
if ((player.Position - new Vector2(chunk.X * Constants.ChunkSize * Constants.TileSize, chunk.Y * Constants.ChunkSize * Constants.TileSize)).Length() > 1300)
{
continue;
}
for (var y = 0; y < Constants.ChunkSize; y++)
{
for (var x = 0; x < Constants.ChunkSize; x++)
@ -64,17 +74,34 @@ public class WorldRenderer : IRenderer
);
}
Renderer.ProcessStatus(SDL_SetRenderTarget(ctx.Renderer.GetRaw(), IntPtr.Zero));
if (stile.Id == 0)
if (stile.Id != 0)
{
continue;
var tile = tileRegistry.GetTile(stile.Id);
tile.Render(drawX, drawY, stile);
}
var tile = tileRegistry.GetTile(stile.Id);
tile.Render(drawX, drawY, stile);
// Console.WriteLine(
// (chunk.Y * Constants.ChunkSize) + y + " "+
// (chunk.X * Constants.ChunkSize) + x
// );
if (ctx.FrontendGameState.DebugState.Overlay == "noise")
{
ctx.Renderer.DrawText("" + Math.Round(ChunkGenerator.Noise.coherentNoise(
(chunk.X * Constants.ChunkSize) + x,
(chunk.Y * Constants.ChunkSize) + y,
0
), 4),
(drawX - (int)camera.Position.X) * scale,
(drawY - (int)camera.Position.Y) * scale);
}
}
}
}
Renderer.ProcessStatus(SDL_SetRenderTarget(ctx.Renderer.GetRaw(), IntPtr.Zero));
if (ctx.FrontendGameState.DebugState.NoFog)
{
return;
}
Renderer.ProcessStatus(SDL_SetTextureBlendMode(this.overlay, SDL_BlendMode.SDL_BLENDMODE_MUL));
Renderer.ProcessStatus(SDL_RenderCopy(ctx.Renderer.GetRaw(), this.overlay, IntPtr.Zero, IntPtr.Zero));
Renderer.ProcessStatus(SDL_SetRenderTarget(ctx.Renderer.GetRaw(), IntPtr.Zero));

View File

@ -27,12 +27,14 @@ public class DebugState {
public string ConsoleInput { get; set; } = "";
public List<string> ConsoleHistory { get; set; } = new();
public int ConsoleHistoryIndex { get; set; } = 0;
public bool NoClip { get; set; } = false;
public bool NoClip { get; set; } = true;
public bool NoFog { get; set; } = false;
public string Overlay { get; set; } = "none";
}
public class Settings
{
public int GameScale { get; set; } = 6;
public int GameScale { get; set; } = 1;
public int UiScale { get; set; } = 4;
public bool ShowCollision { get; set; } = true;
public bool Fullscreen { get; set; } = false;