building profiling tools and refactoring networking
This commit is contained in:
@@ -49,7 +49,7 @@
|
||||
<TrimmerRootAssembly Include="Microsoft.Xna.Framework.Content.ContentTypeReader" Visible="false" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Assets\Scripts\MainMenu.lua">
|
||||
<!--None Update="Assets\Scripts\MainMenu.lua">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Assets\Scripts\menu.lua">
|
||||
@@ -57,8 +57,8 @@
|
||||
</None>
|
||||
<None Update="Assets\Scripts\SingleplayerMenu.lua">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Assets\Textures\icon.png">
|
||||
</None-->
|
||||
<None Update="assets\Textures\icon.png">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath></PackagePath>
|
||||
</None>
|
||||
@@ -89,9 +89,9 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Assets\Sound\mu\" />
|
||||
<Folder Include="assets\sound\mu\" />
|
||||
</ItemGroup>
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="xcopy "$(ProjectDir)Assets\*.*" "$(TargetDir)Assets\\" /E /I /F /Y" />
|
||||
<Exec Command="xcopy "$(ProjectDir)assets\*.*" "$(TargetDir)assets\\" /E /I /F /Y" />
|
||||
</Target>
|
||||
</Project>
|
@@ -15,35 +15,28 @@ using CaveGame.Server;
|
||||
using System.Threading.Tasks;
|
||||
using CaveGame.Core.Game.Items;
|
||||
using CaveGame.Core.Inventory;
|
||||
using DataManagement;
|
||||
|
||||
namespace CaveGame.Client
|
||||
{
|
||||
public class CaveGameGL : Microsoft.Xna.Framework.Game
|
||||
{
|
||||
// TODO: If running local server, shutdown server when player leaves the world
|
||||
public GameSettings GameSettings { get; set; }
|
||||
public IGameContext CurrentGameContext { get; set; }
|
||||
private IGameContext PreviousGameContext { get; set; }
|
||||
|
||||
#region Game States
|
||||
public GameClient GameClientContext;
|
||||
public Menu.MenuManager MenuContext;
|
||||
public Menu.Settings SettingsContext;
|
||||
#endregion
|
||||
|
||||
public GameClient GameClientContext { get; private set; }
|
||||
public Menu.MenuManager MenuContext { get; private set; }
|
||||
public Menu.Settings SettingsContext { get; private set; }
|
||||
public GraphicsEngine GraphicsEngine { get; private set; }
|
||||
public GraphicsDeviceManager GraphicsDeviceManager { get; private set; }
|
||||
public SpriteBatch SpriteBatch { get; private set; }
|
||||
#region GameComponents
|
||||
public CommandBar Console { get; private set; }
|
||||
public CommandBar Console { get; private set; } // TOOD: Change Name of CommandBar class to Console
|
||||
public FrameCounter FPSCounter { get; private set; }
|
||||
public Splash Splash { get; private set; }
|
||||
#endregion
|
||||
|
||||
public static float ClickTimer;
|
||||
|
||||
|
||||
|
||||
public SteamManager SteamManager { get; private set; }
|
||||
public static float ClickTimer { get; set; }
|
||||
|
||||
|
||||
public void OnSetFPSLimit(int limit)
|
||||
{
|
||||
@@ -57,7 +50,7 @@ namespace CaveGame.Client
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSetChatSize(GameChatSize size) {}
|
||||
public void OnSetChatSize(GameChatSize size) { }
|
||||
|
||||
public void OnSetFullscreen(bool full)
|
||||
{
|
||||
@@ -78,32 +71,45 @@ namespace CaveGame.Client
|
||||
|
||||
// join local (singleplayer server
|
||||
public void EnterLocalGame(WorldMetadata meta)
|
||||
{
|
||||
{
|
||||
var serverCFG = new ServerConfig
|
||||
{
|
||||
Port = 40270, // singleplayer server uses slightly different port
|
||||
World = meta.Name,
|
||||
ServerName = $"LocalServer [{meta.Name}] ",
|
||||
ServerName = $"LocalServer [{meta.Name}] ",
|
||||
ServerMOTD = "Singleplayer game world.",
|
||||
};
|
||||
var worldMDT = meta;
|
||||
LocalServer server = new LocalServer(serverCFG, worldMDT);
|
||||
server.Output = Console;
|
||||
Task.Run(() => {
|
||||
server.Start();
|
||||
server.Run();
|
||||
});
|
||||
this.CurrentGameContext = this.GameClientContext;
|
||||
this.GameClientContext.NetworkUsername = "Player";
|
||||
this.GameClientContext.ConnectAddress = "127.0.0.1:40270";
|
||||
}
|
||||
Task.Run(server.Start);
|
||||
|
||||
StartClient(SteamManager.SteamUsername, "127.0.0.1:40270");
|
||||
CurrentGameContext = GameClientContext;
|
||||
GameClientContext.OnShutdown += server.Shutdown;
|
||||
}
|
||||
|
||||
|
||||
public void StartClient(string userName, string address)
|
||||
{
|
||||
GameClientContext?.Dispose();
|
||||
GameClientContext = new GameClient(this);
|
||||
GameClientContext.NetworkUsername = userName;
|
||||
GameClientContext.ConnectAddress = address;
|
||||
CurrentGameContext = GameClientContext;
|
||||
}
|
||||
|
||||
|
||||
public CaveGameGL()
|
||||
{
|
||||
IsMouseVisible = true;
|
||||
Content.RootDirectory = "Assets";
|
||||
Window.AllowUserResizing = true;
|
||||
Window.AllowAltF4 = true;
|
||||
|
||||
GameSettings = Configuration.Load<GameSettings>("settings.xml", true);
|
||||
SteamManager = new SteamManager(this);
|
||||
|
||||
|
||||
GraphicsDeviceManager = new GraphicsDeviceManager(this)
|
||||
{
|
||||
PreferredBackBufferWidth = 1280,
|
||||
@@ -113,41 +119,29 @@ namespace CaveGame.Client
|
||||
PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8
|
||||
};
|
||||
|
||||
|
||||
IsMouseVisible = true;
|
||||
Content.RootDirectory = "Assets";
|
||||
Window.AllowUserResizing = true;
|
||||
Window.AllowAltF4 = true;
|
||||
|
||||
GraphicsEngine = new GraphicsEngine();
|
||||
|
||||
|
||||
Splash = new Splash();
|
||||
|
||||
FPSCounter = new FrameCounter(this);
|
||||
Components.Add(FPSCounter);
|
||||
|
||||
#if DEBUG
|
||||
GraphicsEngine.LoadingDelay = 0.05f;
|
||||
Splash.SplashTimer = 5f;
|
||||
Splash.SplashTimer = 3f;
|
||||
#endif
|
||||
OnSetFPSLimit(GameSettings.FPSLimit);
|
||||
}
|
||||
|
||||
void Window_ClientSizeChanged(object sender, EventArgs e)
|
||||
{
|
||||
GraphicsEngine.WindowSize = Window.ClientBounds.Size.ToVector2();
|
||||
if (GameClientContext != null)
|
||||
{
|
||||
GameClientContext.Camera.Bounds = Window.ClientBounds;
|
||||
GameClientContext.Camera._screenSize = new Vector2(Window.ClientBounds.Width, Window.ClientBounds.Height);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Window_ClientSizeChanged(object sender, EventArgs e) => GraphicsEngine.WindowSize = Window.ClientBounds.Size.ToVector2();
|
||||
|
||||
|
||||
#region GameConsole Commands
|
||||
private void OnTeleportCommand(CommandBar sender, Command command, params string[] args)
|
||||
{
|
||||
if (args.Length < 2)
|
||||
{
|
||||
sender.Out("Please provide a valid coordinate!", Color.Red);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -182,7 +176,7 @@ namespace CaveGame.Client
|
||||
{
|
||||
if (CurrentGameContext == GameClientContext)
|
||||
{
|
||||
GameClientContext.OverrideDisconnect();
|
||||
GameClientContext.Disconnect();
|
||||
|
||||
} else
|
||||
{
|
||||
@@ -201,7 +195,6 @@ namespace CaveGame.Client
|
||||
TakeScreenshot();
|
||||
sender.Out("Screenshot taken!");
|
||||
}
|
||||
|
||||
}
|
||||
private void SendAdminCommand(string command, params string[] args) => GameClientContext.Send(new AdminCommandPacket(command, args, GameClientContext.MyPlayer.EntityNetworkID));
|
||||
private void CmdTimeCommand(CommandBar sender, Command command, params string[] args)
|
||||
@@ -245,16 +238,22 @@ namespace CaveGame.Client
|
||||
}
|
||||
sender.Out("No item found with matching name!");
|
||||
}
|
||||
#endregion
|
||||
|
||||
protected override void Initialize()
|
||||
public void GoToMainMenu()
|
||||
{
|
||||
Window.TextInput += TextInputManager.OnTextInput;
|
||||
Window.ClientSizeChanged += new EventHandler<EventArgs>(Window_ClientSizeChanged);
|
||||
OnSetFullscreen(GameSettings.Fullscreen);
|
||||
|
||||
|
||||
Console = new CommandBar(this);
|
||||
CurrentGameContext = MenuContext;
|
||||
MenuContext.CurrentPage = MenuContext.Pages["mainmenu"];
|
||||
}
|
||||
public void GoToTimeoutPage(string timeout)
|
||||
{
|
||||
CurrentGameContext = MenuContext;
|
||||
MenuContext.CurrentPage = MenuContext.Pages["timeoutmenu"];
|
||||
MenuContext.TimeoutMessage = timeout;
|
||||
}
|
||||
|
||||
private void InitCommands()
|
||||
{
|
||||
// epic new .NET 5 feature
|
||||
Command[] commands =
|
||||
{
|
||||
@@ -266,21 +265,26 @@ namespace CaveGame.Client
|
||||
new ("time", "Set/Get time of day", new List<string> { "time" }, CmdTimeCommand),
|
||||
new ("sv_summon", "Summon an entity", new List<string>{"entityid, xpos, ypos, metadatastring" }, CmdRequestSummonEntity),
|
||||
new ("gimme", "Gives you an item", new List<string>{"itemid", "amount"}, CmdRequestItemstack),
|
||||
|
||||
|
||||
};
|
||||
foreach (var command in commands)
|
||||
Console.BindCommandInformation(command);
|
||||
commands.ForEach(c => Console.BindCommandInformation(c));
|
||||
//commands.ForEach(Console.BindCommandInformation);
|
||||
}
|
||||
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
Window.TextInput += TextInputManager.OnTextInput;
|
||||
Window.ClientSizeChanged += new EventHandler<EventArgs>(Window_ClientSizeChanged);
|
||||
OnSetFullscreen(GameSettings.Fullscreen);
|
||||
|
||||
Console = new CommandBar(this);
|
||||
InitCommands();
|
||||
|
||||
GameConsole.SetInstance(Console);
|
||||
Components.Add(Console);
|
||||
|
||||
FPSCounter = new FrameCounter(this);
|
||||
Components.Add(FPSCounter);
|
||||
|
||||
|
||||
SteamManager.Initialize();
|
||||
Components.Add(SteamManager);
|
||||
|
||||
base.Initialize();
|
||||
}
|
||||
|
||||
@@ -300,6 +304,7 @@ namespace CaveGame.Client
|
||||
MenuContext = new MenuManager(this);
|
||||
GameClientContext = new GameClient(this);
|
||||
SettingsContext = new Settings(this);
|
||||
|
||||
Window.TextInput += SettingsContext.OnTextInput;
|
||||
CurrentGameContext = MenuContext;
|
||||
}
|
||||
|
@@ -47,6 +47,8 @@ namespace CaveGame.Client
|
||||
|
||||
public class SteamManager: GameComponent, ISteamManager
|
||||
{
|
||||
|
||||
|
||||
// api members
|
||||
public bool HasAchievement(GameSteamAchievement achievement)
|
||||
{
|
||||
@@ -63,6 +65,7 @@ namespace CaveGame.Client
|
||||
//
|
||||
public SteamManager Instance { get; set; }
|
||||
|
||||
public string SteamUsername => SteamEnabled ? SteamFriends.GetPersonaName() : "Player1";
|
||||
|
||||
public bool SteamEnabled { get; set; }
|
||||
public bool SteamInitialized { get; private set; }
|
||||
@@ -71,7 +74,7 @@ namespace CaveGame.Client
|
||||
Microsoft.Xna.Framework.Game game;
|
||||
bool receivedUserStats;
|
||||
|
||||
DelayedTask callbackRun;
|
||||
RepeatingIntervalTask callbackRun;
|
||||
|
||||
public SteamManager(Microsoft.Xna.Framework.Game _game) : base(_game)
|
||||
{
|
||||
@@ -90,7 +93,7 @@ namespace CaveGame.Client
|
||||
|
||||
if (SteamInitialized)
|
||||
{
|
||||
callbackRun = new DelayedTask(() => Steamworks.SteamAPI.RunCallbacks(), 1 / 20.0f);
|
||||
callbackRun = new RepeatingIntervalTask(() => Steamworks.SteamAPI.RunCallbacks(), 1 / 20.0f);
|
||||
m_OverlayActivated = Steamworks.Callback<Steamworks.GameOverlayActivated_t>.Create(Steam_OnOverlayActivated);
|
||||
Steamworks.Callback<Steamworks.SteamShutdown_t>.Create(Steam_OnShutdown);
|
||||
Steamworks.Callback<Steamworks.ScreenshotRequested_t>.Create(Steam_OnScreenshotRequested);
|
||||
|
@@ -9,12 +9,13 @@
|
||||
<Import_RootNamespace>CaveGame.Client</Import_RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DebugTools\DebugInformation.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DebugTools\GraphRenderer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DebugTools\Profiler.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)GameSounds.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DebugTools\ChunkGridLineRenderer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)GameSettings.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Entities\LocalPlayer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Entities\PeerPlayer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Entities\ClientPlayer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)InputManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Input\KeyPressDetector.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Menu\Multiplayer.cs" />
|
||||
@@ -28,7 +29,7 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)LocalWorld.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Menu\Settings.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Menu\UITheme.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)NetworkClient.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Network\NetworkClient.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)IGameContext.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)PauseMenu.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)SavedWorldManager.cs" />
|
||||
@@ -37,6 +38,8 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)UI\ScrollRect.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)UI\UINode.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)UI\UIRect.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)World\ChunkRenderer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)World\Sky.cs" />
|
||||
<Compile Include="..\Client\Menu\MenuManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)PlayerContainerFrontend.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)UI\Label.cs" />
|
||||
@@ -52,4 +55,7 @@
|
||||
<ItemGroup>
|
||||
<MonoGameContentReference Include="$(MSBuildThisFileDirectory)Content\Content.mgcb" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="$(MSBuildThisFileDirectory)Network\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
10
Client/DebugTools/DebugInformation.cs
Normal file
10
Client/DebugTools/DebugInformation.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Client.DebugTools
|
||||
{
|
||||
class DebugInformation
|
||||
{
|
||||
}
|
||||
}
|
111
Client/DebugTools/GraphRenderer.cs
Normal file
111
Client/DebugTools/GraphRenderer.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using CaveGame.Core;
|
||||
using DataManagement;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Client.DebugTools
|
||||
{
|
||||
public interface GraphSample {
|
||||
|
||||
double Value { get; set; }
|
||||
}
|
||||
public interface GraphDataset<TSample> where TSample: GraphSample {
|
||||
Color Color { get; set; }
|
||||
int SampleCount { get; set; }
|
||||
List<TSample> Data { get; set; }
|
||||
}
|
||||
|
||||
public class GraphRecorder<TSample>: GraphDataset<TSample> where TSample : GraphSample
|
||||
{
|
||||
public Color Color { get; set; }
|
||||
public int SampleCount { get; set; }
|
||||
public List<TSample> Data { get; set; }
|
||||
public TSample Average;
|
||||
|
||||
public GraphRecorder()
|
||||
{
|
||||
Data = new List<TSample>();
|
||||
}
|
||||
|
||||
|
||||
public void Push(TSample sample)
|
||||
{
|
||||
Data.Add(sample);
|
||||
if (Data.Count > SampleCount)
|
||||
{
|
||||
Data.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class GraphRenderer<TSample> where TSample : GraphSample
|
||||
{
|
||||
public Vector2 ScreenPosition { get; set; }
|
||||
public Vector2 GraphSize { get; set; }
|
||||
public float XAxisMin { get; set; }
|
||||
public float XAxisMax { get; set; }
|
||||
public float YAxisMin { get; set; }
|
||||
public float YAxisMax { get; set; }
|
||||
public string GraphName { get; set; }
|
||||
|
||||
public float Scale { get; set; }
|
||||
public Color BackgroundColor { get; set; }
|
||||
public GraphRecorder<TSample> DataSet { get; set; }
|
||||
private void DrawBackground(GraphicsEngine GFX)
|
||||
{
|
||||
GFX.Rect(BackgroundColor, ScreenPosition, GraphSize);
|
||||
GFX.Text(GraphName, ScreenPosition - GFX.Fonts.Arial10.MeasureString(GraphName).GetY());
|
||||
}
|
||||
|
||||
private double ScaleDatapoint(TSample datapoint)
|
||||
{
|
||||
|
||||
return datapoint.Value * Scale;
|
||||
}
|
||||
|
||||
private void DrawReferenceLines(GraphicsEngine GFX)
|
||||
{
|
||||
|
||||
Vector2 datapoint = new Vector2(0, GraphSize.Y - (float)Scale * (1 / 60.0f));
|
||||
Vector2 linePos = ScreenPosition + datapoint;
|
||||
GFX.Line(new Color(0.7f, 0.7f, 0.7f), linePos, linePos+GraphSize.GetX());
|
||||
GFX.Text(GFX.Fonts.Arial10, "60fps", ScreenPosition + datapoint.GetY(), Color.White, TextXAlignment.Right, TextYAlignment.Center );
|
||||
}
|
||||
|
||||
private void DrawLineGraph(GraphicsEngine GFX, GraphDataset<TSample> data)
|
||||
{
|
||||
Vector2 lastDatapoint = GraphSize.GetY();
|
||||
float spacing = GraphSize.X / data.SampleCount;
|
||||
|
||||
int start = Math.Max(data.Data.Count - data.SampleCount, 0);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for (int idx = start; idx < data.Data.Count; idx++)
|
||||
{
|
||||
Vector2 datapoint = new Vector2(spacing * idx, GraphSize.Y - (float)ScaleDatapoint(data.Data[idx]));
|
||||
|
||||
GFX.Line(data.Color, ScreenPosition + lastDatapoint, ScreenPosition + datapoint);
|
||||
|
||||
lastDatapoint = datapoint;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void Draw(GraphicsEngine GFX)
|
||||
{
|
||||
DrawBackground(GFX);
|
||||
DrawReferenceLines(GFX);
|
||||
DrawLineGraph(GFX, DataSet);
|
||||
}
|
||||
}
|
||||
}
|
133
Client/DebugTools/Profiler.cs
Normal file
133
Client/DebugTools/Profiler.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using CaveGame.Core;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Client.DebugTools
|
||||
{
|
||||
public class ProfilerEntry
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Stopwatch Timer { get; set; }
|
||||
public double RecordedTime { get; set; }
|
||||
|
||||
public ProfilerEntry()
|
||||
{
|
||||
Timer = new Stopwatch();
|
||||
}
|
||||
}
|
||||
public class ProfilerRegion
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public Stopwatch Timer { get; set; }
|
||||
public double RecordedTime { get; set; }
|
||||
|
||||
|
||||
public Dictionary<string, ProfilerEntry> Functions;
|
||||
|
||||
public ProfilerRegion()
|
||||
{
|
||||
Timer = new Stopwatch();
|
||||
Functions = new Dictionary<string, ProfilerEntry>();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Profiler
|
||||
{
|
||||
static ProfilerRegion currentRegion;
|
||||
static ProfilerEntry currentFunction;
|
||||
public static Dictionary<string, ProfilerRegion> Regions = new Dictionary<string, ProfilerRegion>();
|
||||
|
||||
public static void StartRegion(string regionName)
|
||||
{
|
||||
if (!Regions.ContainsKey(regionName))
|
||||
Regions.Add(regionName, new ProfilerRegion { Name = regionName });
|
||||
|
||||
currentRegion = Regions[regionName];
|
||||
//currentRegion.Timer.Reset();
|
||||
currentRegion.Timer.Start();
|
||||
}
|
||||
|
||||
public static void EndRegion(string regionName)
|
||||
{
|
||||
currentRegion = Regions[regionName];
|
||||
currentRegion.Timer.Stop();
|
||||
currentRegion.RecordedTime = currentRegion.Timer.Elapsed.TotalMilliseconds;
|
||||
currentRegion.Timer.Reset();
|
||||
}
|
||||
|
||||
public static void EndRegion()
|
||||
{
|
||||
if (currentRegion == null)
|
||||
return;
|
||||
|
||||
currentRegion.Timer.Stop();
|
||||
currentRegion.RecordedTime = currentRegion.Timer.Elapsed.TotalMilliseconds;
|
||||
currentRegion.Timer.Reset();
|
||||
}
|
||||
public static void Start(string functionName)
|
||||
{
|
||||
if (currentRegion == null)
|
||||
return;
|
||||
|
||||
if (!currentRegion.Functions.ContainsKey(functionName))
|
||||
currentRegion.Functions.Add(functionName, new ProfilerEntry { Name = functionName });
|
||||
currentFunction = currentRegion.Functions[functionName];
|
||||
//currentFunction.Timer.Reset();
|
||||
currentFunction.Timer.Start();
|
||||
}
|
||||
public static void Track(string functionName, Action action)
|
||||
{
|
||||
Start(functionName);
|
||||
action.Invoke();
|
||||
End(functionName);
|
||||
}
|
||||
public static void End()
|
||||
{
|
||||
if (currentFunction == null)
|
||||
return;
|
||||
currentFunction.Timer.Stop();
|
||||
currentFunction.RecordedTime = currentFunction.Timer.Elapsed.TotalMilliseconds;
|
||||
currentFunction.Timer.Reset();
|
||||
}
|
||||
public static void End(string funcname)
|
||||
{
|
||||
currentFunction = currentRegion.Functions[funcname];
|
||||
currentFunction.Timer.Stop();
|
||||
currentFunction.RecordedTime = currentFunction.Timer.Elapsed.TotalMilliseconds;
|
||||
currentFunction.Timer.Reset();
|
||||
}
|
||||
|
||||
const int percent_accuracy = 0;
|
||||
|
||||
public static void Draw(GraphicsEngine GFX)
|
||||
{
|
||||
|
||||
float renderHeight = 0;
|
||||
foreach (var dataset in Regions)
|
||||
{
|
||||
|
||||
var totalMS = dataset.Value.RecordedTime;
|
||||
double timeAccountedFor = totalMS;
|
||||
GFX.Text($"{dataset.Key} : {Math.Round(totalMS, 2)}ms", new Vector2(50, 100 + renderHeight));
|
||||
renderHeight += 12;
|
||||
foreach (var subset in dataset.Value.Functions)
|
||||
{
|
||||
var frac = subset.Value.RecordedTime / totalMS;
|
||||
timeAccountedFor -= subset.Value.RecordedTime;
|
||||
|
||||
GFX.Text($"{subset.Key} : {Math.Round(frac * 100)}% {Math.Round(subset.Value.RecordedTime, 2)}ms", new Vector2(70, 100 + renderHeight));
|
||||
renderHeight += 12;
|
||||
}
|
||||
var unaccountedFrac = timeAccountedFor / totalMS;
|
||||
if (unaccountedFrac > 0) {
|
||||
GFX.Text($"Other : {Math.Round(unaccountedFrac*100)}% {Math.Round(timeAccountedFor, 2)}ms", new Vector2(70, 100 + renderHeight));
|
||||
renderHeight += 12;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
using CaveGame.Core;
|
||||
using CaveGame.Core.Game.Entities;
|
||||
using CaveGame.Core.Generic;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Client.Game.Entities
|
||||
{
|
||||
public abstract class ClientPlayer : Core.Game.Entities.Player
|
||||
{
|
||||
public override void Draw(GraphicsEngine gfx)
|
||||
{
|
||||
|
||||
Rectangle spriteFrame = new Rectangle(0, 0, 16, 24);
|
||||
|
||||
int flipSprite = 0;
|
||||
if (Facing == Direction.Left)
|
||||
flipSprite = 0;
|
||||
if (Facing == Direction.Right)
|
||||
flipSprite = 1;
|
||||
|
||||
|
||||
if (Walking)
|
||||
{
|
||||
spriteFrame = new Rectangle(16, 0, 16, 24);
|
||||
if (walkingAnimationTimer % 2 >= 1)
|
||||
spriteFrame = new Rectangle(32, 0, 16, 24);
|
||||
}
|
||||
|
||||
if (!OnGround)
|
||||
spriteFrame = new Rectangle(48, 0, 16, 24);
|
||||
|
||||
|
||||
DrawHealth(gfx);
|
||||
gfx.Sprite(gfx.Player, TopLeft, spriteFrame, Color, Rotation.Zero, new Vector2(0, 0), 1, (SpriteEffects)flipSprite, 0);
|
||||
}
|
||||
}
|
||||
}
|
@@ -14,7 +14,7 @@ namespace CaveGame.Client.Game.Entities
|
||||
|
||||
|
||||
|
||||
public class LocalPlayer : ClientPlayer, IClientPhysicsObserver
|
||||
public class LocalPlayer : Player, IClientPhysicsObserver
|
||||
{
|
||||
float jumpEnergy;
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace CaveGame.Client.Game.Entities
|
||||
base.PhysicsStep(world, step);
|
||||
}
|
||||
|
||||
public virtual void ClientPhysicsTick(IClientWorld world, float step) => PhysicsStep(world, step);
|
||||
public override void ClientPhysicsTick(IClientWorld world, float step) => PhysicsStep(world, step);
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -1,25 +0,0 @@
|
||||
using CaveGame.Core;
|
||||
using CaveGame.Core.Game.Entities;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Client.Game.Entities
|
||||
{
|
||||
// Player entities that are controlled by other clients
|
||||
public class PeerPlayer : ClientPlayer, IClientPhysicsObserver
|
||||
{
|
||||
//public void ClientPhysicsTick(IClientWorld world, float step) => PhysicsStep(world, step);
|
||||
public override void Draw(GraphicsEngine GFX)
|
||||
{
|
||||
|
||||
Vector2 namebounds = GFX.Fonts.Arial8.MeasureString(DisplayName);
|
||||
GFX.Text(GFX.Fonts.Arial8, DisplayName, Position - new Vector2(namebounds.X/2, namebounds.Y), Color.White);
|
||||
base.Draw(GFX);
|
||||
}
|
||||
|
||||
public void ClientPhysicsTick(IClientWorld world, float step) => Position = Position.Lerp(NextPosition, 0.5f);
|
||||
}
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
//#define SERVER
|
||||
|
||||
using CaveGame.Client.UI;
|
||||
using CaveGame.Client.UI;
|
||||
using CaveGame.Core;
|
||||
using CaveGame.Core.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
@@ -31,7 +30,7 @@ namespace CaveGame.Client
|
||||
|
||||
inputBox = new TextInput();
|
||||
inputBox.ClearOnReturn = true;
|
||||
inputBox.Handler += client.SendChatMessage;
|
||||
inputBox.Handler += SendChatMessage;
|
||||
|
||||
MessageHistory = new List<Message>();
|
||||
Open = false;
|
||||
@@ -39,6 +38,13 @@ namespace CaveGame.Client
|
||||
Client = client;
|
||||
}
|
||||
|
||||
|
||||
public void SendChatMessage(object sender, string message)
|
||||
{
|
||||
Open = false;
|
||||
Client.Send(new ClientChatMessagePacket(message));
|
||||
}
|
||||
|
||||
public void OnTextInput(object sender, TextInputEventArgs args)
|
||||
{
|
||||
if (Client.Game.Console.Open)
|
||||
|
@@ -1,82 +1,89 @@
|
||||
//#define SERVER
|
||||
|
||||
using CaveGame;
|
||||
using CaveGame.Client;
|
||||
using CaveGame.Client.DebugTools;
|
||||
using CaveGame.Client.Game.Entities;
|
||||
using CaveGame.Client.UI;
|
||||
using CaveGame.Core;
|
||||
using CaveGame.Core.Game.Entities;
|
||||
using CaveGame.Core.Furniture;
|
||||
using CaveGame.Core.Game.Entities;
|
||||
using CaveGame.Core.Game.Items;
|
||||
using CaveGame.Core.Game.Tiles;
|
||||
using CaveGame.Core.Game.Walls;
|
||||
using CaveGame.Core.Generic;
|
||||
using CaveGame.Core.Inventory;
|
||||
using CaveGame.Core.Network;
|
||||
using CaveGame.Core.Game.Tiles;
|
||||
using CaveGame.Core.Game.Walls;
|
||||
using CaveGame.Core.Network.Packets;
|
||||
using DataManagement;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using CaveGame.Client.Game.Entities;
|
||||
using CaveGame.Core.Game.Inventory;
|
||||
using CaveGame.Core.Game.Items;
|
||||
using CaveGame.Client.DebugTools;
|
||||
using CaveGame.Core.Network.Packets;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using CaveGame.Core.Game;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CaveGame.Client
|
||||
{
|
||||
using BombEntity = Core.Game.Entities.Bomb;
|
||||
using ArrowEntity = Core.Game.Entities.Arrow;
|
||||
using WurmholeEntity = Core.Game.Entities.Wurmhole;
|
||||
using DynamiteEntity = Core.Game.Entities.Dynamite;
|
||||
|
||||
|
||||
|
||||
|
||||
using ArrowEntity = Core.Game.Entities.Arrow;
|
||||
using BombEntity = Core.Game.Entities.Bomb;
|
||||
using DynamiteEntity = Core.Game.Entities.Dynamite;
|
||||
using WurmholeEntity = Core.Game.Entities.Wurmhole;
|
||||
|
||||
public delegate void ClientShutdown();
|
||||
|
||||
public class GameClient : IGameContext, IGameClient
|
||||
{
|
||||
public static float CameraZoom = 2.0f;
|
||||
public bool ChunkLock { get; set; }
|
||||
protected ChunkGridLineRenderer chunkGridTool;// = new ChunkGridLineRenderer();
|
||||
public bool ShowChunkBoundaries { get; set; }
|
||||
public CaveGameGL Game { get; private set; }
|
||||
public GameChat Chat { get; private set; }
|
||||
|
||||
public event ClientShutdown OnShutdown;
|
||||
|
||||
public string NetworkUsername { get; set; }
|
||||
public string ConnectAddress { get; set; }
|
||||
public bool Active { get; set; }
|
||||
|
||||
public static float CameraZoom = 2.0f;
|
||||
|
||||
public bool ShowChunkBoundaries { get; set; }
|
||||
|
||||
public CaveGameGL Game { get; private set; }
|
||||
public GameChat Chat { get; private set; }
|
||||
public LocalWorld World { get; private set; }
|
||||
public PlayerContainerFrontend Inventory { get; set; }
|
||||
public Camera2D Camera { get; }
|
||||
|
||||
protected NetworkClient NetClient { get; set; }
|
||||
|
||||
|
||||
protected struct FpsSample : GraphSample
|
||||
{
|
||||
public double Value { get; set; }
|
||||
|
||||
}
|
||||
|
||||
protected GraphRenderer<FpsSample> FPSGraph { get; private set; }
|
||||
|
||||
|
||||
Microsoft.Xna.Framework.Game IGameContext.Game => Game;
|
||||
IClientWorld IGameClient.World => World;
|
||||
//public Hotbar Hotbar { get; set; }
|
||||
public PlayerContainerFrontend Inventory { get; set; }
|
||||
public LocalWorld World { get; private set; }
|
||||
private NetworkClient gameClient;
|
||||
public Camera2D Camera { get; }
|
||||
|
||||
public int ChunkingRadius { get; set; }
|
||||
|
||||
int MyUserID;
|
||||
int MyPlayerID;
|
||||
|
||||
|
||||
|
||||
public Game.Entities.LocalPlayer MyPlayer { get; private set; }
|
||||
|
||||
private DelayedTask chunkUnloadingTask;
|
||||
DelayedTask playerStateReplicationTask;
|
||||
DelayedTask chunkLoadingTask;
|
||||
|
||||
private int IntitalScrollValue;
|
||||
|
||||
|
||||
PauseMenu PauseMenu { get; set; }
|
||||
|
||||
|
||||
private void onClientExit(TextButton sender, MouseState state)=>OverrideDisconnect();
|
||||
|
||||
public void OverrideDisconnect()
|
||||
{
|
||||
PauseMenu.Open = false;
|
||||
Disconnect();
|
||||
Game.CurrentGameContext = Game.MenuContext;
|
||||
}
|
||||
|
||||
protected List<RepeatingIntervalTask> ClientTasks { get; set; }
|
||||
|
||||
private Dictionary<PacketType, NetworkListener> NetworkEvents;
|
||||
private void InitNetworkEvents() => NetworkEvents = new Dictionary<PacketType, NetworkListener>()
|
||||
@@ -87,6 +94,10 @@ namespace CaveGame.Client
|
||||
[PacketType.sDownloadChunk] = DownloadChunk,
|
||||
[PacketType.sUpdateTile] = UpdateTile,
|
||||
[PacketType.sUpdateWall] = UpdateWall,
|
||||
|
||||
[PacketType.netPlaceTile] = UpdateTile,
|
||||
[PacketType.netPlaceWall] = UpdateWall,
|
||||
|
||||
[PacketType.sRejectLogin] = OnServerRejectLogin,
|
||||
[PacketType.sAcceptLogin] = OnServerAcceptLogin,
|
||||
[PacketType.sPlayerPeerJoined] = OnPeerJoined,
|
||||
@@ -107,51 +118,82 @@ namespace CaveGame.Client
|
||||
[PacketType.netPlayerState] = OnPlayerAnimationStateUpdate,
|
||||
};
|
||||
|
||||
internal void Dispose()
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public float ServerKeepAlive { get; set; }
|
||||
|
||||
public GameClient(CaveGameGL _game)
|
||||
{
|
||||
Game = _game;
|
||||
InitNetworkEvents();
|
||||
|
||||
|
||||
Game = _game;
|
||||
|
||||
MouseState mouse = Mouse.GetState();
|
||||
|
||||
World = new LocalWorld(this);
|
||||
Camera = new Camera2D(Game.GraphicsDevice.Viewport) { Zoom = CameraZoom };
|
||||
Camera = new Camera2D{ Zoom = CameraZoom };
|
||||
Chat = new GameChat(this);
|
||||
PauseMenu = new PauseMenu(this);
|
||||
Inventory = new PlayerContainerFrontend();
|
||||
|
||||
IntitalScrollValue = mouse.ScrollWheelValue;
|
||||
ClientTasks = new List<RepeatingIntervalTask>
|
||||
{
|
||||
new RepeatingIntervalTask(ReplicatePlayerState, 1 / 10.0f),
|
||||
new RepeatingIntervalTask(ChunkUnloadingCheck, 1/2.0f),
|
||||
new RepeatingIntervalTask(ChunkLoadingCheckUpdate, 1 / 2.0f),
|
||||
};
|
||||
|
||||
|
||||
FPSGraph = new GraphRenderer<FpsSample>
|
||||
{
|
||||
BackgroundColor = new Color(0.1f, 0.1f, 0.1f)*0.5f,
|
||||
ScreenPosition = new Vector2(50, 400),
|
||||
GraphSize = new Vector2(500, 200),
|
||||
GraphName = "FPS",
|
||||
YAxisMin = 0,
|
||||
Scale = 1000,
|
||||
YAxisMax = 120,
|
||||
DataSet = new GraphRecorder<FpsSample>
|
||||
{
|
||||
SampleCount = 500,
|
||||
Color = Color.Yellow,
|
||||
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
playerStateReplicationTask = new DelayedTask(ReplicatePlayerState, 1 / 10.0f);
|
||||
chunkUnloadingTask = new DelayedTask(ChunkUnloadingCheck, 1/2.0f);
|
||||
chunkLoadingTask = new DelayedTask(ChunkLoadingCheckUpdate, 1 / 2.0f);
|
||||
|
||||
|
||||
ChunkingRadius = 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void Uncouple()
|
||||
{
|
||||
PauseMenu.Open = false;
|
||||
|
||||
World?.ClientDisconnect(); // start cleaning up server
|
||||
|
||||
NetClient?.Logout(MyUserID, UserDisconnectReason.LogOff);
|
||||
World?.Dispose(); // destroy local world
|
||||
OnShutdown?.Invoke(); // bound to localserver (if it exists)
|
||||
//Dispose();
|
||||
}
|
||||
public void Send(Packet p)=>gameClient.SendPacket(p);
|
||||
public void SendChatMessage(object sender, string message)
|
||||
{
|
||||
Chat.Open = false;
|
||||
gameClient.SendPacket(new ClientChatMessagePacket(message));
|
||||
}
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
if (MyPlayer != null) {
|
||||
|
||||
World.ClientDisconnect();
|
||||
gameClient.SendPacket(new DisconnectPacket(MyPlayer.EntityNetworkID, UserDisconnectReason.LogOff));
|
||||
gameClient.Stop();
|
||||
}
|
||||
|
||||
Uncouple();
|
||||
Game.GoToMainMenu();
|
||||
}
|
||||
|
||||
public void ForcedDisconnect(string kickReason)
|
||||
{
|
||||
Uncouple();
|
||||
Game.GoToTimeoutPage(kickReason);
|
||||
}
|
||||
|
||||
private void ChunkUnloadingCheck()
|
||||
{
|
||||
|
||||
foreach (var chunkpair in World.Chunks)
|
||||
{
|
||||
if (!World.LoadedChunks.Contains(chunkpair.Key))
|
||||
@@ -160,10 +202,10 @@ namespace CaveGame.Client
|
||||
{
|
||||
World.Chunks.TryRemove(chunkpair.Key, out _);
|
||||
World.Lighting.UnregisterChunk(chunkpair.Key);
|
||||
chunkpair.Value.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
private void ChunkLoadingCheckUpdate()
|
||||
{
|
||||
@@ -187,7 +229,7 @@ namespace CaveGame.Client
|
||||
|
||||
if ((!World.Chunks.ContainsKey(chunkCoords)) && (!World.RequestedChunks.Contains(chunkCoords)))
|
||||
{
|
||||
gameClient.SendPacket(new RequestChunkPacket(chunkCoords));
|
||||
NetClient.SendPacket(new RequestChunkPacket(chunkCoords));
|
||||
World.RequestedChunks.Add(chunkCoords);
|
||||
}
|
||||
}
|
||||
@@ -195,24 +237,36 @@ namespace CaveGame.Client
|
||||
}
|
||||
}
|
||||
|
||||
public void Send(Packet p) => NetClient.SendPacket(p);
|
||||
|
||||
#region NetworkListenerMethods
|
||||
|
||||
public delegate void NetworkListener(NetworkMessage message);
|
||||
|
||||
private void OnPing(NetworkMessage message) { } // dont do jack
|
||||
|
||||
private void DownloadChunk(NetworkMessage message)
|
||||
{
|
||||
ChunkDownloadPacket chunkdata = new ChunkDownloadPacket(message.Packet.GetBytes());
|
||||
|
||||
Chunk chunk = chunkdata.StoredChunk;
|
||||
|
||||
// Did we ask for this chunk?
|
||||
if (World.RequestedChunks.Contains(chunk.Coordinates))
|
||||
Task.Run(() =>
|
||||
{
|
||||
//World.Chunks. Add(chunk.Coordinates, chunk);
|
||||
World.Chunks.TryAdd(chunk.Coordinates, chunk);
|
||||
World.RequestedChunks.Remove(chunk.Coordinates);
|
||||
World.Lighting.RegisterChunk(chunk);
|
||||
}
|
||||
//Stopwatch stopWatch = new Stopwatch();
|
||||
//stopWatch.Start();
|
||||
Chunk chunk = chunkdata.StoredChunk;
|
||||
//stopWatch.Stop();
|
||||
// GameConsole.Log($"ChunkDecode: {stopWatch.ElapsedMilliseconds}(ms)");
|
||||
|
||||
// Did we ask for this chunk?
|
||||
if (World.RequestedChunks.Contains(chunk.Coordinates))
|
||||
{
|
||||
//World.Chunks. Add(chunk.Coordinates, chunk);
|
||||
World.Chunks.TryAdd(chunk.Coordinates, chunk);
|
||||
World.RequestedChunks.Remove(chunk.Coordinates);
|
||||
World.Lighting.RegisterChunk(chunk);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
private void UpdateTile(NetworkMessage message)
|
||||
@@ -241,7 +295,7 @@ namespace CaveGame.Client
|
||||
{
|
||||
PlayerJoinedPacket packet = new PlayerJoinedPacket(message.Packet.GetBytes());
|
||||
|
||||
var player = new Game.Entities.PeerPlayer()
|
||||
var player = new Core.Game.Entities.Player()
|
||||
{
|
||||
EntityNetworkID = packet.EntityID,
|
||||
Color = packet.PlayerColor,
|
||||
@@ -260,7 +314,7 @@ namespace CaveGame.Client
|
||||
}
|
||||
private void OnEntityPhysUpdate(NetworkMessage message)
|
||||
{
|
||||
EntityPositionPacket packet = new EntityPositionPacket(message.Packet.GetBytes());
|
||||
EntityPhysicsStatePacket packet = new EntityPhysicsStatePacket(message.Packet.GetBytes());
|
||||
|
||||
var entity = World.FindEntityOfID(packet.EntityID);
|
||||
|
||||
@@ -463,11 +517,19 @@ namespace CaveGame.Client
|
||||
}
|
||||
|
||||
private void OnDamageTile(NetworkMessage msg)
|
||||
{
|
||||
// TODO: Implement damage texture onto tile
|
||||
// TODO: add audio for tile being damaged
|
||||
{
|
||||
//GameConsole.Log("WTF BRYH");
|
||||
DamageTilePacket packet = new DamageTilePacket(msg.Packet.GetBytes());
|
||||
|
||||
}
|
||||
var tile = World.GetTile(packet.Position.X, packet.Position.Y);
|
||||
|
||||
tile.Damage += (byte)packet.Damage;
|
||||
|
||||
if (tile.Damage >= tile.Hardness)
|
||||
{
|
||||
World.SetTile(packet.Position.X, packet.Position.Y, new Core.Game.Tiles.Air());
|
||||
}
|
||||
}
|
||||
|
||||
private void GiveItToMeDaddy(NetworkMessage msg)
|
||||
{
|
||||
@@ -512,31 +574,34 @@ namespace CaveGame.Client
|
||||
foreach (var name in packet.PlayerList.Where(str => str.Length > 0))
|
||||
GameConsole.Log($" {name}", Color.LightBlue);
|
||||
GameConsole.Log($"Requesting game session...");
|
||||
gameClient.SendPacket(new RequestJoinPacket(NetworkUsername));
|
||||
NetClient.SendPacket(new RequestJoinPacket(NetworkUsername));
|
||||
}
|
||||
|
||||
#endregion
|
||||
private void ReadIncomingPackets()
|
||||
{
|
||||
while (gameClient.HaveIncomingMessage())
|
||||
while (NetClient.HaveIncomingMessage())
|
||||
{
|
||||
NetworkMessage msg = gameClient.GetLatestMessage();
|
||||
NetworkMessage msg = NetClient.GetLatestMessage();
|
||||
foreach(var ev in NetworkEvents)
|
||||
if (ev.Key == msg.Packet.Type)
|
||||
{
|
||||
ServerKeepAlive = 0;
|
||||
ev.Value.Invoke(msg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawChunks(GraphicsEngine GFX)
|
||||
|
||||
float redrawTimer { get; set; }
|
||||
private void RedrawChunkBuffers(GraphicsEngine GFX)
|
||||
{
|
||||
if (drawTimer > (1/5.0f))
|
||||
foreach (var chunkpair in World.Chunks)
|
||||
{
|
||||
drawTimer = 0;
|
||||
Chunk.RefreshedThisFrame = false;
|
||||
foreach (var chunkpair in World.Chunks)
|
||||
{
|
||||
chunkpair.Value.Draw(GFX);
|
||||
}
|
||||
var chunk = chunkpair.Value;
|
||||
chunk.RedrawWallBuffer(GFX);
|
||||
chunk.RedrawTileBuffer(GFX);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,19 +614,19 @@ namespace CaveGame.Client
|
||||
|
||||
}
|
||||
|
||||
private void DrawChunkFGTextures(GraphicsEngine gfx)
|
||||
private void DrawChunkTileTextures(GraphicsEngine gfx)
|
||||
{
|
||||
foreach (var chunkpair in World.Chunks)
|
||||
{
|
||||
|
||||
Chunk chunk = chunkpair.Value;
|
||||
Vector2 pos = new Vector2(chunk.Coordinates.X * Globals.ChunkSize * Globals.TileSize, chunk.Coordinates.Y * Globals.ChunkSize * Globals.TileSize);
|
||||
if (chunk.ForegroundRenderBuffer != null)
|
||||
gfx.Sprite(chunk.ForegroundRenderBuffer, pos, Color.White);
|
||||
if (chunk.TileRenderBuffer != null)
|
||||
gfx.Sprite(chunk.TileRenderBuffer, pos, Color.White);
|
||||
|
||||
}
|
||||
}
|
||||
private void DrawChunkBGTextures(GraphicsEngine gfx)
|
||||
private void DrawChunkWallTextures(GraphicsEngine gfx)
|
||||
{
|
||||
foreach (var chunkpair in World.Chunks)
|
||||
{
|
||||
@@ -569,8 +634,8 @@ namespace CaveGame.Client
|
||||
Chunk chunk = chunkpair.Value;
|
||||
Vector2 pos = new Vector2(chunk.Coordinates.X * Globals.ChunkSize * Globals.TileSize, chunk.Coordinates.Y * Globals.ChunkSize * Globals.TileSize);
|
||||
|
||||
if (chunk.BackgroundRenderBuffer != null)
|
||||
gfx.Sprite(chunk.BackgroundRenderBuffer, pos, Color.White);
|
||||
if (chunk.WallRenderBuffer != null)
|
||||
gfx.Sprite(chunk.WallRenderBuffer, pos, Color.White);
|
||||
}
|
||||
}
|
||||
private void DrawDebugInfo(GraphicsEngine gfx)
|
||||
@@ -592,148 +657,73 @@ namespace CaveGame.Client
|
||||
|
||||
if (MyPlayer != null)
|
||||
{
|
||||
string positionData = String.Format("pos {0} {1} vel {2} {3}",
|
||||
|
||||
string mObjData = String.Format("entities {0} furn {1}", World.Entities.Count, World.Furniture.Count);
|
||||
|
||||
string[] debugStats = {
|
||||
String.Format("pos {0} {1} vel {2} {3}, rv {4} {5}",
|
||||
Math.Floor(MyPlayer.Position.X / Globals.TileSize),
|
||||
Math.Floor(MyPlayer.Position.Y / Globals.TileSize),
|
||||
Math.Round(MyPlayer.Velocity.X, 2),
|
||||
Math.Round(MyPlayer.Velocity.Y, 2)
|
||||
);
|
||||
|
||||
string networkData = String.Format("pin {0}, pout {1} myid {2} ipaddr {3}",
|
||||
gameClient.ReceivedCount,
|
||||
gameClient.SentCount,
|
||||
MyPlayer?.EntityNetworkID,
|
||||
ConnectAddress
|
||||
);
|
||||
|
||||
string worldData = String.Format("tid {0}, state {1} tdmg {2} wid {3} wdmg {4} light {5}",
|
||||
Math.Round(MyPlayer.Velocity.Y, 2),
|
||||
Math.Round(MyPlayer.RecentVelocity.X, 2),
|
||||
Math.Round(MyPlayer.RecentVelocity.Y, 2)
|
||||
),
|
||||
$"userid {MyUserID} netaddr {ConnectAddress}",
|
||||
$"in {Math.Round(NetClient.BytesReceivedPerSecond/1000.0f, 2)}kb/s || {Math.Round(NetClient.TotalBytesReceived/1000.0f, 2)}kb total || {NetClient.PacketsReceived}ct",
|
||||
$"out {Math.Round(NetClient.BytesSentPerSecond/1000.0f, 2)}kb/s || {Math.Round(NetClient.TotalBytesSent/1000.0f, 2)}kb total || {NetClient.PacketsSent}ct",
|
||||
String.Format("tid {0}, state {1} tdmg {2} wid {3} wdmg {4} light {5}",
|
||||
tileat.ID,
|
||||
tileat.TileState,
|
||||
tileat.Damage,
|
||||
wallat.ID,
|
||||
wallat.Damage,
|
||||
World.GetLight((int)tileCoords.X, (int)tileCoords.Y).ToString()
|
||||
);
|
||||
|
||||
),
|
||||
mObjData,
|
||||
};
|
||||
|
||||
string mObjectData = String.Format("entities {0} furn {1}", World.Entities.Count, World.Furniture.Count);
|
||||
|
||||
gfx.Text(positionData, new Vector2(2, 12));
|
||||
gfx.Text(networkData, new Vector2(2, 24));
|
||||
gfx.Text(worldData, new Vector2(2, 36));
|
||||
gfx.Text(mObjectData, new Vector2(2, 48));
|
||||
int incr = 1;
|
||||
foreach(var line in debugStats)
|
||||
{
|
||||
gfx.Text(line, new Vector2(2, incr * 14));
|
||||
incr++;
|
||||
}
|
||||
|
||||
}
|
||||
gfx.End();
|
||||
}
|
||||
|
||||
private void DrawSkyColor(GraphicsEngine GFX)
|
||||
{
|
||||
for (int y = 0; y<10; y++)
|
||||
{
|
||||
|
||||
|
||||
int hourTime = (int)Math.Floor( ( (World.TimeOfDay+1)%24) / 2);
|
||||
int bottom = hourTime*2;
|
||||
int top = (hourTime*2) + 1;
|
||||
//float diff = World.TimeOfDay % 1;
|
||||
var thisSection = Color.Lerp(World.SkyColors[bottom], World.SkyColors[top], y/10.0f);
|
||||
|
||||
int prevhourTime = (int)Math.Floor((World.TimeOfDay % 24) / 2);
|
||||
int prevbottom = prevhourTime * 2;
|
||||
int prevtop = (prevhourTime * 2) + 1;
|
||||
//float diff = World.TimeOfDay % 1;
|
||||
var prevSection = Color.Lerp(World.SkyColors[prevbottom], World.SkyColors[prevtop], y / 10.0f);
|
||||
|
||||
var finalColor = Color.Lerp(prevSection, thisSection, (World.TimeOfDay % 2.0f) / 2.0f);
|
||||
float sliceHeight = Camera._screenSize.Y / 10.0f;
|
||||
GFX.Rect(finalColor, new Vector2(0,(sliceHeight*y)), new Vector2(Camera._screenSize.X, sliceHeight + 1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Draw(GraphicsEngine GFX)
|
||||
{
|
||||
|
||||
DrawChunks(GFX);
|
||||
|
||||
Game.GraphicsDevice.Clear(World.SkyColor);
|
||||
GFX.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp);
|
||||
|
||||
DrawSkyColor(GFX);
|
||||
GFX.End();
|
||||
GFX.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, Camera.View);
|
||||
if (PauseMenu.Open)
|
||||
PauseMenu.DrawWaterPixelsFilter(GFX);
|
||||
|
||||
|
||||
|
||||
DrawChunkBGTextures(GFX);
|
||||
DrawChunkFGTextures(GFX);
|
||||
|
||||
foreach (var furn in World.Furniture)
|
||||
{
|
||||
furn.Draw(GFX);
|
||||
}
|
||||
EntityRendering(GFX);
|
||||
|
||||
World.ParticleSystem.Draw(GFX);
|
||||
|
||||
if (!Inventory.EquippedItem.Equals(ItemStack.Empty))
|
||||
{
|
||||
Inventory.EquippedItem.Item?.OnClientDraw(GFX);
|
||||
}
|
||||
|
||||
MouseState mouse = Mouse.GetState();
|
||||
|
||||
var mp = Camera.ScreenToWorldCoordinates(mouse.Position.ToVector2());
|
||||
|
||||
mp /= 8;
|
||||
mp.Floor();
|
||||
var tileCoords = mp;
|
||||
mp *= 8;
|
||||
|
||||
|
||||
if (mouse.LeftButton == ButtonState.Pressed)
|
||||
{
|
||||
GFX.Rect(Color.Green, mp, new Vector2(8, 8));
|
||||
} else
|
||||
{
|
||||
GFX.Rect(new Color(1,1,1,0.5f), mp, new Vector2(8, 8));
|
||||
}
|
||||
|
||||
GFX.End();
|
||||
if (ShowChunkBoundaries)
|
||||
{
|
||||
GFX.Begin(SpriteSortMode.Immediate, null, SamplerState.PointClamp, null, null, null, Camera.View);
|
||||
chunkGridTool?.Draw(GFX, Camera);
|
||||
GFX.End();
|
||||
}
|
||||
|
||||
// TODO: Consolidate draw calls
|
||||
GFX.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp);
|
||||
Inventory.Draw(GFX);
|
||||
PauseMenu.Draw(GFX);
|
||||
GFX.End();
|
||||
DrawDebugInfo(GFX);
|
||||
Chat.Draw(GFX);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void Load()
|
||||
{
|
||||
PauseMenu.LoadShader(Game.Content);
|
||||
if (NetworkClient.IsAddressValidIPv4(ConnectAddress))
|
||||
{
|
||||
FailConnect("Server address is not a valid IPv4 address!");
|
||||
return;
|
||||
}
|
||||
if (NetworkClient.IsServerOnline(ConnectAddress))
|
||||
{
|
||||
FailConnect("Failed to connect, server may be offline!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
gameClient = new NetworkClient(ConnectAddress);
|
||||
NetClient = new NetworkClient(ConnectAddress);
|
||||
//gameClient = new NetworkClient("127.0.0.1:40269");
|
||||
//gameClient.Output = Game.Console;
|
||||
gameClient.Start();
|
||||
gameClient.SendPacket(new InitServerHandshakePacket(Globals.ProtocolVersion));
|
||||
NetClient.Start();
|
||||
NetClient.SendPacket(new InitServerHandshakePacket(Globals.ProtocolVersion));
|
||||
|
||||
//gameClient.SendPacket(new RequestJoinPacket("jooj"));
|
||||
}
|
||||
|
||||
private void FailConnect(string reason)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Unload() {}
|
||||
MouseState previous = Mouse.GetState();
|
||||
private void HotbarUpdate(GameTime gt)
|
||||
@@ -770,17 +760,13 @@ namespace CaveGame.Client
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void ReplicatePlayerState()
|
||||
{
|
||||
//Debug.WriteLine("Replicating");
|
||||
if (MyPlayer != null)
|
||||
{
|
||||
gameClient?.SendPacket(
|
||||
new EntityPositionPacket(MyPlayer)
|
||||
);
|
||||
|
||||
gameClient?.SendPacket(new PlayerStatePacket(MyPlayer.Facing, MyPlayer.OnGround, MyPlayer.Walking));
|
||||
NetClient?.SendPacket(new EntityPhysicsStatePacket(MyPlayer));
|
||||
NetClient?.SendPacket(new PlayerStatePacket(MyPlayer.Facing, MyPlayer.OnGround, MyPlayer.Walking));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -801,7 +787,7 @@ namespace CaveGame.Client
|
||||
|
||||
//float ZoomFactor = ((mouse.ScrollWheelValue - IntitalScrollValue) * (Senitivity / 120)) + 2;
|
||||
|
||||
Vector2 MouseCameraMovement = ((mouse.Position.ToVector2() / Camera._screenSize) - new Vector2(0.5f, 0.5f)) * 5.5f;
|
||||
Vector2 MouseCameraMovement = ((mouse.Position.ToVector2() / Camera.WindowSize) - new Vector2(0.5f, 0.5f)) * 5.5f;
|
||||
|
||||
|
||||
Camera.Zoom = Math.Clamp(scroll, 0.05f, 10f);
|
||||
@@ -857,22 +843,22 @@ namespace CaveGame.Client
|
||||
previousKB = currentKB;
|
||||
}
|
||||
|
||||
|
||||
float drawTimer = 0;
|
||||
|
||||
public void Update(GameTime gt)
|
||||
{
|
||||
|
||||
FPSGraph.DataSet.Push(new FpsSample { Value = gt.GetDelta()});
|
||||
|
||||
NetClient.Update(gt);
|
||||
redrawTimer += gt.GetDelta();
|
||||
|
||||
Profiler.StartRegion("Update");
|
||||
|
||||
ServerKeepAlive += gt.GetDelta();
|
||||
UpdateInputs();
|
||||
|
||||
Camera.Update(gt);
|
||||
|
||||
|
||||
drawTimer += (float)gt.ElapsedGameTime.TotalSeconds;
|
||||
|
||||
playerStateReplicationTask.Update(gt);
|
||||
chunkUnloadingTask.Update(gt);
|
||||
chunkLoadingTask.Update(gt);
|
||||
ClientTasks.ForEach(ct => ct.Update(gt));
|
||||
|
||||
if (MyPlayer != null)
|
||||
{
|
||||
@@ -882,14 +868,130 @@ namespace CaveGame.Client
|
||||
MyPlayer.IgnoreInput = false;
|
||||
}
|
||||
|
||||
|
||||
Profiler.Start("UIUpdate");
|
||||
Inventory.Update(gt);
|
||||
PauseMenu.Update(gt);
|
||||
Chat.Update(gt);
|
||||
|
||||
Chat.Update(gt);
|
||||
Profiler.End();
|
||||
|
||||
//Profiler.Start("WorldUpdate");
|
||||
World.Update(gt);
|
||||
//Profiler.End();
|
||||
|
||||
Profiler.Start("Camera");
|
||||
HotbarUpdate(gt);
|
||||
UpdateCamera(gt);
|
||||
Profiler.End();
|
||||
|
||||
Profiler.Start("ReadPackets");
|
||||
ReadIncomingPackets();
|
||||
Profiler.End();
|
||||
|
||||
Profiler.EndRegion();
|
||||
}
|
||||
|
||||
protected void DrawBackgroundLayer(GraphicsEngine GFX)
|
||||
{
|
||||
Game.GraphicsDevice.Clear(World.SkyColor);
|
||||
GFX.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp);
|
||||
World.Sky.DrawSkyColors(GFX);
|
||||
GFX.End();
|
||||
}
|
||||
protected void DrawGameLayer(GraphicsEngine GFX)
|
||||
{
|
||||
// Game Layer
|
||||
GFX.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, null, null, null, Camera.View);
|
||||
|
||||
if (PauseMenu.Open)
|
||||
PauseMenu.DrawWaterPixelsFilter(GFX);
|
||||
|
||||
World.Sky.DrawBackground(GFX);
|
||||
Profiler.Start("DrawChunkCanvases");
|
||||
DrawChunkWallTextures(GFX);
|
||||
DrawChunkTileTextures(GFX);
|
||||
Profiler.End();
|
||||
|
||||
Profiler.Start("DrawFurniture");
|
||||
foreach (var furn in World.Furniture)
|
||||
{
|
||||
furn.Draw(GFX);
|
||||
}
|
||||
Profiler.End();
|
||||
Profiler.Start("DrawEntities");
|
||||
EntityRendering(GFX);
|
||||
Profiler.End();
|
||||
|
||||
Profiler.Start("DrawParticles");
|
||||
World.ParticleSystem.Draw(GFX);
|
||||
Profiler.End();
|
||||
|
||||
if (!Inventory.EquippedItem.Equals(ItemStack.Empty))
|
||||
{
|
||||
Inventory.EquippedItem.Item?.OnClientDraw(GFX);
|
||||
}
|
||||
|
||||
MouseState mouse = Mouse.GetState();
|
||||
|
||||
var mp = Camera.ScreenToWorldCoordinates(mouse.Position.ToVector2());
|
||||
|
||||
mp /= 8;
|
||||
mp.Floor();
|
||||
var tileCoords = mp;
|
||||
mp *= 8;
|
||||
|
||||
|
||||
if (mouse.LeftButton == ButtonState.Pressed)
|
||||
{
|
||||
GFX.Rect(Color.Green, mp, new Vector2(8, 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
GFX.Rect(new Color(1, 1, 1, 0.5f), mp, new Vector2(8, 8));
|
||||
}
|
||||
|
||||
GFX.End();
|
||||
}
|
||||
|
||||
protected void DrawUILayer(GraphicsEngine GFX)
|
||||
{
|
||||
Profiler.Start("DrawUI");
|
||||
GFX.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp);
|
||||
Inventory.Draw(GFX);
|
||||
PauseMenu.Draw(GFX);
|
||||
GFX.End();
|
||||
Chat.Draw(GFX);
|
||||
Profiler.End();
|
||||
|
||||
Profiler.Start("DrawDebug");
|
||||
DrawDebugInfo(GFX);
|
||||
Profiler.End();
|
||||
}
|
||||
|
||||
public void Draw(GraphicsEngine GFX)
|
||||
{
|
||||
Profiler.StartRegion("Draw");
|
||||
|
||||
if (redrawTimer > (1.0f / 8.0f))
|
||||
{
|
||||
redrawTimer = 0;
|
||||
Profiler.Start("DrawChunkBuffers");
|
||||
RedrawChunkBuffers(GFX);
|
||||
//Profiler.Track("DrawChunkBuffers", ()=>RedrawChunkBuffers(GFX));
|
||||
Profiler.End("DrawChunkBuffers");
|
||||
}
|
||||
|
||||
DrawBackgroundLayer(GFX);
|
||||
DrawGameLayer(GFX);
|
||||
DrawUILayer(GFX);
|
||||
|
||||
|
||||
Profiler.EndRegion("Draw");
|
||||
|
||||
GFX.Begin(SpriteSortMode.Immediate);
|
||||
Profiler.Draw(GFX);
|
||||
FPSGraph.Draw(GFX);
|
||||
GFX.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -39,23 +39,23 @@ namespace CaveGame.Client
|
||||
|
||||
public static void LoadAssets(ContentManager Content)
|
||||
{
|
||||
Content.RootDirectory = "Assets";
|
||||
MenuBlip = Content.Load<SoundEffect>("Sound/click1");
|
||||
Content.RootDirectory = Path.Combine("assets", "sound");
|
||||
MenuBlip = Content.Load<SoundEffect>("click1");
|
||||
|
||||
Mu_Big_Brother = Content.Load<Song>("Sound/mu/big_brother");
|
||||
Mu_Cliff = Content.Load<Song>("Sound/mu/cliff");
|
||||
Mu_Hey_Bella = Content.Load<Song>("Sound/mu/hey_bella");
|
||||
Mu_Mithril_Ocean = Content.Load<Song>("Sound/mu/mithril_ocean");
|
||||
AmbientLava = Content.Load<Song>("Sound/ambient/lava");
|
||||
AmbientBirds1 = Content.Load<Song>("Sound/ambient/birds1");
|
||||
AmbientBirds2 = Content.Load<Song>("Sound/ambient/birds2");
|
||||
AmbientBirds3 = Content.Load<Song>("Sound/ambient/birds3");
|
||||
AmbientBirds4 = Content.Load<Song>("Sound/ambient/birds4");
|
||||
AmbientBirds5 = Content.Load<Song>("Sound/ambient/birds5");
|
||||
AmbientBirds6 = Content.Load<Song>("Sound/ambient/birds6");
|
||||
AmbientBirds7 = Content.Load<Song>("Sound/ambient/birds7");
|
||||
AmbientCreepy1 = Content.Load<Song>("Sound/ambient/birds1");
|
||||
AmbientBirds7 = Content.Load<Song>("Sound/ambient/birds1");
|
||||
Mu_Big_Brother = Content.Load<Song>("mu/big_brother");
|
||||
Mu_Cliff = Content.Load<Song>("mu/cliff");
|
||||
Mu_Hey_Bella = Content.Load<Song>("mu/hey_bella");
|
||||
Mu_Mithril_Ocean = Content.Load<Song>("mu/mithril_ocean");
|
||||
AmbientLava = Content.Load<Song>("ambient/lava");
|
||||
AmbientBirds1 = Content.Load<Song>("ambient/birds1");
|
||||
AmbientBirds2 = Content.Load<Song>("ambient/birds2");
|
||||
AmbientBirds3 = Content.Load<Song>("ambient/birds3");
|
||||
AmbientBirds4 = Content.Load<Song>("ambient/birds4");
|
||||
AmbientBirds5 = Content.Load<Song>("ambient/birds5");
|
||||
AmbientBirds6 = Content.Load<Song>("ambient/birds6");
|
||||
AmbientBirds7 = Content.Load<Song>("ambient/birds7");
|
||||
AmbientCreepy1 = Content.Load<Song>("ambient/birds1");
|
||||
AmbientBirds7 = Content.Load<Song>("ambient/birds1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
// TODO: Refactor and clean
|
||||
namespace CaveGame.Client
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
@@ -29,6 +30,13 @@ namespace CaveGame.Client
|
||||
Light = l;
|
||||
}
|
||||
|
||||
public Cell(Point coords, Light3 l)
|
||||
{
|
||||
X = coords.X;
|
||||
Y = coords.Y;
|
||||
Light = l;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
System.GC.SuppressFinalize(this);
|
||||
@@ -71,6 +79,14 @@ namespace CaveGame.Client
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal struct InvokedLightCell
|
||||
{
|
||||
public Point Coords { get; set; }
|
||||
public Light3 Value { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class LightingEngine : ILightingEngine
|
||||
{
|
||||
public Thread LightThread;
|
||||
@@ -126,6 +142,7 @@ namespace CaveGame.Client
|
||||
OutputLights = new Dictionary<ChunkCoordinates, Light3[,]>();
|
||||
LocalChunks = new Dictionary<ChunkCoordinates, Chunk>();
|
||||
LightCells = new Dictionary<ChunkCoordinates, Light3[,]>();
|
||||
InvokedCells = new ConcurrentQueue<InvokedLightCell>();
|
||||
UpdatedCells = new Queue<Cell>();
|
||||
}
|
||||
|
||||
@@ -133,6 +150,7 @@ namespace CaveGame.Client
|
||||
private ConcurrentQueue<ChunkCoordinates> RemovedChunkQueue;
|
||||
private ConcurrentQueue<TileChangedCell> ChangedTiles;
|
||||
private ConcurrentQueue<WallChangedCell> ChangedWalls;
|
||||
private ConcurrentQueue<InvokedLightCell> InvokedCells;
|
||||
private Dictionary<ChunkCoordinates, Light3[,]> OutputLights;
|
||||
|
||||
private Dictionary<ChunkCoordinates, Chunk> LocalChunks;
|
||||
@@ -152,7 +170,7 @@ namespace CaveGame.Client
|
||||
public Light3 GetLight(int x, int y)
|
||||
{
|
||||
int chunkX = (int)Math.Floor((float)x / Globals.ChunkSize);
|
||||
int chunkY = (int)Math.Floor((double)y / Globals.ChunkSize);
|
||||
int chunkY = (int)Math.Floor((float)y / Globals.ChunkSize);
|
||||
|
||||
var tileX = x.Mod(Globals.ChunkSize);
|
||||
var tileY = y.Mod(Globals.ChunkSize);
|
||||
@@ -166,7 +184,9 @@ namespace CaveGame.Client
|
||||
}
|
||||
return new Light3(0, 0, 0);
|
||||
}
|
||||
public void SetLight(int x, int y, Light3 val)
|
||||
|
||||
public Light3 GetLight(Point coords) => GetLight(coords.X, coords.Y);
|
||||
private void SetLight(int x, int y, Light3 val)
|
||||
{
|
||||
int chunkX = (int)Math.Floor((double)x / Globals.ChunkSize);
|
||||
int chunkY = (int)Math.Floor((double)y / Globals.ChunkSize);
|
||||
@@ -182,6 +202,14 @@ namespace CaveGame.Client
|
||||
chunk[tileX, tileY] = val;
|
||||
}
|
||||
}
|
||||
|
||||
public void InvokeLight(Point coords, Light3 value)
|
||||
{
|
||||
UpdatedCells.Enqueue(new Cell(coords, value));
|
||||
SetLight(coords, value);
|
||||
}
|
||||
|
||||
private void SetLight(Point coords, Light3 val) => SetLight(coords.X, coords.Y, val);
|
||||
private void SetTile(int x, int y, Tile t)
|
||||
{
|
||||
int chunkX = (int)Math.Floor((double)x / Globals.ChunkSize);
|
||||
@@ -278,7 +306,7 @@ namespace CaveGame.Client
|
||||
byte opacity = Math.Max(tile.Opacity, wall.Opacity);
|
||||
var tileLight = Light3.Dark;
|
||||
if (tile.ID == 0 && wall.ID == 0)
|
||||
tileLight = Light3.Ambience;
|
||||
tileLight = World.Ambience;
|
||||
else if (tile is ILightEmitter emitter)
|
||||
tileLight = emitter.Light;
|
||||
|
||||
|
@@ -12,6 +12,7 @@ using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CaveGame.Core.Game.Walls;
|
||||
using CaveGame.Client.DebugTools;
|
||||
|
||||
namespace CaveGame.Client
|
||||
{
|
||||
@@ -28,26 +29,30 @@ namespace CaveGame.Client
|
||||
public LightingEngine Lighting { get; set; }
|
||||
ILightingEngine IClientWorld.Lighting => Lighting;
|
||||
|
||||
protected DelayedTask localTileUpdateTask;
|
||||
protected DelayedTask localLightingUpdateTask;
|
||||
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
public GameClient Client { get; set; }
|
||||
public Sky Sky { get; private set; }
|
||||
|
||||
public LocalWorld(GameClient client) : base()
|
||||
{
|
||||
Context = NetworkContext.Client;
|
||||
|
||||
Client = client;
|
||||
localTileUpdateTask = new DelayedTask(ApplyVisualTileUpdates, 1 / 10.0f);
|
||||
localLightingUpdateTask = new DelayedTask(GetLatestDataFromLightingThread, 1 / 20.0f);
|
||||
|
||||
Sky = new Sky(this);
|
||||
ParticleSystem = new ParticleEmitter(this);
|
||||
Lighting = new LightingEngine(this);
|
||||
Lighting.On();
|
||||
|
||||
WorldTimedTasks.Add(new RepeatingIntervalTask(ApplyVisualTileUpdates, 1 / 10.0f));
|
||||
WorldTimedTasks.Add(new RepeatingIntervalTask(GetLatestDataFromLightingThread, 1 / 20.0f));
|
||||
|
||||
RequestedChunks = new List<ChunkCoordinates>();
|
||||
LoadedChunks = new List<ChunkCoordinates>();
|
||||
Lighting.On();
|
||||
|
||||
Tile.InitializeManager(420);
|
||||
}
|
||||
|
||||
@@ -57,6 +62,11 @@ namespace CaveGame.Client
|
||||
Lighting.Off();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void UnloadChunk(ChunkCoordinates coords) {}
|
||||
|
||||
Random r = new Random();
|
||||
@@ -68,15 +78,8 @@ namespace CaveGame.Client
|
||||
return AmbientLights[wrapped];
|
||||
}
|
||||
}
|
||||
public Color SkyColor
|
||||
{
|
||||
get {
|
||||
int wrapped = ((int)Math.Floor(TimeOfDay)).Mod(24);
|
||||
int last = ((int)Math.Floor(TimeOfDay) - 1).Mod(24);
|
||||
float diff = TimeOfDay % 1;
|
||||
return Color.Lerp(SkyColors[last], SkyColors[wrapped], diff);
|
||||
}
|
||||
}
|
||||
|
||||
public Color SkyColor => Sky.SkyColor;
|
||||
|
||||
public override void SetTileNoLight(int x, int y, Tile t)
|
||||
{
|
||||
@@ -146,53 +149,49 @@ namespace CaveGame.Client
|
||||
|
||||
public override void Update(GameTime gt)
|
||||
{
|
||||
localTileUpdateTask.Update(gt);
|
||||
localLightingUpdateTask.Update(gt);
|
||||
//Profiler.Start("WorldTasks");
|
||||
//base.Update(gt);
|
||||
//localTileUpdateTask.Update(gt);
|
||||
//localLightingUpdateTask.Update(gt);
|
||||
//Profiler.End();
|
||||
|
||||
Profiler.Start("Particles");
|
||||
ParticleSystem.Update(gt);
|
||||
Profiler.End();
|
||||
|
||||
Profiler.Start("Lighting");
|
||||
Lighting.Update(gt);
|
||||
Profiler.End();
|
||||
|
||||
|
||||
Profiler.Start("EntityUpdate");
|
||||
foreach (IEntity entity in Entities)
|
||||
entity.ClientUpdate(Client, gt);
|
||||
|
||||
|
||||
Profiler.End();
|
||||
|
||||
TimeOfDay += (float)gt.ElapsedGameTime.TotalSeconds / 30.0f;
|
||||
|
||||
|
||||
//Entities.RemoveAll(e => e.Dead);
|
||||
//Profiler.Start("PhysicsTask");
|
||||
//physicsTask.Update(gt);
|
||||
//Profiler.End();
|
||||
base.Update(gt);
|
||||
|
||||
}
|
||||
|
||||
private void LocalTileUpdates(Chunk chunk)
|
||||
{
|
||||
for (int x = 0; x < Globals.ChunkSize; x++)
|
||||
{
|
||||
for (int y = 0; y < Globals.ChunkSize; y++)
|
||||
{
|
||||
if (chunk.TileUpdate[x, y] == true)
|
||||
{
|
||||
chunk.TileUpdate[x, y] = false;
|
||||
|
||||
|
||||
if (chunk.GetTile(x, y) is ILocalTileUpdate tile)
|
||||
{
|
||||
int worldX = (chunk.Coordinates.X * Globals.ChunkSize) + x;
|
||||
int worldY = (chunk.Coordinates.Y * Globals.ChunkSize) + y;
|
||||
|
||||
tile.LocalTileUpdate(this, worldX, worldY);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SpawnExplosionParticles(Explosion blast)
|
||||
{
|
||||
for (int i = 0; i < 360; i += 5)
|
||||
for (int i = 0; i < 360; i += 20)
|
||||
{
|
||||
float randy = r.Next(0, 10) - 5;
|
||||
Rotation rotation = Rotation.FromDeg(i + randy);
|
||||
Vector2 direction = new Vector2((float)Math.Sin(rotation.Radians), (float)Math.Cos(rotation.Radians));
|
||||
float size = ((float)r.NextDouble() * 0.4f) + (blast.BlastPressure * 0.2f);
|
||||
ParticleSystem.EmitSmokeParticle(blast.Position, Color.White, Rotation.FromDeg(0), size, direction * (blast.BlastRadius * 1.0f + ((float)r.NextDouble() * 5)));
|
||||
float size = ((float)r.NextDouble() * 0.2f) + (blast.BlastPressure * 0.1f);
|
||||
ParticleSystem.EmitSmokeParticle(blast.Position, Color.Gray, Rotation.FromDeg(0), new Vector2(size, size), direction * (blast.BlastRadius * ((float)r.NextDouble())));
|
||||
}
|
||||
ParticleSystem.EmitExplosionParticle(blast.Position);
|
||||
}
|
||||
|
||||
public override void Explosion(Explosion Blast, bool DamageTiles, bool DamageEntities)
|
||||
@@ -216,17 +215,21 @@ namespace CaveGame.Client
|
||||
ParticleSystem.Add(new TileBloodSplatterParticle { AttachedTo = result.TileCoordinates, Position = rounded, Face = result.Face });
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyVisualTileUpdates()
|
||||
{
|
||||
foreach (var kvp in Chunks)
|
||||
|
||||
int count = TileUpdateQueue.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
LocalTileUpdates(kvp.Value);
|
||||
Point coords = TileUpdateQueue.Dequeue();
|
||||
if (GetTile(coords) is ILocalTileUpdate tile)
|
||||
tile.LocalTileUpdate(this, coords.X, coords.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -70,7 +70,7 @@ namespace CaveGame.Client.Menu
|
||||
luastate["_G.script"] = luastate;
|
||||
luastate.DoString(@"_G.oldprint = print; _G.print = function(str) game.Console:LuaPrint(str) end");
|
||||
luastate.DoString(LuaSnippets.UtilityFunctions);
|
||||
luastate.DoFile(Path.Combine("Assets", "Scripts", "menu.lua"));
|
||||
luastate.DoFile(Path.Combine("assets", "scripts", "menu.lua"));
|
||||
}
|
||||
|
||||
public void Load()
|
||||
|
@@ -170,7 +170,7 @@ namespace CaveGame.Client.Menu
|
||||
GameSounds.MenuBlip?.Play(0.8f, 1, 0.0f);
|
||||
}
|
||||
fpsCapSlider.OnValueChanged += onFpsCapSliderChanged;
|
||||
fpsCapSlider.SetIndex(GameSettings.CurrentSettings.FPSLimitIndex);
|
||||
//fpsCapSlider.SetIndex(GameSettings.CurrentSettings.FPSLimitIndex);
|
||||
|
||||
Label chatSizeText = new Label
|
||||
{
|
||||
@@ -199,7 +199,7 @@ namespace CaveGame.Client.Menu
|
||||
GameSounds.MenuBlip?.Play(0.8f, 1, 0.0f);
|
||||
}
|
||||
chatSizeSlider.OnValueChanged += onChatSliderChanged;
|
||||
chatSizeSlider.SetIndex((int)GameSettings.CurrentSettings.ChatSize);
|
||||
//chatSizeSlider.SetIndex((int)GameSettings.CurrentSettings.ChatSize);
|
||||
|
||||
void bindButtonClick(TextButton b, MouseState m)
|
||||
{
|
||||
|
194
Client/Network/NetworkClient.cs
Normal file
194
Client/Network/NetworkClient.cs
Normal file
@@ -0,0 +1,194 @@
|
||||
using CaveGame.Core;
|
||||
using CaveGame.Core.Generic;
|
||||
using CaveGame.Core.Network;
|
||||
using CaveGame.Core.Network.Packets;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CaveGame.Client
|
||||
{
|
||||
public class NetworkClient : SharedNetworkSubsystem
|
||||
{
|
||||
public IPEndPoint EndPoint
|
||||
{
|
||||
get {
|
||||
IPEndPoint output = default;
|
||||
bool success = IPEndPoint.TryParse(ServerHostname + ":"+ServerPort, out output);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private ThreadSafeValue<bool> running = new ThreadSafeValue<bool>(false);
|
||||
|
||||
public readonly string ServerHostname;
|
||||
public readonly int ServerPort;
|
||||
|
||||
private ConcurrentQueue<NetworkMessage> incomingMessages;
|
||||
private ConcurrentQueue<Packet> outgoingMessages;
|
||||
|
||||
|
||||
public static bool IsServerOnline(string hostname)
|
||||
{
|
||||
try
|
||||
{
|
||||
Ping pingSender = new Ping();
|
||||
PingOptions options = new PingOptions();
|
||||
options.DontFragment = true;
|
||||
string data = "CAVEGAME CAVEGAME CAVEGAME";
|
||||
byte[] buffer = Encoding.ASCII.GetBytes(data);
|
||||
int timeout = 120;
|
||||
|
||||
PingReply reply = pingSender.Send(hostname, timeout, buffer, options);
|
||||
if (reply.Status == IPStatus.Success)
|
||||
return true;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsAddressValidIPv4(string hostname)=>IPEndPoint.TryParse(hostname, out _);
|
||||
|
||||
public static HandshakeResponsePacket GetServerInformation(string hostname)
|
||||
{
|
||||
|
||||
var tempClient = new NetworkClient(hostname);
|
||||
return null;
|
||||
|
||||
// TODO: Finish
|
||||
}
|
||||
|
||||
public NetworkClient(string ipaddress)
|
||||
{
|
||||
IPEndPoint addr;
|
||||
|
||||
bool success = IPEndPoint.TryParse(ipaddress, out addr);
|
||||
|
||||
ServerHostname = addr.Address.ToString();
|
||||
ServerPort = addr.Port;
|
||||
|
||||
UdpSocket = new UdpClient(ServerHostname, ServerPort);
|
||||
IOControlFixICMPBullshit();
|
||||
}
|
||||
|
||||
private void FlushOutgoingPackets()
|
||||
{
|
||||
int outQCount = outgoingMessages.Count;
|
||||
// write out queued messages
|
||||
for (int i = 0; i < outQCount; i++)
|
||||
{
|
||||
Packet packet;
|
||||
bool have = outgoingMessages.TryDequeue(out packet);
|
||||
|
||||
if (have)
|
||||
{
|
||||
packet.Send(UdpSocket);
|
||||
PacketsSent++;
|
||||
TotalBytesSent += packet.Payload.Length;
|
||||
InternalSendCount += packet.Payload.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadIncomingPackets()
|
||||
{
|
||||
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
|
||||
byte[] data = UdpSocket.Receive(ref ep);
|
||||
|
||||
NetworkMessage nm = new NetworkMessage();
|
||||
nm.Sender = ep;
|
||||
nm.Packet = new Packet(data);
|
||||
nm.ReceiveTime = DateTime.Now;
|
||||
|
||||
incomingMessages.Enqueue(nm);
|
||||
PacketsReceived++;
|
||||
TotalBytesReceived += nm.Packet.Payload.Length;
|
||||
InternalReceiveCount += nm.Packet.Payload.Length;
|
||||
LatestReceiveTimestamp = DateTime.Now;
|
||||
}
|
||||
|
||||
|
||||
private void NetworkThreadLoop()
|
||||
{
|
||||
GameConsole.Log("NetworkClientSubsystem thread started.");
|
||||
while (running.Value) {
|
||||
bool canRead = UdpSocket.Available > 0;
|
||||
int outgoingMessageQueueCount = outgoingMessages.Count;
|
||||
|
||||
// get data if there's any
|
||||
if (canRead)
|
||||
ReadIncomingPackets();
|
||||
|
||||
FlushOutgoingPackets();
|
||||
|
||||
// if nothing happened, take a nap
|
||||
if (!canRead && (outgoingMessageQueueCount == 0))
|
||||
Thread.Sleep(NAP_TIME_MILLISECONDS);
|
||||
}
|
||||
|
||||
|
||||
UdpSocket.Close();
|
||||
UdpSocket.Dispose();
|
||||
GameConsole.Log("NetworkClientSubsystem thread stopped.");
|
||||
}
|
||||
|
||||
public void SendPacket(Packet packet)
|
||||
{
|
||||
//Output?.Out("client: Sending packet " + packet.Type.ToString(), Color.Cyan);
|
||||
outgoingMessages.Enqueue(packet);
|
||||
LatestSendTimestamp = DateTime.Now;
|
||||
}
|
||||
|
||||
public void Logout(int userID, UserDisconnectReason reason)
|
||||
{
|
||||
SendPacket(new DisconnectPacket(userID, reason));
|
||||
Stop();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
running.Value = true;
|
||||
Task.Factory.StartNew(NetworkThreadLoop);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
running.Value = false;
|
||||
}
|
||||
|
||||
|
||||
public override void Update(GameTime gt)
|
||||
{
|
||||
base.Update(gt);
|
||||
}
|
||||
|
||||
public bool HaveIncomingMessage() => incomingMessages.Count > 0;
|
||||
|
||||
public NetworkMessage GetLatestMessage()
|
||||
{
|
||||
NetworkMessage msg;
|
||||
bool success = incomingMessages.TryDequeue(out msg);
|
||||
|
||||
if (success)
|
||||
{
|
||||
return msg;
|
||||
}
|
||||
throw new Exception("No Message Queued! Used HaveIncomingMessage() to check!");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -1,156 +0,0 @@
|
||||
using CaveGame.Core;
|
||||
using CaveGame.Core.Generic;
|
||||
using CaveGame.Core.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CaveGame.Client
|
||||
{
|
||||
public class NetworkClient
|
||||
{
|
||||
public IPEndPoint EndPoint
|
||||
{
|
||||
get {
|
||||
IPEndPoint output = default;
|
||||
bool success = IPEndPoint.TryParse(ServerHostname + ":"+ServerPort, out output);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
public IMessageOutlet Output { get; set; }
|
||||
|
||||
public int ReceivedCount { get; private set; }
|
||||
public int SentCount { get; private set; }
|
||||
private DateTime lastPacketReceivedTime = DateTime.MinValue;
|
||||
private DateTime lastPacketSentTime = DateTime.MinValue;
|
||||
private long lastPacketReceivedTimestamp = 0; // from server
|
||||
private TimeSpan heartbeatTimeout = TimeSpan.FromSeconds(20);
|
||||
|
||||
private ThreadSafeValue<bool> running = new ThreadSafeValue<bool>(false);
|
||||
|
||||
public readonly string ServerHostname;
|
||||
public readonly int ServerPort;
|
||||
|
||||
private ConcurrentQueue<NetworkMessage> incomingMessages;
|
||||
private ConcurrentQueue<Packet> outgoingMessages;
|
||||
|
||||
private UdpClient udpClient;
|
||||
|
||||
public NetworkClient(string ipaddress)
|
||||
{
|
||||
IPEndPoint addr;
|
||||
|
||||
bool success = IPEndPoint.TryParse(ipaddress, out addr);
|
||||
|
||||
ServerHostname = addr.Address.ToString();
|
||||
ServerPort = addr.Port;
|
||||
System.Diagnostics.Debug.WriteLine(addr.ToString());
|
||||
incomingMessages = new ConcurrentQueue<NetworkMessage>();
|
||||
outgoingMessages = new ConcurrentQueue<Packet>();
|
||||
|
||||
udpClient = new UdpClient(ServerHostname, ServerPort);
|
||||
}
|
||||
|
||||
public NetworkClient(string hostname, int port)
|
||||
{
|
||||
|
||||
incomingMessages = new ConcurrentQueue<NetworkMessage>();
|
||||
outgoingMessages = new ConcurrentQueue<Packet>();
|
||||
|
||||
ServerHostname = hostname;
|
||||
ServerPort = port;
|
||||
udpClient = new UdpClient(ServerHostname, ServerPort);
|
||||
}
|
||||
|
||||
private void NetworkRun()
|
||||
{
|
||||
while (running.Value) {
|
||||
bool canRead = udpClient.Available > 0;
|
||||
int outgoingMessageQueueCount = outgoingMessages.Count;
|
||||
|
||||
// get data if there's any
|
||||
if (canRead)
|
||||
{
|
||||
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
|
||||
byte[] data = udpClient.Receive(ref ep);
|
||||
|
||||
NetworkMessage nm = new NetworkMessage();
|
||||
nm.Sender = ep;
|
||||
nm.Packet = new Packet(data);
|
||||
nm.ReceiveTime = DateTime.Now;
|
||||
|
||||
incomingMessages.Enqueue(nm);
|
||||
ReceivedCount++;
|
||||
lastPacketReceivedTime = DateTime.Now;
|
||||
}
|
||||
|
||||
// write out queued messages
|
||||
for (int i = 0; i < outgoingMessageQueueCount; i++)
|
||||
{
|
||||
Packet packet;
|
||||
bool have = outgoingMessages.TryDequeue(out packet);
|
||||
|
||||
if (have)
|
||||
{
|
||||
packet.Send(udpClient);
|
||||
SentCount++;
|
||||
//Output?.Out(string.Format("client: sending {0} at {1}", packet.Payload, packet.Timestamp), Color.Cyan);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if nothing happened, take a nap
|
||||
if (!canRead && (outgoingMessageQueueCount == 0))
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
|
||||
|
||||
udpClient.Close();
|
||||
udpClient.Dispose();
|
||||
}
|
||||
|
||||
public void SendPacket(Packet packet)
|
||||
{
|
||||
Output?.Out("client: Sending packet " + packet.Type.ToString(), Color.Cyan);
|
||||
outgoingMessages.Enqueue(packet);
|
||||
lastPacketSentTime = DateTime.Now;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
running.Value = true;
|
||||
Task.Factory.StartNew(NetworkRun);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
running.Value = false;
|
||||
|
||||
}
|
||||
|
||||
public bool HaveIncomingMessage()
|
||||
{
|
||||
return incomingMessages.Count > 0;
|
||||
}
|
||||
|
||||
public NetworkMessage GetLatestMessage()
|
||||
{
|
||||
NetworkMessage msg;
|
||||
bool success = incomingMessages.TryDequeue(out msg);
|
||||
|
||||
if (success)
|
||||
{
|
||||
return msg;
|
||||
}
|
||||
throw new Exception("No Message Queued! Used HaveIncomingMessage() to check!");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -6,6 +6,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Client
|
||||
@@ -36,7 +37,8 @@ namespace CaveGame.Client
|
||||
|
||||
public void LoadShader(ContentManager GameContent)
|
||||
{
|
||||
WaterpixelsShader = GameContent.Load<Effect>("Shaders/Waterpixels");
|
||||
GameContent.RootDirectory = Path.Combine("assets", "shaders");
|
||||
WaterpixelsShader = GameContent.Load<Effect>("Waterpixels");
|
||||
}
|
||||
|
||||
public void Update(GameTime gt) {
|
||||
@@ -101,7 +103,7 @@ namespace CaveGame.Client
|
||||
|
||||
public void TryClientExit(TextButton tbtn, MouseState ms)
|
||||
{
|
||||
Client.OverrideDisconnect();
|
||||
Client.Disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
11
Client/World/ChunkRenderer.cs
Normal file
11
Client/World/ChunkRenderer.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Client
|
||||
{
|
||||
public class ChunkRenderer
|
||||
{
|
||||
|
||||
}
|
||||
}
|
113
Client/World/Sky.cs
Normal file
113
Client/World/Sky.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using CaveGame.Core;
|
||||
using DataManagement;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Client
|
||||
{
|
||||
public class Sky
|
||||
{
|
||||
public LocalWorld World { get; private set; }
|
||||
|
||||
|
||||
public Color SkyColor
|
||||
{
|
||||
get
|
||||
{
|
||||
int wrapped = ((int)Math.Floor(World.TimeOfDay)).Mod(24);
|
||||
int last = ((int)Math.Floor(World.TimeOfDay) - 1).Mod(24);
|
||||
float diff = World.TimeOfDay % 1;
|
||||
return Color.Lerp(SkyColors[last], SkyColors[wrapped], diff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Color[] SkyColors =
|
||||
{
|
||||
new Color(0, 2, 6), new Color(5, 5, 30), //0 or 24
|
||||
new Color(2, 2, 10), new Color(16, 16, 40), //2
|
||||
new Color(2, 2, 10), new Color(20, 20, 45), //4
|
||||
new Color(8, 9, 50), new Color(85, 85, 40), //6
|
||||
new Color(40, 60, 90), new Color(90, 90, 190), //8
|
||||
new Color(70, 90, 130), new Color(110, 110, 230), //10
|
||||
new Color(70, 80, 170), new Color(170, 170, 255), //12
|
||||
new Color(80, 100, 140), new Color(140, 140, 250), //14
|
||||
new Color(35, 41, 60), new Color(60, 80, 140), //14
|
||||
new Color(50, 32, 50), new Color(170, 100, 70), // 18
|
||||
new Color(25, 25, 55), new Color(92, 52, 23), //20
|
||||
new Color(5, 7, 14), new Color(9, 23, 45), //22
|
||||
};
|
||||
|
||||
public Sky(LocalWorld world)
|
||||
{
|
||||
World = world;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private void DrawSkyColorGradient(GraphicsEngine GFX)
|
||||
{
|
||||
for (int y = 0; y < 10; y++)
|
||||
{
|
||||
int hourTime = (int)Math.Floor(((World.TimeOfDay + 1) % 24) / 2);
|
||||
int bottom = hourTime * 2;
|
||||
int top = (hourTime * 2) + 1;
|
||||
//float diff = World.TimeOfDay % 1;
|
||||
var thisSection = Color.Lerp(SkyColors[bottom], SkyColors[top], y / 10.0f);
|
||||
|
||||
int prevhourTime = (int)Math.Floor((World.TimeOfDay % 24) / 2);
|
||||
int prevbottom = prevhourTime * 2;
|
||||
int prevtop = (prevhourTime * 2) + 1;
|
||||
//float diff = World.TimeOfDay % 1;
|
||||
var prevSection = Color.Lerp(SkyColors[prevbottom], SkyColors[prevtop], y / 10.0f);
|
||||
|
||||
var finalColor = Color.Lerp(prevSection, thisSection, (World.TimeOfDay % 2.0f) / 2.0f);
|
||||
float sliceHeight = World.Client.Camera.WindowSize.Y / 10.0f;
|
||||
GFX.Rect(finalColor, new Vector2(0, (sliceHeight * y)), new Vector2(World.Client.Camera.WindowSize.X, sliceHeight + 1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void DrawBackgroundParallax(GraphicsEngine GFX)
|
||||
{
|
||||
float starfieldPar = 0.85f;
|
||||
|
||||
|
||||
|
||||
float scale = 1.5f;
|
||||
float textureWidth = GFX.Starfield.Width * scale;
|
||||
float textureHeight = GFX.Starfield.Height * scale;
|
||||
|
||||
var pos = World.Client.Camera.Position;
|
||||
var gridPos = new Vector2(
|
||||
(float)pos.X / textureWidth,
|
||||
(float)pos.Y / textureHeight
|
||||
) * starfieldPar;
|
||||
|
||||
|
||||
|
||||
|
||||
for (int tx = -2; tx < 2; tx++)
|
||||
{
|
||||
for (int ty = -2; ty < 2; ty++)
|
||||
{
|
||||
float xPos = tx + gridPos.X;
|
||||
float yPos = ty + gridPos.Y;
|
||||
GFX.Sprite(GFX.Starfield, new Vector2(xPos * textureWidth, yPos * textureHeight), null, Color.White, Rotation.Zero, Vector2.Zero, scale, Microsoft.Xna.Framework.Graphics.SpriteEffects.None, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void DrawSkyColors(GraphicsEngine GFX) => DrawSkyColorGradient(GFX);
|
||||
public void DrawBackground(GraphicsEngine GFX) => DrawBackgroundParallax(GFX);
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -9,10 +9,20 @@
|
||||
<Import_RootNamespace>CaveGame.Core</Import_RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)AssetLoader.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Camera.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Enums.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)GameConsole.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)AssetManagement\AssetLoader.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Enums\DamageType.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Enums\Direction.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Enums\GameSteamAchievement.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Enums\TextAlignment.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Camera.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Interfaces\ICaveGameImplementation.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Interfaces\IDamageSource.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Interfaces\IEntityManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Interfaces\IGameClient.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Interfaces\IGameServer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Interfaces\INetworkingSubsystem.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Interfaces\ISteamManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Logging\GameConsole.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\CraftingRecipes\Recipe.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Entities\Arrow.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Entities\Bee.cs" />
|
||||
@@ -41,39 +51,40 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Tiles\Torches.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Tiles\VegetationTiles.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Tiles\WoodTiles.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Generic\DelayedTask.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)FileUtil\StructureFile.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Furniture\Furniture.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Generic\CircularArray.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Generic\RepeatingIntervalTask.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Generic\ThreadSafeValue.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Generic\UniqueQueue.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)GraphicsEngine.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)IGameMainControllers.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ILightingEngine.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Logger.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Interfaces\ILightingEngine.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Logging\Logger.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)LuaInterop\LuaEvent.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)LuaInterop\LuaInterop.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Network\SharedNetworkSubsystem.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Network\Packets\SessonControlPackets.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Network\User.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)DataTypes\Rotation.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ParticleEmitter.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Shell.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)WorldMetadata.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)OperatingSystem.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)World\WorldMetadata.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)World\Chunk.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)World\ChunkCoordinates.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Physics\CollisionSolver.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)CollisionSolver.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Entities\Entity.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Entities\ItemstackEntity.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Entities\Player.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)FileUtil\Configuration.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)World\GameWorld.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Globals.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)IMessageOutlet.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Interfaces\IMessageOutlet.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)MonoGameExtensions.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Items\Item.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Game\Inventory\ItemStack.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)World\Generator.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)World\Light3.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Message.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Chat\ChatMessage.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Network\NetworkMessage.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Network\Packet.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Network\TypeSerializer.cs" />
|
||||
@@ -91,5 +102,9 @@
|
||||
<ItemGroup>
|
||||
<Folder Include="$(MSBuildThisFileDirectory)Game\Items\" />
|
||||
<Folder Include="$(MSBuildThisFileDirectory)DataTypes\" />
|
||||
<Folder Include="$(MSBuildThisFileDirectory)Game\Structures\" />
|
||||
<Folder Include="$(MSBuildThisFileDirectory)Logging\" />
|
||||
<Folder Include="$(MSBuildThisFileDirectory)Chat\" />
|
||||
<Folder Include="$(MSBuildThisFileDirectory)AssetManagement\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@@ -1,4 +1,6 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using CaveGame.Core.Game.Entities;
|
||||
using CaveGame.Core.Game.Tiles;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@@ -7,14 +9,26 @@ using System.Text;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
public class CastResult
|
||||
|
||||
public struct TileRaycastResult
|
||||
{
|
||||
public bool Hit { get; set; }
|
||||
public bool Hit { get; set; }
|
||||
public Tile Target { get; set; }
|
||||
public Point TileCoordinates { get; set; }
|
||||
public Vector2 Intersection { get; set; }
|
||||
public Vector2 SurfaceNormal { get; set; }
|
||||
public Face Face { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public struct EntityRaycastResult
|
||||
{
|
||||
public bool Hit { get; set; }
|
||||
public IEntity Target { get; set; }
|
||||
public Vector2 Intersection { get; set; }
|
||||
public Vector2 SurfaceNormal { get; set; }
|
||||
public Face Face { get; set; }
|
||||
}
|
||||
|
||||
public struct LineSegment
|
||||
{
|
||||
@@ -32,10 +46,6 @@ namespace CaveGame.Core
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static class CollisionSolver
|
||||
{
|
||||
|
||||
@@ -62,8 +72,6 @@ namespace CaveGame.Core
|
||||
|
||||
if (top_hits || bottom_hits || left_hits || right_hits)
|
||||
{
|
||||
|
||||
|
||||
intersection = seg.B;
|
||||
|
||||
if (top_hits && seg.A.Distance(top_intersect) < seg.A.Distance(intersection))
|
||||
@@ -89,14 +97,8 @@ namespace CaveGame.Core
|
||||
intersection = right_intersect;
|
||||
collidingface = Face.Right;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
23
Core/Enums/DamageType.cs
Normal file
23
Core/Enums/DamageType.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
public enum DamageType
|
||||
{
|
||||
Frostbite,
|
||||
Fire,
|
||||
Lava,
|
||||
BluntForceTrauma,
|
||||
PunctureTrauma,
|
||||
Electrocution,
|
||||
LacerationTrauma,
|
||||
Neurotoxin,
|
||||
Poison,
|
||||
Explosion,
|
||||
Psionic,
|
||||
Asphyxiation,
|
||||
ActOfGod,
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
@@ -12,7 +13,6 @@ namespace CaveGame.Core
|
||||
Down,
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Cardinal Directions. Generally used for surface face of a tile.
|
||||
/// </summary>
|
||||
@@ -23,9 +23,8 @@ namespace CaveGame.Core
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
public enum Compass
|
||||
{
|
||||
{
|
||||
North = 0,
|
||||
Northeast = 45,
|
||||
East = 90,
|
||||
@@ -34,37 +33,23 @@ namespace CaveGame.Core
|
||||
Southwest = 225,
|
||||
West = 270,
|
||||
Northwest = 315
|
||||
}
|
||||
|
||||
public static class CardinalDirectionExtension
|
||||
{
|
||||
public static Rotation ToRotation(this Compass dir) => Rotation.FromDeg((int)dir);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Applied to the following:
|
||||
/// IEntity, Explosion, and certain tile classes
|
||||
/// </summary>
|
||||
public interface IDamageSource { }
|
||||
|
||||
public enum DamageType
|
||||
{
|
||||
Frostbite,
|
||||
Fire,
|
||||
Lava,
|
||||
BluntForceTrauma,
|
||||
PunctureTrauma,
|
||||
Electrocution,
|
||||
LacerationTrauma,
|
||||
Neurotoxin,
|
||||
Poison,
|
||||
Explosion,
|
||||
Psionic,
|
||||
Asphyxiation,
|
||||
ActOfGod,
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static class CardinalDirectionExtension
|
||||
{
|
||||
public static Rotation ToRotation(this Compass dir) => Rotation.FromDeg((int)dir);
|
||||
public static Vector2 ToSurfaceNormal(this Face face)
|
||||
{
|
||||
Vector2 normal = Vector2.Zero;
|
||||
if (face == Face.Top)
|
||||
normal = new Vector2(0, -1);
|
||||
if (face == Face.Bottom)
|
||||
normal = new Vector2(0, 1);
|
||||
if (face == Face.Left)
|
||||
normal = new Vector2(-1, 0);
|
||||
if (face == Face.Right)
|
||||
normal = new Vector2(1, 0);
|
||||
return normal;
|
||||
}
|
||||
}
|
||||
}
|
13
Core/Enums/GameSteamAchievement.cs
Normal file
13
Core/Enums/GameSteamAchievement.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
public enum GameSteamAchievement : byte
|
||||
{
|
||||
HELLO_WORLD = 0,
|
||||
MORNING_WOOD = 1,
|
||||
|
||||
}
|
||||
}
|
20
Core/Enums/TextAlignment.cs
Normal file
20
Core/Enums/TextAlignment.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
public enum TextXAlignment
|
||||
{
|
||||
Left,
|
||||
Center,
|
||||
Right
|
||||
}
|
||||
public enum TextYAlignment
|
||||
{
|
||||
Top,
|
||||
Center,
|
||||
Bottom,
|
||||
|
||||
}
|
||||
}
|
@@ -12,9 +12,9 @@ namespace CaveGame.Core
|
||||
public Vector2 Position { get; set; }
|
||||
public float Rotation { get; set; }
|
||||
|
||||
public Rectangle Bounds { get; set; }
|
||||
public Vector2 WindowSize => GraphicsEngine.Instance.WindowSize;
|
||||
|
||||
public Vector2 _screenSize;
|
||||
public Vector2 _screenSize { get; set; }
|
||||
|
||||
public Vector2 TopLeft
|
||||
{
|
||||
@@ -50,7 +50,7 @@ namespace CaveGame.Core
|
||||
Matrix.CreateTranslation(new Vector3(-OutputPosition.X, -OutputPosition.Y, 0)) *
|
||||
Matrix.CreateRotationZ(Rotation) *
|
||||
Matrix.CreateScale(Zoom) *
|
||||
Matrix.CreateTranslation(new Vector3(Bounds.Width * 0.5f, Bounds.Height * 0.5f, 0));
|
||||
Matrix.CreateTranslation(new Vector3(WindowSize.X * 0.5f, WindowSize.Y * 0.5f, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ namespace CaveGame.Core
|
||||
{
|
||||
var inverseViewMatrix = Matrix.Invert(View);
|
||||
var tl = Vector2.Transform(Vector2.Zero, inverseViewMatrix);
|
||||
var tr = Vector2.Transform(new Vector2(_screenSize.X, 0), inverseViewMatrix);
|
||||
var bl = Vector2.Transform(new Vector2(0, _screenSize.Y), inverseViewMatrix);
|
||||
var tr = Vector2.Transform(new Vector2(WindowSize.X, 0), inverseViewMatrix);
|
||||
var bl = Vector2.Transform(new Vector2(0, WindowSize.Y), inverseViewMatrix);
|
||||
var br = Vector2.Transform(_screenSize, inverseViewMatrix);
|
||||
var min = new Vector2(
|
||||
MathHelper.Min(tl.X, MathHelper.Min(tr.X, MathHelper.Min(bl.X, br.X))),
|
||||
@@ -73,10 +73,8 @@ namespace CaveGame.Core
|
||||
}
|
||||
}
|
||||
|
||||
public Camera2D(Viewport viewport)
|
||||
public Camera2D()
|
||||
{
|
||||
Bounds = viewport.Bounds;
|
||||
_screenSize = new Vector2(Bounds.Width, Bounds.Height);
|
||||
Rotation = 0;
|
||||
Zoom = 1;
|
||||
Position = new Vector2(0, 0);
|
@@ -59,13 +59,15 @@ namespace CaveGame.Core.Game.Items
|
||||
public virtual string Name => this.GetType().Name;
|
||||
public virtual string DisplayName => Name;
|
||||
|
||||
public virtual Texture2D Texture { get; }
|
||||
|
||||
public bool MouseDown { get; set; }
|
||||
|
||||
public void Draw(GraphicsEngine GFX, Texture2D texture, Vector2 position, float scale)
|
||||
{
|
||||
GFX.Sprite(texture, position, null, Color.Gray, Rotation.Zero, Vector2.Zero, scale, SpriteEffects.None, 0);
|
||||
} // pseudo- default draw
|
||||
public virtual void Draw(GraphicsEngine GFX, Vector2 position, float scale) {}
|
||||
public virtual void Draw(GraphicsEngine GFX, Vector2 position, float scale) => Draw(GFX, Texture, position, scale);
|
||||
public virtual void OnClientLMBDown(Player player, IGameClient client, ItemStack stack)
|
||||
{
|
||||
MouseDown = true;
|
||||
@@ -201,7 +203,7 @@ namespace CaveGame.Core.Game.Items
|
||||
|
||||
if (client.World.GetTile(x, y).ID != 0)
|
||||
{
|
||||
client.Send(new DamageTilePacket(new Point(x, y), 2));
|
||||
client.Send(new DamageTilePacket(new Point(x, y), Strength));
|
||||
//client.Send(new PlaceTilePacket(0, 0, 0, x, y));
|
||||
//client.World.SetTile(x, y, new Tiles.Air());
|
||||
}
|
||||
@@ -372,12 +374,33 @@ namespace CaveGame.Core.Game.Items
|
||||
}
|
||||
}
|
||||
|
||||
public class BowItem : Item {
|
||||
public override int MaxStack => 1;
|
||||
public override void OnClientLMBDown(Player player, IGameClient client, ItemStack stack)
|
||||
{
|
||||
// TODO: Find and comsume arrows in inventory
|
||||
bool hasArrows = true;
|
||||
|
||||
|
||||
if (!hasArrows)
|
||||
return;
|
||||
|
||||
MouseState mouse = Mouse.GetState();
|
||||
|
||||
var mp = client.Camera.ScreenToWorldCoordinates(mouse.Position.ToVector2());
|
||||
|
||||
var unitLookVector = player.Position.LookAt(mp);
|
||||
|
||||
client.Send(new PlayerThrowItemPacket(ThrownItem.Arrow, Rotation.FromUnitVector(unitLookVector)));
|
||||
|
||||
base.OnClientLMBDown(player, client, stack);
|
||||
}
|
||||
public override void Draw(GraphicsEngine GFX, Vector2 position, float scale) => Draw(GFX, GFX.BowSprite, position, scale);
|
||||
}
|
||||
|
||||
public class BombItem : Item
|
||||
{
|
||||
public override int MaxStack => 99;
|
||||
|
||||
|
||||
public override void OnClientLMBDown(Player player, IGameClient client, ItemStack stack)
|
||||
{
|
||||
stack.Quantity--;
|
||||
|
@@ -18,7 +18,6 @@ namespace CaveGame.Core.Game.Tiles
|
||||
public class Diode { }
|
||||
public class NORGate { }
|
||||
public class XANDGate { }
|
||||
public class Delay { }
|
||||
public class Pump { }
|
||||
public class Pipe { }
|
||||
public class Trapdoor { }
|
||||
|
@@ -69,7 +69,7 @@ namespace CaveGame.Core.Game.Tiles
|
||||
|
||||
// Tile Properties
|
||||
public virtual float Friction => 1;
|
||||
public virtual byte Opacity => 3;
|
||||
public virtual byte Opacity => 48;
|
||||
public virtual Color Color => Color.White;
|
||||
public virtual Rectangle Quad => TileMap.Default;
|
||||
public virtual byte Hardness => 2;
|
||||
|
@@ -25,6 +25,7 @@ namespace CaveGame.Core.Game.Tiles
|
||||
{
|
||||
public override void Drop(IGameServer server, IGameWorld world, Point tilePosition) { }
|
||||
public override void Draw(GraphicsEngine GFX, int x, int y, Light3 light) { } // leave empty
|
||||
|
||||
}
|
||||
public class Vacuum { }
|
||||
public class Fog { }
|
||||
|
@@ -89,27 +89,27 @@ namespace CaveGame.Core.Game.Tiles
|
||||
}
|
||||
public class Torch : BaseTorch, ILightEmitter
|
||||
{
|
||||
public Light3 Light => new Light3(20, 20, 12);
|
||||
public Light3 Light => new Light3(1f, 0.9f, 0.7f);
|
||||
public override Color FlameColor => new Color(1, 1, 0.8f);
|
||||
}
|
||||
public class WhiteTorch : BaseTorch, ILightEmitter
|
||||
{
|
||||
public Light3 Light => new Light3(20, 20, 20);
|
||||
public Light3 Light => new Light3(1f, 1f, 1f);
|
||||
public override Color FlameColor => new Color(1, 1, 1f);
|
||||
}
|
||||
public class GreenTorch : BaseTorch, ILightEmitter
|
||||
{
|
||||
public Light3 Light => new Light3(0, 20, 0);
|
||||
public Light3 Light => new Light3(0f, 1.2f, 0f);
|
||||
public override Color FlameColor => new Color(0.1f, 1, 0.1f);
|
||||
}
|
||||
public class RedTorch : BaseTorch, ILightEmitter
|
||||
{
|
||||
public Light3 Light => new Light3(20, 0, 0);
|
||||
public Light3 Light => new Light3(1.2f, 0, 0);
|
||||
public override Color FlameColor => new Color(1, 0.1f, 0.1f);
|
||||
}
|
||||
public class BlueTorch : BaseTorch, ILightEmitter
|
||||
{
|
||||
public Light3 Light => new Light3(0, 0, 20);
|
||||
public Light3 Light => new Light3(0, 0, 1.2f);
|
||||
public override Color FlameColor => new Color(0.2f, 0.2f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
@@ -36,7 +36,7 @@ namespace CaveGame.Core.Game.Walls
|
||||
|
||||
public class Wall
|
||||
{
|
||||
public virtual byte Opacity => 1;
|
||||
public virtual byte Opacity => 4;
|
||||
public virtual Color Color => Color.Gray;
|
||||
public virtual Rectangle Quad => TileMap.Default;
|
||||
public virtual byte Hardness => 2;
|
||||
|
@@ -11,7 +11,7 @@ namespace CaveGame.Core.Generic
|
||||
SubtractIncrement
|
||||
}
|
||||
|
||||
public class DelayedTask
|
||||
public class RepeatingIntervalTask
|
||||
{
|
||||
public TimeStepProcedure TimeStepProcedure { get; set; }
|
||||
public bool Active { get; set; }
|
||||
@@ -23,7 +23,7 @@ namespace CaveGame.Core.Generic
|
||||
private Action job;
|
||||
|
||||
|
||||
public DelayedTask(Action action, float timeIncrement, TimeStepProcedure procedure = TimeStepProcedure.SetToZero)
|
||||
public RepeatingIntervalTask(Action action, float timeIncrement, TimeStepProcedure procedure = TimeStepProcedure.SetToZero)
|
||||
{
|
||||
Active = true;
|
||||
job = action;
|
73
Core/Generic/UniqueQueue.cs
Normal file
73
Core/Generic/UniqueQueue.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core.Generic
|
||||
{
|
||||
public class UniqueQueue<T> : IEnumerable<T>
|
||||
{
|
||||
private HashSet<T> hashSet;
|
||||
private Queue<T> queue;
|
||||
|
||||
|
||||
public UniqueQueue()
|
||||
{
|
||||
hashSet = new HashSet<T>();
|
||||
queue = new Queue<T>();
|
||||
}
|
||||
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return hashSet.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
hashSet.Clear();
|
||||
queue.Clear();
|
||||
}
|
||||
|
||||
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return hashSet.Contains(item);
|
||||
}
|
||||
|
||||
|
||||
public void Enqueue(T item)
|
||||
{
|
||||
if (hashSet.Add(item))
|
||||
{
|
||||
queue.Enqueue(item);
|
||||
}
|
||||
}
|
||||
|
||||
public T Dequeue()
|
||||
{
|
||||
T item = queue.Dequeue();
|
||||
hashSet.Remove(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
public T Peek()
|
||||
{
|
||||
return queue.Peek();
|
||||
}
|
||||
|
||||
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return queue.GetEnumerator();
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return queue.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
@@ -18,17 +18,17 @@ namespace CaveGame.Core
|
||||
{
|
||||
public const int TileSize = 8;
|
||||
public const int ChunkSize = 32;
|
||||
public const string CurrentVersionString = "2.2.0";
|
||||
public const string CurrentVersionFullString = "2.2.0 Beta";
|
||||
public const int ProtocolVersion = 2;
|
||||
public const string CurrentVersionString = "2.3.0";
|
||||
public const string CurrentVersionFullString = "2.3.0 Beta";
|
||||
public const int ProtocolVersion = 3;
|
||||
|
||||
public static UpdateDescription[] UpdateLog =
|
||||
{
|
||||
new UpdateDescription
|
||||
{
|
||||
VersionString = "2.2.0",
|
||||
Date = "2020 November 27",
|
||||
UpdateName = "Multiplayer Update 2",
|
||||
VersionString = "2.3.0",
|
||||
Date = "2020 XX XX",
|
||||
UpdateName = "Multiplayer Update 2.3",
|
||||
|
||||
ChangeLog = new string[]{
|
||||
"+ Added Biomes",
|
||||
@@ -48,7 +48,7 @@ namespace CaveGame.Core
|
||||
},
|
||||
Notes = new string[]{
|
||||
"This version will be distributed to playtesters only.",
|
||||
"2.2.1 will be released on Steam in one week."
|
||||
"2.3 will be released on Steam in one week."
|
||||
},
|
||||
},
|
||||
new UpdateDescription
|
||||
|
@@ -12,11 +12,28 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
|
||||
|
||||
|
||||
using Circle = List<Vector2>;
|
||||
using Arc = List<Vector2>;
|
||||
public interface IGraphicsEngine
|
||||
{
|
||||
Vector2 WindowSize { get; set; }
|
||||
SpriteBatch SpriteBatch { get; set; }
|
||||
|
||||
SpriteSortMode SpriteSortMode { get; set; }
|
||||
BlendState BlendState { get; set; }
|
||||
SamplerState SamplerState { get; set; }
|
||||
DepthStencilState DepthStencilState { get; set; }
|
||||
RasterizerState RasterizerState { get; set; }
|
||||
Effect Shader { get; set; }
|
||||
Matrix Matrix { get; set; }
|
||||
|
||||
void Begin(SpriteSortMode sorting = SpriteSortMode.Deferred, BlendState blending = null, SamplerState sampling = null,
|
||||
DepthStencilState depthStencil = null, RasterizerState rasterizing = null, Effect effect = null, Matrix? transform = null);
|
||||
void End();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class MissingGameDataException : ApplicationException {
|
||||
public string MissingFilename { get; set; }
|
||||
@@ -101,17 +118,19 @@ namespace CaveGame.Core
|
||||
public SpriteFont ComicSans10 { get; private set; }
|
||||
public void LoadAssets(ContentManager Content)
|
||||
{
|
||||
Arial8 = Content.Load<SpriteFont>("Fonts/Arial8");
|
||||
Arial10 = Content.Load<SpriteFont>("Fonts/Arial10");
|
||||
Arial12 = Content.Load<SpriteFont>("Fonts/Arial12");
|
||||
Arial14 = Content.Load<SpriteFont>("Fonts/Arial14");
|
||||
Arial16 = Content.Load<SpriteFont>("Fonts/Arial16");
|
||||
Arial20 = Content.Load<SpriteFont>("Fonts/Arial20");
|
||||
Arial30 = Content.Load<SpriteFont>("Fonts/Arial30");
|
||||
Arial10Italic = Content.Load<SpriteFont>("Fonts/Arial10Italic");
|
||||
Consolas10 = Content.Load<SpriteFont>("Fonts/Consolas10");
|
||||
Consolas12 = Content.Load<SpriteFont>("Fonts/Consolas12");
|
||||
ComicSans10 = Content.Load<SpriteFont>("Fonts/ComicSans10");
|
||||
|
||||
Content.RootDirectory = Path.Combine("assets", "fonts");
|
||||
Arial8 = Content.Load<SpriteFont>("Arial8");
|
||||
Arial10 = Content.Load<SpriteFont>("Arial10");
|
||||
Arial12 = Content.Load<SpriteFont>("Arial12");
|
||||
Arial14 = Content.Load<SpriteFont>("Arial14");
|
||||
Arial16 = Content.Load<SpriteFont>("Arial16");
|
||||
Arial20 = Content.Load<SpriteFont>("Arial20");
|
||||
Arial30 = Content.Load<SpriteFont>("Arial30");
|
||||
Arial10Italic = Content.Load<SpriteFont>("Arial10Italic");
|
||||
Consolas10 = Content.Load<SpriteFont>("Consolas10");
|
||||
Consolas12 = Content.Load<SpriteFont>("Consolas12");
|
||||
ComicSans10 = Content.Load<SpriteFont>("ComicSans10");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,8 +142,10 @@ namespace CaveGame.Core
|
||||
|
||||
public static GraphicsEngine Instance { get; private set; }
|
||||
|
||||
|
||||
|
||||
#region Texture Shortcuts
|
||||
public Texture2D Player => Textures["Entities/player.png"];
|
||||
|
||||
public Texture2D TitleScreen => Textures["TitleScreen.png"];
|
||||
public Texture2D EyeOfHorus => Textures["csoft.png"];
|
||||
public Texture2D ParticleSet => Textures["particles.png"];
|
||||
@@ -132,29 +153,38 @@ namespace CaveGame.Core
|
||||
public Texture2D BG => Textures["menu_bg.png"];
|
||||
public Texture2D Border => Textures["border.png"];
|
||||
public Texture2D Slot => Textures["slot.png"];
|
||||
public Texture2D CloudBackground => Textures["clouds.png"];
|
||||
public Texture2D Starfield => Textures["stars.png"];
|
||||
|
||||
public Texture2D BombSprite => Textures["bomb.png"];
|
||||
public Texture2D Bong => Textures["bong.png"];
|
||||
public Texture2D Arrow => Textures["arrow.png"];
|
||||
public Texture2D Bucket => Textures["bucket.png"];
|
||||
public Texture2D BigPickaxe => Textures["bigpickaxe.png"];
|
||||
public Texture2D Helmet => Textures["helmet.png"];
|
||||
public Texture2D Chestplate => Textures["chestplate.png"];
|
||||
public Texture2D Sword => Textures["sword.png"];
|
||||
public Texture2D WallScraper => Textures["wallscraper.png"];
|
||||
public Texture2D PickaxeNew => Textures["pickaxenew.png"];
|
||||
public Texture2D Scroll => Textures["scroll.png"];
|
||||
public Texture2D Dynamite => Textures["dynamite.png"];
|
||||
public Texture2D Workbench => Textures["workbench.png"];
|
||||
public Texture2D Potion => Textures["potion.png"];
|
||||
public Texture2D Jetpack => Textures["jetpack.png"];
|
||||
public Texture2D Door => Textures["door.png"];
|
||||
public Texture2D ForestPainting => Textures["forestpainting.png"];
|
||||
public Texture2D Ingot => Textures["ingot.png"];
|
||||
public Texture2D Leggings => Textures["leggings.png"];
|
||||
public Texture2D Furnace => Textures["furnace.png"];
|
||||
public Texture2D Campfire => Textures["campfire.png"];
|
||||
public Texture2D VoidMonster => Textures["Entities/tortured.png"];
|
||||
public Texture2D Explosion => Textures["michaelbay.png"];
|
||||
public Texture2D BowSprite => Textures["items:bow.png"];
|
||||
public Texture2D BombSprite => Textures["items:bomb.png"];
|
||||
public Texture2D Bong => Textures["items:bong.png"];
|
||||
public Texture2D Arrow => Textures["items:arrow.png"];
|
||||
public Texture2D Bucket => Textures["items:bucket.png"];
|
||||
public Texture2D BigPickaxe => Textures["items:bigpickaxe.png"];
|
||||
public Texture2D Helmet => Textures["armor:helmet.png"];
|
||||
public Texture2D Chestplate => Textures["armor:chestplate.png"];
|
||||
public Texture2D Sword => Textures["items:sword.png"];
|
||||
public Texture2D WallScraper => Textures["items:wallscraper.png"];
|
||||
public Texture2D PickaxeNew => Textures["items:pickaxenew.png"];
|
||||
public Texture2D Scroll => Textures["items:scroll.png"];
|
||||
public Texture2D Dynamite => Textures["items:dynamite.png"];
|
||||
public Texture2D Workbench => Textures["items:workbench.png"];
|
||||
public Texture2D Potion => Textures["items:potion.png"];
|
||||
public Texture2D Jetpack => Textures["items:jetpack.png"];
|
||||
public Texture2D Door => Textures["items:door.png"];
|
||||
public Texture2D ForestPainting => Textures["items:forestpainting.png"];
|
||||
public Texture2D Ingot => Textures["items:ingot.png"];
|
||||
public Texture2D Leggings => Textures["armor:leggings.png"];
|
||||
public Texture2D Furnace => Textures["items:furnace.png"];
|
||||
public Texture2D Campfire => Textures["items:campfire.png"];
|
||||
|
||||
public Texture2D Player => Textures["entities:player.png"];
|
||||
public Texture2D ArrowEntity => Textures["entities:arrow.png"];
|
||||
public Texture2D VoidMonster => Textures["entities:wurmhole.png"];
|
||||
public Texture2D Bee => Textures["entities:bee.png"];
|
||||
public Texture2D Goldfish => Textures["entities:gregothy.png"];
|
||||
|
||||
//public static Texture2D Campfire => Textures["campfire.png"];
|
||||
#endregion
|
||||
@@ -193,26 +223,29 @@ namespace CaveGame.Core
|
||||
|
||||
public void LoadAssets(GraphicsDevice graphicsDevice)
|
||||
{
|
||||
var texturesPath = Path.Combine("Assets", "Textures");
|
||||
var texturesPath = Path.Combine("assets", "textures");
|
||||
if (!Directory.Exists(texturesPath))
|
||||
throw new MissingContentFolderException { MissingFilename = "texturesPath" };
|
||||
|
||||
foreach (var tex in Directory.GetFiles("Assets/Textures/", "*.png"))
|
||||
foreach (var tex in Directory.GetFiles(texturesPath, "*.png", SearchOption.AllDirectories))
|
||||
{
|
||||
LoadingQueue.Enqueue(new TextureDef(
|
||||
tex.Replace("Assets/Textures/", ""),
|
||||
tex
|
||||
));
|
||||
|
||||
var trimmedPath = tex.Replace(texturesPath + @"\", "");
|
||||
var cleanedPath = trimmedPath.Replace(@"\", ":");
|
||||
// GameConsole.Log($"QTexture {tex} => {cleanedPath} ");
|
||||
|
||||
LoadingQueue.Enqueue(new TextureDef(cleanedPath, tex));
|
||||
TotalTextures++;
|
||||
}
|
||||
|
||||
|
||||
var entityTexturesPath = Path.Combine("Assets", "Textures", "Entities");
|
||||
foreach (var tex in Directory.GetFiles("Assets/Textures/Entities/", "*.png"))
|
||||
#if !EDITOR
|
||||
/*var entityTexturesPath = Path.Combine("Assets", "Textures", "Entities");
|
||||
foreach (var tex in Directory.GetFiles(entityTexturesPath, "*.png", SearchOption.AllDirectories))
|
||||
{
|
||||
// Texture2D loaded = AssetLoader.LoadTexture(graphicsDevice, tex);
|
||||
|
||||
GameConsole.Log($"QTexture {tex} => {tex.Replace(entityTexturesPath + @"\", "")} ");
|
||||
LoadingQueue.Enqueue(new TextureDef(
|
||||
tex.Replace("Assets/Textures/", ""),
|
||||
tex.Replace(entityTexturesPath + @"\", ""),
|
||||
tex
|
||||
));
|
||||
TotalTextures++;
|
||||
@@ -226,7 +259,8 @@ namespace CaveGame.Core
|
||||
tex
|
||||
));
|
||||
TotalTextures++;
|
||||
}
|
||||
}*/
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
|
@@ -1,108 +0,0 @@
|
||||
using CaveGame.Core.Game.Entities;
|
||||
using CaveGame.Core.Generic;
|
||||
using CaveGame.Core.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
|
||||
public enum TextXAlignment
|
||||
{
|
||||
Left,
|
||||
Center,
|
||||
Right
|
||||
}
|
||||
public enum TextYAlignment
|
||||
{
|
||||
Top,
|
||||
Center,
|
||||
Bottom,
|
||||
|
||||
}
|
||||
public enum GameSteamAchievement : byte
|
||||
{
|
||||
HELLO_WORLD = 0,
|
||||
MORNING_WOOD = 1,
|
||||
|
||||
}
|
||||
|
||||
public interface IEntityManager
|
||||
{
|
||||
int GetNextEntityNetworkID();
|
||||
}
|
||||
public interface ISteamManager
|
||||
{
|
||||
bool HasAchievement(GameSteamAchievement ach);
|
||||
void AwardAchievement(GameSteamAchievement ach);
|
||||
}
|
||||
public interface ICaveGame
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public interface ICommonGameDriver
|
||||
{
|
||||
IMessageOutlet Output { get; }
|
||||
}
|
||||
|
||||
public interface IGameClient
|
||||
{
|
||||
Camera2D Camera { get; }
|
||||
void Send(Packet p);
|
||||
IClientWorld World { get; }
|
||||
|
||||
}
|
||||
|
||||
public interface IGameServer
|
||||
{
|
||||
void SendTo(Packet p, User user);
|
||||
void SendToAll(Packet p);
|
||||
void SendToAllExcept(Packet p, User exclusion);
|
||||
User GetConnectedUser(IPEndPoint ep);
|
||||
void OutputAndChat(string text);
|
||||
void Chat(string text);
|
||||
void Chat(string text, Color color);
|
||||
IServerWorld World { get; }
|
||||
void SpawnEntity(IEntity entity);
|
||||
void Update(GameTime gt);
|
||||
int TickRate { get; }
|
||||
int MaxPlayers { get; }
|
||||
IEntityManager EntityManager { get; }
|
||||
|
||||
}
|
||||
|
||||
// TODO: Make comprehensive render contract
|
||||
public interface IGraphicsEngine
|
||||
{
|
||||
Vector2 WindowSize { get; set; }
|
||||
SpriteBatch SpriteBatch { get; set; }
|
||||
|
||||
SpriteSortMode SpriteSortMode { get; set; }
|
||||
BlendState BlendState { get; set; }
|
||||
SamplerState SamplerState { get; set; }
|
||||
DepthStencilState DepthStencilState { get; set; }
|
||||
RasterizerState RasterizerState { get; set; }
|
||||
Effect Shader { get; set; }
|
||||
Matrix Matrix { get; set; }
|
||||
|
||||
void Begin(SpriteSortMode sorting = SpriteSortMode.Deferred, BlendState blending = null, SamplerState sampling = null,
|
||||
DepthStencilState depthStencil = null, RasterizerState rasterizing = null, Effect effect = null, Matrix? transform = null);
|
||||
void End();
|
||||
|
||||
}
|
||||
|
||||
// todo: sound
|
||||
public interface ISoundEngine
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
11
Core/Interfaces/ICaveGameImplementation.cs
Normal file
11
Core/Interfaces/ICaveGameImplementation.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
public interface ICaveGame
|
||||
{
|
||||
|
||||
}
|
||||
}
|
12
Core/Interfaces/IDamageSource.cs
Normal file
12
Core/Interfaces/IDamageSource.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Applied to the following:
|
||||
/// IEntity, Explosion, and certain tile classes
|
||||
/// </summary>
|
||||
public interface IDamageSource { }
|
||||
}
|
11
Core/Interfaces/IEntityManager.cs
Normal file
11
Core/Interfaces/IEntityManager.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
public interface IEntityManager
|
||||
{
|
||||
int GetNextEntityNetworkID();
|
||||
}
|
||||
}
|
15
Core/Interfaces/IGameClient.cs
Normal file
15
Core/Interfaces/IGameClient.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using CaveGame.Core.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
public interface IGameClient
|
||||
{
|
||||
Camera2D Camera { get; }
|
||||
void Send(Packet p);
|
||||
IClientWorld World { get; }
|
||||
|
||||
}
|
||||
}
|
29
Core/Interfaces/IGameServer.cs
Normal file
29
Core/Interfaces/IGameServer.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using CaveGame.Core.Game.Entities;
|
||||
using CaveGame.Core.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
public interface IGameServer
|
||||
{
|
||||
Entity GetEntity(int networkID);
|
||||
void SendTo(Packet p, User user);
|
||||
void SendToAll(Packet p);
|
||||
void SendToAllExcept(Packet p, User exclusion);
|
||||
User GetConnectedUser(IPEndPoint ep);
|
||||
void OutputAndChat(string text);
|
||||
void Chat(string text);
|
||||
void Chat(string text, Color color);
|
||||
IServerWorld World { get; }
|
||||
void SpawnEntity(IEntity entity);
|
||||
void Update(GameTime gt);
|
||||
int TickRate { get; }
|
||||
int MaxPlayers { get; }
|
||||
IEntityManager EntityManager { get; }
|
||||
|
||||
}
|
||||
}
|
@@ -8,6 +8,9 @@ namespace CaveGame.Core
|
||||
public interface ILightingEngine
|
||||
{
|
||||
Light3 GetLight(int x, int y);
|
||||
void SetLight(int x, int y, Light3 val);
|
||||
Light3 GetLight(Point coords);
|
||||
//void SetLight(int x, int y, Light3 val);
|
||||
// void SetLight(Point coords, Light3 val);
|
||||
void InvokeLight(Point coords, Light3 val);
|
||||
}
|
||||
}
|
24
Core/Interfaces/INetworkingSubsystem.cs
Normal file
24
Core/Interfaces/INetworkingSubsystem.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
public interface INetworkingSubsystem
|
||||
{
|
||||
DateTime LatestReceiveTimestamp { get; }
|
||||
DateTime LatestSendTimestamp { get; }
|
||||
|
||||
int PacketsReceived { get; }
|
||||
int PacketsSent { get; }
|
||||
|
||||
int TotalBytesSent { get; }
|
||||
int TotalBytesReceived { get; }
|
||||
|
||||
int BytesSentPerSecond { get; }
|
||||
int BytesReceivedPerSecond { get; }
|
||||
|
||||
void Update(GameTime gt);
|
||||
}
|
||||
}
|
12
Core/Interfaces/ISteamManager.cs
Normal file
12
Core/Interfaces/ISteamManager.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
public interface ISteamManager
|
||||
{
|
||||
bool HasAchievement(GameSteamAchievement ach);
|
||||
void AwardAchievement(GameSteamAchievement ach);
|
||||
}
|
||||
}
|
@@ -12,5 +12,10 @@ namespace CaveGame.Core
|
||||
public static void Log(string message) => messenger?.Out(message);
|
||||
public static void Log(string message, Color color) => messenger?.Out(message, color);
|
||||
|
||||
public static void LogWTF(string message) => messenger?.Out($"[WTF]: {message}", new Color(0, 0.8f, 0.8f));
|
||||
public static void LogWarning(string message) => messenger?.Out($"[WARN]: {message}", new Color(1, 0.7f, 0));
|
||||
public static void LogProblem(string message) => messenger?.Out($"[PROBLEM]: {message}", new Color(1, 0f, 0.5f));
|
||||
public static void LogError(string message) => messenger?.Out($"[ERROR]: {message}", new Color(1, 0f, 0));
|
||||
|
||||
}
|
||||
}
|
@@ -11,7 +11,10 @@ namespace CaveGame.Core
|
||||
string date = DateTime.Now.ToString("yy-MM-dd");
|
||||
if (!Directory.Exists("logs"))
|
||||
Directory.CreateDirectory("logs");
|
||||
File.AppendAllText($"logs/log_{date}.txt", DateTime.Now.ToString("HH-mm-ss") + ": " + data + "\n");
|
||||
File.AppendAllText(
|
||||
Path.Combine("logs", $"log_{date}.txt"),
|
||||
DateTime.Now.ToString("HH-mm-ss") + ": " + data + "\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@@ -12,13 +12,35 @@ namespace CaveGame.Core
|
||||
|
||||
public static class MonoGameExtensions
|
||||
{
|
||||
public static Vector2 LookAt(this Vector2 origin, Vector2 goal)
|
||||
|
||||
public static Rectangle GetSpriteFrame(this Rectangle[] animation, float animationTime)
|
||||
{
|
||||
Vector2 UnitVector = (goal - origin);
|
||||
UnitVector.Normalize();
|
||||
return UnitVector;
|
||||
int anim_length = animation.Length;
|
||||
return animation[(int)(animationTime % anim_length)];
|
||||
}
|
||||
|
||||
public static Point ToTileCoords(this Vector2 grug) => new Point(
|
||||
(int)Math.Floor(grug.X / Globals.TileSize),
|
||||
(int)Math.Floor(grug.Y / Globals.TileSize)
|
||||
);
|
||||
|
||||
public static Vector2 RoundTo(this Vector2 og, int decimalplaces)
|
||||
{
|
||||
return new Vector2((float)Math.Round(og.X, decimalplaces), (float)Math.Round(og.Y, decimalplaces));
|
||||
}
|
||||
|
||||
public static Vector2 GetY(this Vector2 vec) => new Vector2(0, vec.Y);
|
||||
|
||||
public static Vector2 GetX(this Vector2 vec) => new Vector2(vec.X, 0);
|
||||
|
||||
public static Vector2 LookAt(this Vector2 origin, Vector2 goal) => (goal - origin).Unit();
|
||||
|
||||
public static Vector2 Unit(this Vector2 vector)
|
||||
{
|
||||
Vector2 copy = vector;
|
||||
copy.Normalize();
|
||||
return copy;
|
||||
}
|
||||
public static float Distance(this Vector2 a, Vector2 b) => (a - b).Length();
|
||||
|
||||
public static Color Inverse(this Color color)
|
||||
|
@@ -82,7 +82,10 @@ namespace CaveGame.Core.Network
|
||||
cAdminCommand,
|
||||
cThrowItem,
|
||||
cDamageFurniture,
|
||||
|
||||
cDamageTile,
|
||||
cPlaceTile,
|
||||
cPlaceWall,
|
||||
cDamageWall,
|
||||
#endregion
|
||||
|
||||
#region Server-Sender Packets
|
||||
@@ -254,7 +257,6 @@ namespace CaveGame.Core.Network
|
||||
BlastRadius = Payload.ReadFloat(8), // 4 bytes (12)
|
||||
BlastPressure = Payload.ReadFloat(12)// 4 bytes (16)
|
||||
};
|
||||
|
||||
set
|
||||
{
|
||||
Payload.WriteVector2(0, value.Position);
|
||||
@@ -439,7 +441,7 @@ namespace CaveGame.Core.Network
|
||||
set => Payload = value.ToMetabinary().Serialize();
|
||||
}
|
||||
}
|
||||
public class EntityPositionPacket : Packet
|
||||
public class EntityPhysicsStatePacket : Packet
|
||||
{
|
||||
public int EntityID
|
||||
{
|
||||
@@ -472,7 +474,7 @@ namespace CaveGame.Core.Network
|
||||
}
|
||||
|
||||
|
||||
public EntityPositionPacket(int id, int health, Vector2 position, Vector2 velocity, Vector2 nextPosition) : base(PacketType.netEntityPhysicsUpdate) {
|
||||
public EntityPhysicsStatePacket(int id, int health, Vector2 position, Vector2 velocity, Vector2 nextPosition) : base(PacketType.netEntityPhysicsUpdate) {
|
||||
Payload = new byte[32];
|
||||
EntityID = id;
|
||||
Health = health;
|
||||
@@ -481,7 +483,7 @@ namespace CaveGame.Core.Network
|
||||
NextPosition = nextPosition;
|
||||
}
|
||||
|
||||
public EntityPositionPacket(IEntity entity) : base(PacketType.netEntityPhysicsUpdate)
|
||||
public EntityPhysicsStatePacket(IEntity entity) : base(PacketType.netEntityPhysicsUpdate)
|
||||
{
|
||||
Payload = new byte[32];
|
||||
EntityID = entity.EntityNetworkID;
|
||||
@@ -494,7 +496,7 @@ namespace CaveGame.Core.Network
|
||||
}
|
||||
}
|
||||
|
||||
public EntityPositionPacket(byte[] bytes) : base(bytes) { }
|
||||
public EntityPhysicsStatePacket(byte[] bytes) : base(bytes) { }
|
||||
}
|
||||
public class PlaceFurniturePacket : Packet
|
||||
{
|
||||
@@ -743,6 +745,7 @@ namespace CaveGame.Core.Network
|
||||
public enum ThrownItem : byte
|
||||
{
|
||||
Bomb,
|
||||
Arrow,
|
||||
}
|
||||
|
||||
public class PlayerThrowItemPacket : Packet
|
||||
@@ -881,6 +884,7 @@ namespace CaveGame.Core.Network
|
||||
WorldX = worldX;
|
||||
WorldY = worldY;
|
||||
}
|
||||
public PlaceWallPacket(Point coords, Wall w) : this(w.ID, 0, w.Damage, coords.X, coords.Y) { }
|
||||
}
|
||||
public class PlaceTilePacket : Packet
|
||||
{
|
||||
@@ -918,6 +922,15 @@ namespace CaveGame.Core.Network
|
||||
WorldX = worldX;
|
||||
WorldY = worldY;
|
||||
}
|
||||
public PlaceTilePacket(Point coords, Tile t) : this(t.ID, t.TileState, t.Damage, coords.X, coords.Y) { }
|
||||
}
|
||||
public class ServerUpdateTilePacket : Packet
|
||||
{
|
||||
public ServerUpdateTilePacket() : base(PacketType.sUpdateTile) { }
|
||||
}
|
||||
public class ServerUpdateWallPacket : Packet
|
||||
{
|
||||
public ServerUpdateWallPacket() : base(PacketType.sUpdateWall) { }
|
||||
}
|
||||
// temporary?
|
||||
public class RequestChunkPacket : Packet
|
||||
|
@@ -6,6 +6,13 @@ using System.Text;
|
||||
|
||||
namespace CaveGame.Core.Network.Packets
|
||||
{
|
||||
|
||||
|
||||
public class PingPacket : Packet
|
||||
{
|
||||
public PingPacket() : base(PacketType.netPing) { Payload = new byte[4]; } // pretty much empty lol
|
||||
public PingPacket(byte[] data) : base(data) { }
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
92
Core/Network/SharedNetworkSubsystem.cs
Normal file
92
Core/Network/SharedNetworkSubsystem.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace CaveGame.Core.Network
|
||||
{
|
||||
public struct OutgoingPayload
|
||||
{
|
||||
public Packet Payload { get; set; }
|
||||
public IPEndPoint TargetAddress { get; set; }
|
||||
}
|
||||
|
||||
public class SharedNetworkSubsystem
|
||||
{
|
||||
public const int NAP_TIME_MILLISECONDS = 1;
|
||||
public const int SIO_UDP_CONNRESET = -1744830452;
|
||||
public const int PROTOCOL_VERSION = Globals.ProtocolVersion;
|
||||
|
||||
protected ConcurrentQueue<NetworkMessage> IncomingMessages { get; private set; }
|
||||
protected ConcurrentQueue<OutgoingPayload> OutgoingMessages { get; private set; }
|
||||
|
||||
|
||||
public virtual DateTime LatestReceiveTimestamp { get; protected set; }
|
||||
public virtual DateTime LatestSendTimestamp { get; protected set; }
|
||||
public virtual int PacketsReceived { get; protected set; }
|
||||
public virtual int PacketsSent { get; protected set; }
|
||||
public virtual int TotalBytesSent { get; protected set; }
|
||||
public virtual int TotalBytesReceived { get; protected set; }
|
||||
public virtual int BytesSentPerSecond { get; protected set; }
|
||||
public virtual int BytesReceivedPerSecond { get; protected set; }
|
||||
|
||||
public virtual IMessageOutlet Output { get; set; }
|
||||
|
||||
public virtual int Port { get; protected set; }
|
||||
|
||||
protected int InternalReceiveCount { get; set; }
|
||||
protected int InternalSendCount { get; set; }
|
||||
|
||||
private float counter = 0;
|
||||
|
||||
public UdpClient UdpSocket { get; protected set; }
|
||||
|
||||
protected void IOControlFixICMPBullshit()
|
||||
{
|
||||
UdpSocket.Client.IOControl(
|
||||
(IOControlCode)SIO_UDP_CONNRESET,
|
||||
new byte[] { 0, 0, 0, 0 },
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
public SharedNetworkSubsystem()
|
||||
{
|
||||
IncomingMessages = new ConcurrentQueue<NetworkMessage>();
|
||||
OutgoingMessages = new ConcurrentQueue<OutgoingPayload>();
|
||||
IOControlFixICMPBullshit();
|
||||
}
|
||||
|
||||
private void ResetByteCounters()
|
||||
{
|
||||
BytesSentPerSecond = InternalSendCount;
|
||||
BytesReceivedPerSecond = InternalReceiveCount;
|
||||
InternalSendCount = 0;
|
||||
InternalReceiveCount = 0;
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
|
||||
public virtual void Update(GameTime gt)
|
||||
{
|
||||
counter += gt.GetDelta();
|
||||
if (counter > (1.0f))
|
||||
ResetByteCounters();
|
||||
}
|
||||
|
||||
public virtual void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void Close()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -32,6 +32,11 @@ namespace CaveGame.Core.Network
|
||||
{
|
||||
return dispatchedPackets.Count > 0;
|
||||
}
|
||||
public void SendDispatchMessages(IGameServer server)
|
||||
{
|
||||
if (DispatcherHasMessage())
|
||||
server.SendTo(PopDispatcherQueue(), this);
|
||||
}
|
||||
|
||||
public Packet PopDispatcherQueue()
|
||||
{
|
||||
|
@@ -26,23 +26,17 @@ namespace CaveGame.Core
|
||||
catch
|
||||
{
|
||||
// hack because of this: https://github.com/dotnet/corefx/issues/10361
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
if (IsWindows())
|
||||
{
|
||||
url = url.Replace("&", "^&");
|
||||
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true });
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
else if (IsLinux())
|
||||
Process.Start("xdg-open", url);
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
else if (IsMacOS())
|
||||
Process.Start("open", url);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -46,13 +46,14 @@ namespace CaveGame.Core
|
||||
public static Vector2 Origin = new Vector2(2, 2);
|
||||
public static Vector2 Friction = new Vector2(0.8f, 0.8f);
|
||||
public static float Mass = 0.1f;
|
||||
public static Vector2 BoundingBox = new Vector2(2, 2);
|
||||
public override float MaxParticleAge => 2.0f;
|
||||
|
||||
public Rotation Rotation { get; set; }
|
||||
public Vector2 Position { get; set; }
|
||||
|
||||
public Color Color { get; set; }
|
||||
public float Scale { get; set; }
|
||||
public Vector2 Scale { get; set; }
|
||||
public Vector2 NextPosition;
|
||||
public Vector2 Velocity;
|
||||
public Vector2 Accelleration;
|
||||
@@ -61,7 +62,7 @@ namespace CaveGame.Core
|
||||
|
||||
|
||||
|
||||
public void Initialize(Vector2 _position, Color _color, Rotation _rotation, float _scale, Vector2 _accel)
|
||||
public void Initialize(Vector2 _position, Color _color, Rotation _rotation, Vector2 _scale, Vector2 _accel)
|
||||
{
|
||||
ParticleAge = 0;
|
||||
Position = _position;
|
||||
@@ -83,6 +84,38 @@ namespace CaveGame.Core
|
||||
|
||||
public override void PhysicsStep(IGameWorld world, float step)
|
||||
{
|
||||
var tilePosition = new Point(
|
||||
(int)Math.Floor(Position.X / Globals.TileSize),
|
||||
(int)Math.Floor(Position.Y / Globals.TileSize)
|
||||
);
|
||||
|
||||
int bb = 2;
|
||||
for (int x = -bb; x < bb; x++)
|
||||
{
|
||||
for (int y = -bb; y < bb; y++)
|
||||
{
|
||||
Point tileBoxPos = new Point(tilePosition.X + x, tilePosition.Y + y);
|
||||
|
||||
var tile = world.GetTile(tileBoxPos.X, tileBoxPos.Y);
|
||||
|
||||
if (tile.ID != 0 && (!(tile is INonSolid) || tile is ILiquid))
|
||||
{
|
||||
var tileChec = (tileBoxPos.ToVector2() * Globals.TileSize) + new Vector2(4, 4);
|
||||
var tileBoxSize = new Vector2(4, 4);
|
||||
if (CollisionSolver.CheckAABB(NextPosition, BoundingBox * Scale, tileChec, tileBoxSize))
|
||||
{
|
||||
var separation = CollisionSolver.GetSeparationAABB(NextPosition, BoundingBox, tileChec, tileBoxSize);
|
||||
var normal = CollisionSolver.GetNormalAABB(separation, Velocity);
|
||||
if (tile.ID > 0 && !(tile is INonSolid))
|
||||
{
|
||||
NextPosition += separation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Velocity += (Accelleration * step*3);
|
||||
Accelleration -= (Accelleration * step*3);
|
||||
|
||||
@@ -173,6 +206,70 @@ namespace CaveGame.Core
|
||||
}
|
||||
}
|
||||
|
||||
public class ExplosionParticle : Particle
|
||||
{
|
||||
public static Rectangle SP_EXPLOSION0 = new Rectangle(0, 0, 32, 32);
|
||||
public static Rectangle SP_EXPLOSION1 = new Rectangle(32, 0, 32, 32);
|
||||
public static Rectangle SP_EXPLOSION2 = new Rectangle(64, 0, 32, 32);
|
||||
public static Rectangle SP_EXPLOSION3 = new Rectangle(96, 0, 32, 32);
|
||||
public static Rectangle SP_EXPLOSION4 = new Rectangle(128, 0, 32, 32);
|
||||
|
||||
|
||||
public static Rectangle[] ANIM =
|
||||
{
|
||||
SP_EXPLOSION0,
|
||||
SP_EXPLOSION1,
|
||||
SP_EXPLOSION2,
|
||||
SP_EXPLOSION3,
|
||||
SP_EXPLOSION4,
|
||||
|
||||
};
|
||||
|
||||
public static Vector2 Origin => new Vector2(16, 16);
|
||||
|
||||
public override float MaxParticleAge => 0.5f;
|
||||
|
||||
|
||||
public Vector2 Position { get; set; }
|
||||
public Vector2 Scale { get; set; }
|
||||
public Color Color { get; set; }
|
||||
Rotation Rotation { get; set; }
|
||||
|
||||
Random RNG = new Random();
|
||||
|
||||
public ExplosionParticle()
|
||||
{
|
||||
Rotation = Rotation.FromDeg(RNG.Next(0, 360));
|
||||
}
|
||||
|
||||
public override void Update(GameTime gt)
|
||||
{
|
||||
ParticleAge += (float)gt.ElapsedGameTime.TotalSeconds;
|
||||
}
|
||||
|
||||
public override void PhysicsStep(IGameWorld world, float step)
|
||||
{
|
||||
// base.PhysicsStep(world, step);
|
||||
}
|
||||
|
||||
public override void Draw(GraphicsEngine gfx)
|
||||
{
|
||||
|
||||
var quad = ANIM.GetSpriteFrame( (ParticleAge/MaxParticleAge) * (ANIM.Length-1));
|
||||
|
||||
gfx.Sprite(gfx.Explosion, Position, quad, Color.White, Rotation, Origin, Scale, SpriteEffects.None, 0);
|
||||
}
|
||||
|
||||
public void Initialize(Vector2 _position, Color _color, Rotation _rotation, Vector2 _scale)
|
||||
{
|
||||
ParticleAge = 0;
|
||||
Position = _position;
|
||||
Color = _color;
|
||||
Scale = _scale;
|
||||
Dead = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class FireParticle
|
||||
{
|
||||
@@ -197,7 +294,8 @@ namespace CaveGame.Core
|
||||
|
||||
|
||||
ObjectPool<SmokeParticle> SmokeParticlePool = new ObjectPool<SmokeParticle>(() => new SmokeParticle());
|
||||
|
||||
//ObjectPool<SmokeParticle> SmokeParticlePool = new ObjectPool<SmokeParticle>(() => new SmokeParticle());
|
||||
ObjectPool<ExplosionParticle> ExplosionParticlePool = new ObjectPool<ExplosionParticle>(() => new ExplosionParticle());
|
||||
|
||||
private List<Particle> Particles;
|
||||
public IGameWorld World { get; set; }
|
||||
@@ -212,13 +310,19 @@ namespace CaveGame.Core
|
||||
public void Add(Particle p) => Particles.Add(p);
|
||||
|
||||
|
||||
public void EmitSmokeParticle(Vector2 position, Color color, Rotation rotation, float scale, Vector2 accel)
|
||||
public void EmitSmokeParticle(Vector2 position, Color color, Rotation rotation, Vector2 scale, Vector2 accel)
|
||||
{
|
||||
var myParticle = SmokeParticlePool.Get();
|
||||
|
||||
myParticle.Initialize(position, color, rotation, scale, accel);
|
||||
Add(myParticle);
|
||||
}
|
||||
public void EmitExplosionParticle(Vector2 position)
|
||||
{
|
||||
var myParticle = ExplosionParticlePool.Get();
|
||||
myParticle.Initialize(position, Color.White, Rotation.Zero, new Vector2(2.0f));
|
||||
Add(myParticle);
|
||||
}
|
||||
|
||||
public void Update(GameTime gt)
|
||||
{
|
||||
@@ -230,13 +334,25 @@ namespace CaveGame.Core
|
||||
if (particle.ParticleAge > particle.MaxParticleAge)
|
||||
particle.Dead = true;
|
||||
|
||||
if (particle.Dead && particle is SmokeParticle smokey)
|
||||
if (particle.Dead)
|
||||
{
|
||||
SmokeParticlePool.Return(smokey);
|
||||
if (particle is SmokeParticle smokey)
|
||||
SmokeParticlePool.Return(smokey);
|
||||
|
||||
Particles.Remove(particle);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (particle.Dead)
|
||||
{
|
||||
if (particle is ExplosionParticle bomb)
|
||||
ExplosionParticlePool.Return(bomb);
|
||||
|
||||
Particles.Remove(particle);
|
||||
continue;
|
||||
}
|
||||
|
||||
particle.Update(gt);
|
||||
}
|
||||
}
|
||||
|
@@ -8,12 +8,10 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using CaveGame.Core.Game.Walls;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
|
||||
|
||||
|
||||
public class Chunk
|
||||
{
|
||||
public static bool RefreshedThisFrame = false;
|
||||
@@ -26,21 +24,20 @@ namespace CaveGame.Core
|
||||
|
||||
public Light3[,] Lights;
|
||||
public Tile[,] Tiles;
|
||||
public bool[,] NetworkUpdated;
|
||||
public bool[,] TileUpdate;
|
||||
public Wall[,] Walls;
|
||||
public ChunkCoordinates Coordinates;
|
||||
public bool UpdateRenderBuffer = true;
|
||||
public bool WallBufferNeedsRedrawn = true;
|
||||
public bool TileBufferNeedsRedrawn = false;
|
||||
|
||||
public RenderTarget2D TileRenderBuffer { get; set; }
|
||||
public RenderTarget2D WallRenderBuffer { get; set; }
|
||||
|
||||
public RenderTarget2D ForegroundRenderBuffer;
|
||||
public RenderTarget2D BackgroundRenderBuffer;
|
||||
|
||||
public Chunk(int X, int Y)
|
||||
{
|
||||
Coordinates = new ChunkCoordinates(X, Y);
|
||||
NetworkUpdated = new bool[ChunkSize, ChunkSize];
|
||||
|
||||
Tiles = new Tile[ChunkSize, ChunkSize];
|
||||
TileUpdate = new bool[ChunkSize, ChunkSize];
|
||||
Walls = new Wall[ChunkSize, ChunkSize];
|
||||
Lights = new Light3[ChunkSize, ChunkSize];
|
||||
|
||||
@@ -53,15 +50,22 @@ namespace CaveGame.Core
|
||||
SetWall(x, y, new Game.Walls.Air());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
bool disposed;
|
||||
~Chunk() => Dispose(false);
|
||||
|
||||
public void ClearUpdateQueue()
|
||||
{
|
||||
NetworkUpdated = new bool[ChunkSize, ChunkSize];
|
||||
TileUpdate = new bool[ChunkSize, ChunkSize];
|
||||
}
|
||||
public void Dispose() => Dispose(true);
|
||||
|
||||
protected void Dispose(bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
if (disposing)
|
||||
{
|
||||
TileRenderBuffer?.Dispose();
|
||||
WallRenderBuffer?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void FromData(byte[] data)
|
||||
{
|
||||
@@ -126,48 +130,25 @@ namespace CaveGame.Core
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
public void SetTileUpdated(int x, int y)
|
||||
{
|
||||
TileUpdate[x, y] = true;
|
||||
UpdateRenderBuffer = true;
|
||||
}
|
||||
|
||||
public Tile GetTile(int x, int y)=> Tiles[x, y];
|
||||
public void SetTile(int x, int y, Tile t)
|
||||
{
|
||||
//Debug.WriteLine("TT " + t.TileState);
|
||||
if (Tiles[x,y] == null || Tiles[x, y].Equals(t) == false)
|
||||
{
|
||||
Tiles[x, y] = t;
|
||||
NetworkUpdated[x, y] = true; // TODO: Create WallReplicate and TileReplicate queues
|
||||
UpdateRenderBuffer = true;
|
||||
}
|
||||
Tiles[x, y] = t;
|
||||
TileBufferNeedsRedrawn = true;
|
||||
}
|
||||
|
||||
public Tile GetTile(int x, int y)
|
||||
public Wall GetWall(int x, int y) => Walls[x, y];
|
||||
public void SetWall(int x, int y, Wall w)
|
||||
{
|
||||
return Tiles[x, y];
|
||||
Walls[x, y] = w;
|
||||
WallBufferNeedsRedrawn = true;
|
||||
}
|
||||
public void RedrawTileBuffer(GraphicsEngine GFX)
|
||||
{
|
||||
if (TileRenderBuffer == null)
|
||||
TileRenderBuffer = new RenderTarget2D(GFX.GraphicsDevice, ChunkSize * Globals.TileSize, ChunkSize * Globals.TileSize);
|
||||
|
||||
public Wall GetWall(int x, int y) {
|
||||
return Walls[x, y];
|
||||
}
|
||||
|
||||
public void SetWall(int x, int y, Wall w) {
|
||||
// if (Walls[x, y] == null)
|
||||
// {
|
||||
Walls[x, y] = w;
|
||||
NetworkUpdated[x, y] = true; // TODO: Create WallReplicate and TileReplicate queues
|
||||
UpdateRenderBuffer = true;
|
||||
// }
|
||||
}
|
||||
|
||||
private void DrawForegroundBuffer(GraphicsEngine GFX)
|
||||
{
|
||||
if (ForegroundRenderBuffer == null)
|
||||
ForegroundRenderBuffer = new RenderTarget2D(GFX.GraphicsDevice, ChunkSize * Globals.TileSize, ChunkSize * Globals.TileSize);
|
||||
|
||||
GFX.GraphicsDevice.SetRenderTarget(ForegroundRenderBuffer);
|
||||
GFX.GraphicsDevice.SetRenderTarget(TileRenderBuffer);
|
||||
GFX.Clear(Color.Black * 0f);
|
||||
|
||||
GFX.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
|
||||
@@ -175,7 +156,7 @@ namespace CaveGame.Core
|
||||
|
||||
for (int x = 0; x < ChunkSize; x++)
|
||||
{
|
||||
for(int y = 0; y<ChunkSize; y++)
|
||||
for (int y = 0; y < ChunkSize; y++)
|
||||
{
|
||||
tile = GetTile(x, y);
|
||||
if (tile.ID > 0)
|
||||
@@ -186,12 +167,12 @@ namespace CaveGame.Core
|
||||
GFX.GraphicsDevice.SetRenderTarget(null);
|
||||
}
|
||||
|
||||
private void DrawBackgroundBuffer(GraphicsEngine GFX)
|
||||
{
|
||||
if (BackgroundRenderBuffer == null)
|
||||
BackgroundRenderBuffer = new RenderTarget2D(GFX.GraphicsDevice, ChunkSize * Globals.TileSize, ChunkSize * Globals.TileSize);
|
||||
public void RedrawWallBuffer(GraphicsEngine GFX)
|
||||
{
|
||||
if (WallRenderBuffer == null)
|
||||
WallRenderBuffer = new RenderTarget2D(GFX.GraphicsDevice, ChunkSize * Globals.TileSize, ChunkSize * Globals.TileSize);
|
||||
|
||||
GFX.GraphicsDevice.SetRenderTarget(BackgroundRenderBuffer);
|
||||
GFX.GraphicsDevice.SetRenderTarget(WallRenderBuffer);
|
||||
GFX.Clear(Color.Black * 0f);
|
||||
|
||||
GFX.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
|
||||
@@ -203,23 +184,13 @@ namespace CaveGame.Core
|
||||
{
|
||||
wall = GetWall(x, y);
|
||||
if (wall.ID > 0)
|
||||
{
|
||||
wall.Draw(GFX, x, y, Lights[x, y]);
|
||||
}
|
||||
}
|
||||
}
|
||||
GFX.End();
|
||||
GFX.GraphicsDevice.SetRenderTarget(null);
|
||||
}
|
||||
|
||||
public void Draw(GraphicsEngine GFX)
|
||||
{
|
||||
|
||||
Chunk.RefreshedThisFrame = true;
|
||||
// cock and ball torture
|
||||
UpdateRenderBuffer = false;
|
||||
DrawBackgroundBuffer(GFX);
|
||||
DrawForegroundBuffer(GFX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -19,10 +19,20 @@ namespace CaveGame.Core
|
||||
public bool Thermal { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
public enum NetworkContext
|
||||
{
|
||||
Server,
|
||||
Client
|
||||
}
|
||||
|
||||
public interface IGameWorld
|
||||
{
|
||||
bool IsServer();
|
||||
bool IsClient();
|
||||
|
||||
NetworkContext Context { get; }
|
||||
float TimeOfDay { get; set; }
|
||||
void Explosion(Explosion Blast, bool DamageTiles, bool DamageEntities);
|
||||
List<IEntity> Entities { get; }
|
||||
@@ -32,7 +42,7 @@ namespace CaveGame.Core
|
||||
void GetTile(int x, int y, out Tile t);
|
||||
Wall GetWall(int x, int y);
|
||||
void SetWall(int x, int y, Wall w);
|
||||
void SetTileNetworkUpdated(int x, int y);
|
||||
|
||||
void DoUpdatePropogation(int x, int y);
|
||||
void BreakTile(int x, int y);
|
||||
void SetTileUpdated(int x, int y);
|
||||
@@ -42,10 +52,16 @@ namespace CaveGame.Core
|
||||
void RemoveFurniture(FurnitureTile furn);
|
||||
FurnitureTile GetFurniture(int networkID);
|
||||
void Update(GameTime gt);
|
||||
CastResult TileRaycast(Vector2 origin, Rotation direction, float maxDistance = 1000f, bool detectLiquids = false, bool detectNonSolids = false);
|
||||
}
|
||||
TileRaycastResult TileRaycast(Vector2 origin, Rotation direction, float maxDistance = 100f, bool detectLiquids = false, bool detectNonSolids = false);
|
||||
EntityRaycastResult EntityRaycast(Vector2 origin, Rotation direction, float maxDistance = 100f);
|
||||
}
|
||||
|
||||
public interface IServerWorld : IGameWorld { }
|
||||
public interface IServerWorld : IGameWorld
|
||||
{
|
||||
//void SetTileNetworkUpdated(int x, int y);
|
||||
void RequestTileNetworkUpdate(Point p);
|
||||
void RequestWallNetworkUpdate(Point p);
|
||||
}
|
||||
|
||||
public interface IClientWorld: IGameWorld
|
||||
{
|
||||
@@ -60,97 +76,117 @@ namespace CaveGame.Core
|
||||
}
|
||||
public abstract class World : IGameWorld
|
||||
{
|
||||
public bool IsServer() => (Context == NetworkContext.Server);
|
||||
public bool IsClient() => (Context == NetworkContext.Client);
|
||||
|
||||
|
||||
|
||||
|
||||
public float TimeOfDay { get; set; }
|
||||
public Light3[] AmbientLights = // depends on time of day
|
||||
{
|
||||
new Light3(0,0,0), //0 or 24
|
||||
new Light3(0,0,0), //1
|
||||
new Light3(0,0,0), //2
|
||||
new Light3(0,0,0), //3
|
||||
new Light3(0,0,0), //4
|
||||
new Light3(0,0,0), //5
|
||||
new Light3(0,0,0), //6
|
||||
new Light3(0,0,0), //7
|
||||
new Light3(0,0,0), //8
|
||||
new Light3(0,0,0), //9
|
||||
new Light3(0,0,0), //10
|
||||
new Light3(0,0,0), //11
|
||||
new Light3(0,0,0), //12
|
||||
new Light3(0,0,0), //13
|
||||
new Light3(0,0,0), //14
|
||||
new Light3(0,0,0), //15
|
||||
new Light3(0,0,0), //16
|
||||
new Light3(0,0,0), //17
|
||||
new Light3(0,0,0), //18
|
||||
new Light3(0,0,0), //19
|
||||
new Light3(0,0,0), //20
|
||||
new Light3(0,0,0), //21
|
||||
new Light3(0,0,0), //22
|
||||
new Light3(0,0,0), //23
|
||||
Light3.Moonlight, //0 or 24
|
||||
Light3.Moonlight, //1
|
||||
Light3.Moonlight, //2
|
||||
Light3.Moonlight, //3
|
||||
new Light3(60, 40, 40), //4
|
||||
new Light3(70, 70, 40), //5
|
||||
new Light3(90, 90, 60), //6
|
||||
new Light3(128, 128, 90), //7
|
||||
Light3.Daylight, //8
|
||||
Light3.Daylight, //9
|
||||
Light3.Daylight, //10
|
||||
Light3.Daylight, //11
|
||||
Light3.Daylight, //12
|
||||
Light3.Daylight, //13
|
||||
Light3.Daylight, //14
|
||||
Light3.Daylight, //15
|
||||
Light3.Daylight, //16
|
||||
Light3.Daylight, //17
|
||||
Light3.Moonlight, //18
|
||||
Light3.Moonlight, //19
|
||||
Light3.Moonlight, //20
|
||||
Light3.Moonlight, //21
|
||||
Light3.Moonlight, //22
|
||||
Light3.Moonlight, //23
|
||||
};
|
||||
|
||||
public Color[] SkyColors =
|
||||
{
|
||||
new Color(0, 2, 6), new Color(5, 5, 30), //0 or 24
|
||||
new Color(2, 2, 10), new Color(16, 16, 40), //2
|
||||
new Color(2, 2, 10), new Color(20, 20, 45), //4
|
||||
new Color(8, 9, 50), new Color(85, 85, 40), //6
|
||||
new Color(40, 60, 90), new Color(90, 90, 190), //8
|
||||
new Color(70, 90, 130), new Color(110, 110, 230), //10
|
||||
new Color(70, 80, 170), new Color(170, 170, 255), //12
|
||||
new Color(80, 100, 140), new Color(140, 140, 250), //14
|
||||
new Color(35, 41, 60), new Color(60, 80, 140), //14
|
||||
new Color(50, 32, 50), new Color(170, 100, 70), // 18
|
||||
new Color(25, 25, 55), new Color(92, 52, 23), //20
|
||||
new Color(5, 7, 14), new Color(9, 23, 45), //22
|
||||
};
|
||||
|
||||
#region PhysicsConstants
|
||||
public const float PhysicsStepIncrement = 1 / 100.0f;
|
||||
public const float Gravity = 6.0f;
|
||||
public const float AirResistance = 1.5f;
|
||||
public const float TerminalVelocity = 180.0f;
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
protected List<RepeatingIntervalTask> WorldTimedTasks { get; set; }
|
||||
|
||||
public World()
|
||||
{
|
||||
TileUpdateQueue = new UniqueQueue<Point>();
|
||||
WallUpdateQueue = new UniqueQueue<Point>();
|
||||
Entities = new List<IEntity>();
|
||||
Chunks = new ConcurrentDictionary<ChunkCoordinates, Chunk>();
|
||||
Furniture = new List<Furniture.FurnitureTile>();
|
||||
|
||||
WorldTimedTasks = new List<RepeatingIntervalTask>();
|
||||
WorldTimedTasks.Add(new RepeatingIntervalTask(PhysicsStep, PhysicsStepIncrement, TimeStepProcedure.SubtractIncrement));
|
||||
}
|
||||
|
||||
|
||||
protected UniqueQueue<Point> TileUpdateQueue { get; set; }
|
||||
protected UniqueQueue<Point> WallUpdateQueue { get; set; }
|
||||
|
||||
public void RequestTileUpdate(Point position)=>TileUpdateQueue.Enqueue(position);
|
||||
public void RequestWallUpdate(Point position) => WallUpdateQueue.Enqueue(position);
|
||||
|
||||
public ConcurrentDictionary<ChunkCoordinates, Chunk> Chunks { get; set; }
|
||||
public List<IEntity> Entities { get; protected set; }
|
||||
|
||||
public virtual List<Furniture.FurnitureTile> Furniture { get; protected set; }
|
||||
|
||||
public GameSessionType SessionType { get; set; }
|
||||
public GameSessionType SessionType { get; protected set; }
|
||||
public NetworkContext Context { get; protected set; }
|
||||
|
||||
public void SetTileNetworkUpdated(int x, int y)
|
||||
{
|
||||
int chunkX = (int)Math.Floor((double)x / Globals.ChunkSize);
|
||||
int chunkY = (int)Math.Floor((double)y / Globals.ChunkSize);
|
||||
|
||||
var tileX = x.Mod(Globals.ChunkSize);
|
||||
var tileY = y.Mod(Globals.ChunkSize);
|
||||
|
||||
var coords = new ChunkCoordinates(chunkX, chunkY);
|
||||
if (Chunks.ContainsKey(coords))
|
||||
{
|
||||
var chunk = Chunks[coords];
|
||||
chunk.NetworkUpdated[tileX, tileY] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SetTileNoLight(int x, int y, Tile t)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
|
||||
public virtual void BreakTile(int x, int y)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SetTile(Point p, Tile t)=>SetTile(p.X, p.Y, t);
|
||||
public Tile GetTile (Point p) => GetTile(p.X, p.Y);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public Tile GetTile(int x, int y)
|
||||
{
|
||||
Coordinates6D coordinates = Coordinates6D.FromWorld(x, y);
|
||||
|
||||
var cc = new ChunkCoordinates(coordinates.ChunkX, coordinates.ChunkY);
|
||||
|
||||
if (Chunks.ContainsKey(cc))
|
||||
return Chunks[cc].GetTile(coordinates.TileX, coordinates.TileY);
|
||||
return new Game.Tiles.Void();
|
||||
}
|
||||
public Tile GetTile(Point coords) => GetTile(coords.X, coords.Y);
|
||||
public void GetTile(int x, int y, out Tile t)
|
||||
{
|
||||
Coordinates6D coordinates = Coordinates6D.FromWorld(x, y);
|
||||
|
||||
var cc = new ChunkCoordinates(coordinates.ChunkX, coordinates.ChunkY);
|
||||
t = new Game.Tiles.Void();
|
||||
if (Chunks.ContainsKey(cc))
|
||||
t = Chunks[cc].GetTile(coordinates.TileX, coordinates.TileY);
|
||||
|
||||
}
|
||||
public virtual void SetTile(int x, int y, Tile t)
|
||||
{
|
||||
|
||||
@@ -169,6 +205,46 @@ namespace CaveGame.Core
|
||||
}
|
||||
DoUpdatePropogation(x, y);
|
||||
}
|
||||
public void SetTile(Point p, Tile t) => SetTile(p.X, p.Y, t);
|
||||
|
||||
public Wall GetWall(int x, int y)
|
||||
{
|
||||
Coordinates6D coordinates = Coordinates6D.FromWorld(x, y);
|
||||
|
||||
var cc = new ChunkCoordinates(coordinates.ChunkX, coordinates.ChunkY);
|
||||
|
||||
if (Chunks.ContainsKey(cc))
|
||||
return Chunks[cc].GetWall(coordinates.TileX, coordinates.TileY);
|
||||
return new Game.Walls.Void();
|
||||
}
|
||||
public Wall GetWall(Point coords) => GetWall(coords.X, coords.Y);
|
||||
public void GetWall(int x, int y, out Wall w)
|
||||
{
|
||||
Coordinates6D coordinates = Coordinates6D.FromWorld(x, y);
|
||||
|
||||
var cc = new ChunkCoordinates(coordinates.ChunkX, coordinates.ChunkY);
|
||||
w = new Game.Walls.Void();
|
||||
if (Chunks.ContainsKey(cc))
|
||||
w = Chunks[cc].GetWall(coordinates.TileX, coordinates.TileY);
|
||||
|
||||
}
|
||||
public virtual void SetWall(int x, int y, Wall w)
|
||||
{
|
||||
Coordinates6D coordinates = Coordinates6D.FromWorld(x, y);
|
||||
|
||||
var cc = new ChunkCoordinates(coordinates.ChunkX, coordinates.ChunkY);
|
||||
|
||||
if (Chunks.ContainsKey(cc))
|
||||
Chunks[cc].SetWall(coordinates.TileX, coordinates.TileY, w);
|
||||
}
|
||||
public void SetWall(Point p, Wall w) => SetWall(p.X, p.Y, w);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void SetTileUpdated(int x, int y)
|
||||
{
|
||||
int chunkX = (int)Math.Floor((double)x / Globals.ChunkSize);
|
||||
@@ -182,66 +258,17 @@ namespace CaveGame.Core
|
||||
if (Chunks.ContainsKey(coords))
|
||||
{
|
||||
var chunk = Chunks[coords];
|
||||
chunk.SetTileUpdated(tileX, tileY);
|
||||
//chunk.SetTileUpdated(tileX, tileY);
|
||||
}
|
||||
}
|
||||
|
||||
public void DoUpdatePropogation(int x, int y)
|
||||
{
|
||||
SetTileUpdated(x, y);
|
||||
SetTileUpdated(x, y + 1);
|
||||
SetTileUpdated(x, y - 1);
|
||||
SetTileUpdated(x + 1, y);
|
||||
SetTileUpdated(x - 1, y);
|
||||
}
|
||||
public Tile GetTile(int x, int y)
|
||||
{
|
||||
Coordinates6D coordinates = Coordinates6D.FromWorld(x, y);
|
||||
|
||||
var cc = new ChunkCoordinates(coordinates.ChunkX, coordinates.ChunkY);
|
||||
|
||||
if (Chunks.ContainsKey(cc))
|
||||
return Chunks[cc].GetTile(coordinates.TileX, coordinates.TileY);
|
||||
return new Game.Tiles.Void();
|
||||
}
|
||||
public void GetTile(int x, int y, out Tile t)
|
||||
{
|
||||
Coordinates6D coordinates = Coordinates6D.FromWorld(x, y);
|
||||
|
||||
var cc = new ChunkCoordinates(coordinates.ChunkX, coordinates.ChunkY);
|
||||
t = new Game.Tiles.Void();
|
||||
if (Chunks.ContainsKey(cc))
|
||||
t = Chunks[cc].GetTile(coordinates.TileX, coordinates.TileY);
|
||||
|
||||
}
|
||||
public Wall GetWall(int x, int y)
|
||||
{
|
||||
Coordinates6D coordinates = Coordinates6D.FromWorld(x, y);
|
||||
|
||||
var cc = new ChunkCoordinates(coordinates.ChunkX, coordinates.ChunkY);
|
||||
|
||||
if (Chunks.ContainsKey(cc))
|
||||
return Chunks[cc].GetWall(coordinates.TileX, coordinates.TileY);
|
||||
return new Game.Walls.Void();
|
||||
}
|
||||
public void GetWall(int x, int y, out Wall w)
|
||||
{
|
||||
Coordinates6D coordinates = Coordinates6D.FromWorld(x, y);
|
||||
|
||||
var cc = new ChunkCoordinates(coordinates.ChunkX, coordinates.ChunkY);
|
||||
w = new Game.Walls.Void();
|
||||
if (Chunks.ContainsKey(cc))
|
||||
w = Chunks[cc].GetWall(coordinates.TileX, coordinates.TileY);
|
||||
|
||||
}
|
||||
|
||||
public virtual void SetWall(int x, int y, Wall w)
|
||||
{
|
||||
Coordinates6D coordinates = Coordinates6D.FromWorld(x, y);
|
||||
|
||||
var cc = new ChunkCoordinates(coordinates.ChunkX, coordinates.ChunkY);
|
||||
|
||||
if (Chunks.ContainsKey(cc))
|
||||
Chunks[cc].SetWall(coordinates.TileX, coordinates.TileY, w);
|
||||
RequestTileUpdate(new Point(x, y));
|
||||
RequestTileUpdate(new Point(x, y + 1));
|
||||
RequestTileUpdate(new Point(x, y - 1));
|
||||
RequestTileUpdate(new Point(x + 1, y));
|
||||
RequestTileUpdate(new Point(x - 1, y));
|
||||
}
|
||||
|
||||
public virtual void OnCollectDeadEntity(IEntity ent)
|
||||
@@ -294,13 +321,14 @@ namespace CaveGame.Core
|
||||
|
||||
TimeOfDay += (float)gt.ElapsedGameTime.TotalSeconds/30.0f;
|
||||
|
||||
//Profiler.Start("EntityClear");
|
||||
|
||||
foreach (var ent in Entities.ToArray())
|
||||
if (ent.Dead)
|
||||
OnCollectDeadEntity(ent);
|
||||
|
||||
//Entities.RemoveAll(e => e.Dead);
|
||||
|
||||
physicsTask.Update(gt);
|
||||
foreach (var task in WorldTimedTasks)
|
||||
task.Update(gt);
|
||||
}
|
||||
|
||||
protected virtual void PhysicsStep() { }
|
||||
@@ -443,82 +471,62 @@ namespace CaveGame.Core
|
||||
return false;
|
||||
}
|
||||
|
||||
public CastResult TileRaycast(Vector2 origin, Rotation direction, float maxDistance = 120, bool detectLiquids = false, bool detectNonSolids = false)
|
||||
{
|
||||
const float ray_accuracy = 0.15f;
|
||||
|
||||
Vector2 last_pt = origin;
|
||||
const float ray_accuracy = 0.15f;
|
||||
|
||||
|
||||
public TileRaycastResult TileRaycast(Vector2 origin, Rotation direction, float maxDistance = 120, bool detectLiquids = false, bool detectNonSolids = false)
|
||||
{
|
||||
for (float i = 0; i < maxDistance; i += ray_accuracy)
|
||||
{
|
||||
Vector2 current_pt = origin + (direction.ToUnitVector() * i);
|
||||
|
||||
Point tile_coords = new Point(
|
||||
(int) Math.Floor(current_pt.X / 8),
|
||||
(int) Math.Floor(current_pt.Y / 8)
|
||||
(int)Math.Floor(current_pt.X / 8),
|
||||
(int)Math.Floor(current_pt.Y / 8)
|
||||
);
|
||||
|
||||
Tile tileAt = GetTile(tile_coords.X, tile_coords.Y);
|
||||
Tile tileAt = GetTile(tile_coords.X, tile_coords.Y);
|
||||
|
||||
if (tileAt.ID > 0 && !(tileAt is INonSolid))
|
||||
{
|
||||
Vector2 tile_corner = (tile_coords.ToVector2() * 8);
|
||||
Vector2 tile_size = new Vector2(8, 8);
|
||||
if (tileAt.ID == 0 || (tileAt is INonSolid))
|
||||
continue;
|
||||
|
||||
|
||||
LineSegment ray_travel_segment = new LineSegment(origin, current_pt);
|
||||
Rectangle tile_rect = new Rectangle(tile_corner.ToPoint(), tile_size.ToPoint());
|
||||
Vector2 tile_corner = (tile_coords.ToVector2() * 8);
|
||||
Vector2 tile_size = new Vector2(8, 8);
|
||||
LineSegment ray_travel_segment = new LineSegment(origin, current_pt);
|
||||
Rectangle tile_rect = new Rectangle(tile_corner.ToPoint(), tile_size.ToPoint());
|
||||
|
||||
if (CollisionSolver.Intersects(ray_travel_segment, tile_rect, out Vector2 intersection, out Face face))
|
||||
{
|
||||
Vector2 normal = Vector2.Zero;
|
||||
if (!CollisionSolver.Intersects(ray_travel_segment, tile_rect, out Vector2 intersection, out Face face))
|
||||
continue;
|
||||
|
||||
if (face == Face.Top)
|
||||
normal = new Vector2(0, -1);
|
||||
if (face == Face.Bottom)
|
||||
normal = new Vector2(0, 1);
|
||||
if (face == Face.Left)
|
||||
normal = new Vector2(-1, 0);
|
||||
if (face == Face.Right)
|
||||
normal = new Vector2(1, 0);
|
||||
|
||||
return new CastResult
|
||||
{
|
||||
Hit = true,
|
||||
Intersection = intersection,
|
||||
SurfaceNormal = normal,
|
||||
TileCoordinates = tile_coords,
|
||||
Face = face
|
||||
};
|
||||
}
|
||||
Vector2 normal = face.ToSurfaceNormal();
|
||||
|
||||
/*if (CollisionSolver.CheckAABB(ray_check_center, new Vector2(4, 4), tile_center, tile_half))
|
||||
{
|
||||
var separation = CollisionSolver.GetSeparationAABB(ray_check_center, new Vector2(4, 4), tile_center, tile_half);
|
||||
//if (separation.X != 0 && separation.Y != 0)
|
||||
//{
|
||||
var normal = CollisionSolver.GetNormalAABB(separation, direction.ToUnitVector());
|
||||
return new CastResult {
|
||||
Hit = true,
|
||||
SurfaceNormal = normal,
|
||||
Intersection = current_pt-separation,
|
||||
};
|
||||
// }
|
||||
}*/
|
||||
}
|
||||
return new TileRaycastResult { Hit = true, Intersection = intersection, SurfaceNormal = normal, TileCoordinates = tile_coords, Face = face };
|
||||
|
||||
}
|
||||
return new CastResult { Hit = false };
|
||||
return new TileRaycastResult { Hit = false };
|
||||
}
|
||||
|
||||
protected DelayedTask physicsTask;
|
||||
|
||||
public World()
|
||||
{
|
||||
physicsTask = new DelayedTask(PhysicsStep, PhysicsStepIncrement, TimeStepProcedure.SubtractIncrement);
|
||||
|
||||
Entities = new List<IEntity>();
|
||||
Chunks = new ConcurrentDictionary<ChunkCoordinates, Chunk>();
|
||||
Furniture = new List<Furniture.FurnitureTile>();
|
||||
public EntityRaycastResult EntityRaycast(Vector2 origin, Rotation direction, float maxDistance = 100)
|
||||
{
|
||||
for (float i = 0; i < maxDistance; i += ray_accuracy)
|
||||
{
|
||||
Vector2 intersection;
|
||||
Face side;
|
||||
foreach (IEntity candidate in Entities)
|
||||
{
|
||||
Vector2 current_pt = origin + (direction.ToUnitVector() * i);
|
||||
if (!CollisionSolver.Intersects(new LineSegment(origin, current_pt), candidate.GetCollisionRect(), out intersection, out side))
|
||||
continue;
|
||||
return new EntityRaycastResult{Hit = true,Face = side, Intersection = intersection,Target = candidate,SurfaceNormal = side.ToSurfaceNormal()};
|
||||
}
|
||||
}
|
||||
return new EntityRaycastResult { Hit = false };
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -4,11 +4,21 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// A structure representing lighting value in-game
|
||||
/// Roughly equatable to a color struct, but with specialized
|
||||
/// methods for dealing with light calculation
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct Light3 : IEquatable<Light3>
|
||||
{
|
||||
public static Light3 Dark = new Light3(0, 0, 0);
|
||||
public static Light3 Ambience = new Light3(16, 16, 16);
|
||||
public static Light3 Moonlight = new Light3(128, 128, 128);
|
||||
public static Light3 Dawn = new Light3(96, 96, 40);
|
||||
public static Light3 Ambience = new Light3(255, 255, 255);
|
||||
public static Light3 Daylight = new Light3(255, 255, 255);
|
||||
public static Light3 Dusk = new Light3(96, 60, 40);
|
||||
|
||||
[FieldOffset(0)] public byte Red;
|
||||
[FieldOffset(1)] public byte Blue;
|
||||
@@ -21,21 +31,36 @@ namespace CaveGame.Core
|
||||
Blue = b;
|
||||
}
|
||||
|
||||
public bool Equals(Light3 other)
|
||||
{
|
||||
return (other.Red == Red && other.Blue == Blue && other.Green == Green);
|
||||
}
|
||||
private static double Squirt = Math.Sqrt(15.0);
|
||||
public Light3(float r, float g, float b)
|
||||
{
|
||||
Red = (byte)(r * 255);
|
||||
Green = (byte)(g * 255);
|
||||
Blue = (byte)(b * 255);
|
||||
}
|
||||
|
||||
public bool Equals(Light3 other)=>(other.Red == Red && other.Blue == Blue && other.Green == Green);
|
||||
|
||||
|
||||
public Color ToColor() => new Color(Red, Green, Blue);
|
||||
|
||||
|
||||
public Color MultiplyAgainst(Color col)
|
||||
{
|
||||
return new Color(
|
||||
(col.R / 255.0f) * (float)(Math.Sqrt(Red / 30.0f)),
|
||||
(col.G / 255.0f) * (float)(Math.Sqrt(Green / 30.0f)),
|
||||
(col.B / 255.0f) * (float)(Math.Sqrt(Blue / 30.0f)),
|
||||
(col.R / 255.0f) * (Red / 255.0f),
|
||||
(col.G / 255.0f) * (Green / 255.0f),
|
||||
(col.B / 255.0f) * (Blue / 255.0f),
|
||||
col.A
|
||||
);
|
||||
}
|
||||
|
||||
public static Color operator *(Light3 l, Color c) => l.MultiplyAgainst(c);
|
||||
public static Color operator *(Color c, Light3 l) => l.MultiplyAgainst(c);
|
||||
|
||||
public static Light3 operator +(Light3 a, Light3 b) => new Light3(a.Red + b.Red, a.Green + b.Green, a.Blue + b.Blue);
|
||||
|
||||
public static Light3 operator -(Light3 a, Light3 b) => new Light3(a.Red - b.Red, a.Green -b.Green, a.Blue - b.Blue);
|
||||
|
||||
public Light3 Absorb(byte opacity)
|
||||
{
|
||||
byte red = (byte)Math.Max(0, Red - opacity);
|
||||
|
@@ -6,8 +6,7 @@ using System.Xml;
|
||||
|
||||
namespace CaveGame.Core
|
||||
{
|
||||
|
||||
public class WorldMetadata
|
||||
public class WorldMetadata
|
||||
{
|
||||
public int Seed { get; set; }
|
||||
public string Name { get; set; }
|
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
@@ -6,6 +7,21 @@ namespace DataManagement
|
||||
{
|
||||
public static class ContainerExtensions
|
||||
{
|
||||
public static IEnumerable<T> DequeueAll<T>(this Queue<T> queue, int chunkSize)
|
||||
{
|
||||
for (int i = 0; i < chunkSize && queue.Count > 0; i++)
|
||||
{
|
||||
yield return queue.Dequeue();
|
||||
}
|
||||
}
|
||||
public static IEnumerable<T> DequeueAll<T>(this Queue<T> queue)
|
||||
{
|
||||
int max = queue.Count;
|
||||
for (int i = 0; i < max && queue.Count > 0; i++)
|
||||
{
|
||||
yield return queue.Dequeue();
|
||||
}
|
||||
}
|
||||
public static List<T> ToList<T>(this T[,] array)
|
||||
{
|
||||
int width = array.GetLength(0);
|
||||
|
@@ -1,9 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace DataManagement
|
||||
{
|
||||
public interface IStatistic
|
||||
{
|
||||
decimal Comparator { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public static class LINQExtensions
|
||||
{
|
||||
// LINQ Extensions, borrowed from Jonathan Skeet
|
||||
@@ -16,5 +23,13 @@ namespace DataManagement
|
||||
action(element);
|
||||
}
|
||||
}
|
||||
|
||||
public static TStat GetMean<TStat>(this TStat[] collection) where TStat : IStatistic
|
||||
{
|
||||
//return collection. Average();
|
||||
return default;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -19,5 +19,6 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Plugin.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ServerConfig.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)ServerWorld.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)World\ChunkManager.cs" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@@ -25,6 +25,7 @@ using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using CaveGame.Core.Inventory;
|
||||
using CaveGame.Core.Network.Packets;
|
||||
using CaveGame.Core.Generic;
|
||||
|
||||
namespace CaveGame.Server
|
||||
{
|
||||
@@ -32,12 +33,9 @@ namespace CaveGame.Server
|
||||
{
|
||||
DateTime Time { get; }
|
||||
IMessageOutlet Output { get; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public class PlayerChatMessageEventArgs : LuaEventArgs
|
||||
{
|
||||
public Player Player { get; private set; }
|
||||
@@ -72,10 +70,13 @@ namespace CaveGame.Server
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class GameServer : IGameServer
|
||||
{
|
||||
public delegate void ThrowDelegate(Rotation rotation, Player player);
|
||||
public delegate void NetworkListener(NetworkMessage message, User user);
|
||||
|
||||
|
||||
public bool Running { get; set; }
|
||||
|
||||
public DateTime Time => DateTime.Now;
|
||||
@@ -86,6 +87,8 @@ namespace CaveGame.Server
|
||||
public void Message(User user, string msg, Color color) => SendTo(new ServerChatMessagePacket(msg, color), user);
|
||||
|
||||
|
||||
public Entity GetEntity(int networkID) => (Entity)World.FindEntityOfID(networkID);
|
||||
|
||||
public IMessageOutlet Output
|
||||
{
|
||||
get { return server.Output; }
|
||||
@@ -94,8 +97,6 @@ namespace CaveGame.Server
|
||||
|
||||
private NetworkServer server;
|
||||
|
||||
|
||||
|
||||
|
||||
public EntityManager EntityManager { get; private set; }
|
||||
public int TickRate { get; private set; }
|
||||
@@ -107,7 +108,6 @@ namespace CaveGame.Server
|
||||
public int MaxPlayers { get; private set; }
|
||||
|
||||
|
||||
float ticker;
|
||||
|
||||
IEntityManager IGameServer.EntityManager => EntityManager;
|
||||
IServerWorld IGameServer.World => World;
|
||||
@@ -117,8 +117,8 @@ namespace CaveGame.Server
|
||||
entity.EntityNetworkID = EntityManager.GetNextEntityNetworkID();
|
||||
World.SpawnEntity(entity);
|
||||
}
|
||||
|
||||
|
||||
RepeatingIntervalTask[] ServerTasks;
|
||||
public GameServer(ServerConfig config, WorldMetadata worldmdt) {
|
||||
InitNetworkEvents();
|
||||
|
||||
@@ -127,16 +127,22 @@ namespace CaveGame.Server
|
||||
MaxPlayers = config.MaxPlayers;
|
||||
|
||||
TickRate = config.TickRate;
|
||||
ticker = 0;
|
||||
|
||||
server = new NetworkServer(config.Port);
|
||||
ConnectedUsers = new List<User>();
|
||||
World = new ServerWorld(worldmdt);
|
||||
World.Server = this;
|
||||
|
||||
EntityManager = new EntityManager();
|
||||
|
||||
ServerTasks = new RepeatingIntervalTask[]
|
||||
{
|
||||
new (ReplicateNetworkEntitiesPhysicalStates, 1.0f/20.0f),
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
public delegate void NetworkListener(NetworkMessage message, User user);
|
||||
|
||||
private Dictionary<PacketType, NetworkListener> NetworkEvents;
|
||||
private void InitNetworkEvents() => NetworkEvents = new Dictionary<PacketType, NetworkListener>()
|
||||
@@ -160,6 +166,8 @@ namespace CaveGame.Server
|
||||
|
||||
|
||||
#region NetworkListenerMethods
|
||||
|
||||
protected virtual void OnPing(NetworkMessage msg, User user)=> SendTo(msg.Packet, user); // response
|
||||
private void OnClientDamageWall(NetworkMessage message, User user)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
@@ -252,7 +260,7 @@ namespace CaveGame.Server
|
||||
private void OnPlayerPosition(NetworkMessage msg, User user) // player tells us their state
|
||||
{
|
||||
// TODO: make server more authoritative, prevent cheating
|
||||
EntityPositionPacket packet = new EntityPositionPacket(msg.Packet.GetBytes());
|
||||
EntityPhysicsStatePacket packet = new EntityPhysicsStatePacket(msg.Packet.GetBytes());
|
||||
|
||||
if (World.FindEntityOfID(packet.EntityID, out Player player))
|
||||
{
|
||||
@@ -289,7 +297,7 @@ namespace CaveGame.Server
|
||||
t.TileState = packet.TileState;
|
||||
t.Damage = packet.Damage;
|
||||
World.SetTile(packet.WorldX, packet.WorldY, t);
|
||||
//SendToAll(packet);
|
||||
SendToAll(packet);
|
||||
}
|
||||
private void OnClientRequestChunk(NetworkMessage msg, User user)
|
||||
{
|
||||
@@ -314,30 +322,31 @@ namespace CaveGame.Server
|
||||
|
||||
}
|
||||
|
||||
int bombcount = 0;
|
||||
float bombVelocity = 3.5f;
|
||||
float arrowVelocity = 3.0f;
|
||||
|
||||
private TEntity SpawnThrowable<TEntity>(Rotation dir, Vector2 startpos, float vel, NetEntityType entityType) where TEntity: IEntity, IPhysicsEntity, new()
|
||||
{
|
||||
TEntity entity = new TEntity
|
||||
{ Velocity = dir.ToUnitVector() * vel, Position = startpos, NextPosition = startpos};
|
||||
SpawnEntity(entity);
|
||||
SendToAll(new SpawnEntityGenericPacket(entity.EntityNetworkID, entityType));
|
||||
return entity;
|
||||
}
|
||||
|
||||
private void OnThrowBomb(Rotation dir, Vector2 pos, float force) => SpawnThrowable<Bomb>(dir, pos, force, NetEntityType.Bomb);
|
||||
private void OnShootArrow(Rotation dir, Vector2 pos, float force) => SpawnThrowable<Arrow>(dir, pos, force, NetEntityType.Arrow);
|
||||
|
||||
private void OnClientThrowItem(NetworkMessage msg, User user)
|
||||
{
|
||||
PlayerThrowItemPacket packet = new PlayerThrowItemPacket(msg.Packet.GetBytes());
|
||||
|
||||
Player p = user.PlayerEntity;
|
||||
|
||||
if (packet.Item == ThrownItem.Bomb)
|
||||
{
|
||||
Core.Game.Entities.Bomb bomb = new Core.Game.Entities.Bomb
|
||||
{
|
||||
Velocity = packet.ThrownDirection.ToUnitVector() * bombVelocity,
|
||||
Position = p.Position,
|
||||
NextPosition = p.NextPosition,
|
||||
};
|
||||
|
||||
SpawnEntity(bomb);
|
||||
SendToAll(new SpawnEntityGenericPacket(bomb.EntityNetworkID, NetEntityType.Bomb));
|
||||
bombcount++;
|
||||
}
|
||||
OnThrowBomb(packet.ThrownDirection, p.Position, bombVelocity);
|
||||
if (packet.Item == ThrownItem.Arrow)
|
||||
OnShootArrow(packet.ThrownDirection, p.Position, arrowVelocity);
|
||||
}
|
||||
|
||||
int furniturecount = 0;
|
||||
private void OnClientPlaceFurniture(NetworkMessage msg, User user)
|
||||
{
|
||||
PlaceFurniturePacket packet = new PlaceFurniturePacket(msg.Packet.GetBytes());
|
||||
@@ -352,7 +361,6 @@ namespace CaveGame.Server
|
||||
|
||||
packet.NetworkID = f.FurnitureNetworkID;
|
||||
SendToAll(packet);
|
||||
furniturecount++;
|
||||
}
|
||||
private void OnClientDamageFurniture(NetworkMessage msg, User user)
|
||||
{
|
||||
@@ -396,14 +404,12 @@ namespace CaveGame.Server
|
||||
var tile = World.GetTile(packet.Position.X, packet.Position.Y);
|
||||
|
||||
tile.Damage += (byte)packet.Damage;
|
||||
Debug.WriteLine("tile damage:" + tile.Damage);
|
||||
SendToAllExcept(packet, user);
|
||||
SendToAll(packet);
|
||||
if (tile.Damage >= tile.Hardness)
|
||||
{
|
||||
Debug.WriteLine("Tile Break");
|
||||
tile.Drop(this, World, packet.Position);
|
||||
World.SetTile(packet.Position.X, packet.Position.Y, new Air());
|
||||
//SendToAll(new PlaceTilePacket(0, 0, 0, packet.Position.X, packet.Position.Y));
|
||||
SendToAll(new PlaceTilePacket(0, 0, 0, packet.Position.X, packet.Position.Y));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -476,10 +482,8 @@ namespace CaveGame.Server
|
||||
|
||||
if (msg.Packet.Type == PacketType.cHandshake)
|
||||
HandshakeResponse(msg);
|
||||
|
||||
if (msg.Packet.Type == PacketType.cRequestLogin)
|
||||
OnClientRequestLogin(msg);
|
||||
|
||||
if (msg.Packet.Type == PacketType.cConfirmLogin)
|
||||
OnClientLoginSuccess(msg);
|
||||
|
||||
@@ -493,7 +497,7 @@ namespace CaveGame.Server
|
||||
foreach (var ev in NetworkEvents)
|
||||
if (ev.Key == msg.Packet.Type)
|
||||
ev.Value.Invoke(msg, user);
|
||||
|
||||
#region old shit
|
||||
/*if (msg.Packet.Type == PacketType.ClientQuit)
|
||||
OnClientLogout(msg, user);
|
||||
if (msg.Packet.Type == PacketType.ServerEntityPhysicsState)
|
||||
@@ -522,8 +526,9 @@ namespace CaveGame.Server
|
||||
OnPlayerDamageTile(msg, user);
|
||||
if (msg.Packet.Type == PacketType.cAdminCommand)
|
||||
OnAdminCommandInput(msg, user);*/
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float tileticker = 0;
|
||||
|
||||
@@ -536,98 +541,57 @@ namespace CaveGame.Server
|
||||
ConnectedUsers.Remove(user);
|
||||
}
|
||||
|
||||
protected void DispatchUserMessages(User user)
|
||||
{
|
||||
if (user.DispatcherHasMessage())
|
||||
{
|
||||
Packet p = user.PopDispatcherQueue();
|
||||
SendTo(p, user);
|
||||
}
|
||||
}
|
||||
|
||||
// generic entity physics replication
|
||||
protected virtual void ReplicateNetworkEntitiesPhysicalStates()
|
||||
{
|
||||
foreach (var entity in World.Entities)
|
||||
{
|
||||
if (entity.Dead)
|
||||
continue;
|
||||
|
||||
SendToAll(new EntityPhysicsStatePacket(entity));
|
||||
|
||||
|
||||
if (entity is Wurmhole wurmhole && !entity.Dead)
|
||||
{
|
||||
// TODO: remove dipshit hack;
|
||||
if (wurmhole.Provoked && wurmhole.TriggerNetworkHandled == false)
|
||||
{
|
||||
wurmhole.TriggerNetworkHandled = true;
|
||||
SendToAll(new ProvokeEntityGenericPacket(wurmhole.EntityNetworkID));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void HandleUserConnectionStates()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual void Update(GameTime gt)
|
||||
{
|
||||
|
||||
float delta = (float)gt.ElapsedGameTime.TotalSeconds;
|
||||
|
||||
|
||||
ConnectedUsers.Where(u => u.Kicked == true).ForEach(InternalUserKick);
|
||||
ConnectedUsers.ForEach(u => DispatchUserMessages(u));
|
||||
|
||||
foreach(var user in ConnectedUsers.ToArray())
|
||||
{
|
||||
|
||||
user.KeepAlive += delta;
|
||||
|
||||
if (user.KeepAlive > 10.0f)
|
||||
{
|
||||
user.Kick("Network Timeout");
|
||||
}
|
||||
}
|
||||
|
||||
ticker += delta;
|
||||
|
||||
if (ticker > 1/ 20.0f)
|
||||
{
|
||||
ticker = 0;
|
||||
foreach(var entity in World.Entities)
|
||||
{
|
||||
|
||||
if (entity.Dead)
|
||||
continue;
|
||||
|
||||
var packet = new EntityPositionPacket(entity);
|
||||
SendToAll(packet);
|
||||
|
||||
if (entity is Wurmhole wurmhole && !entity.Dead)
|
||||
{
|
||||
// TODO: remove dipshit hack;
|
||||
if (wurmhole.Provoked)
|
||||
{
|
||||
if (wurmhole.TriggerNetworkHandled == false)
|
||||
{
|
||||
wurmhole.TriggerNetworkHandled = true;
|
||||
SendToAll(new ProvokeEntityGenericPacket(wurmhole.EntityNetworkID));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReadIncomingPackets();
|
||||
HandleUserConnectionStates();
|
||||
|
||||
ServerTasks.ForEach(t => t.Update(gt));
|
||||
|
||||
ConnectedUsers.ForEach(u => u.SendDispatchMessages(this));
|
||||
ConnectedUsers.ForEach(u => u.KeepAlive += gt.GetDelta());
|
||||
ConnectedUsers.Where(u => u.KeepAlive > 10.0f).ForEach(u => u.Kick("Network Timeout"));
|
||||
ConnectedUsers.ToArray().Where(u => u.Kicked == true).ForEach(InternalUserKick); // InvalidOperationException
|
||||
|
||||
World.Update(gt);
|
||||
tileticker += delta;
|
||||
|
||||
if (tileticker > (1/5.0f))
|
||||
{
|
||||
tileticker = 0;
|
||||
foreach (var kvp in World.Chunks)
|
||||
{
|
||||
Chunk c = kvp.Value;
|
||||
|
||||
for (int x = 0; x < Chunk.ChunkSize; x++)
|
||||
{
|
||||
for (int y = 0; y < Chunk.ChunkSize; y++)
|
||||
{
|
||||
if (c.NetworkUpdated[x, y] == true)
|
||||
{
|
||||
c.NetworkUpdated[x, y] = false;
|
||||
var t = c.Tiles[x, y];
|
||||
var w = c.Walls[x, y];
|
||||
SendToAll(new PlaceTilePacket(t.ID, t.TileState, t.Damage, (c.Coordinates.X * Chunk.ChunkSize) + x, (c.Coordinates.Y * Chunk.ChunkSize) + y));
|
||||
SendToAll(new PlaceWallPacket(w.ID, 0, w.Damage, (c.Coordinates.X * Chunk.ChunkSize) + x, (c.Coordinates.Y * Chunk.ChunkSize) + y));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
server.Update(gt);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
server.Start();
|
||||
Running = true;
|
||||
|
||||
Task.Run(GameserverThreadLoop);
|
||||
}
|
||||
public virtual void Shutdown()
|
||||
{
|
||||
@@ -664,10 +628,9 @@ namespace CaveGame.Server
|
||||
Output?.Out(String.Format("[{0} {1}] {2}", "server", DateTime.Now.ToString("HH:mm:ss.ff"), text));
|
||||
}
|
||||
|
||||
// Should be run on it's own thread
|
||||
public void Run()
|
||||
public void GameserverThreadLoop()
|
||||
{
|
||||
server.Run();
|
||||
|
||||
|
||||
Stopwatch timing = new Stopwatch();
|
||||
|
||||
@@ -684,9 +647,6 @@ namespace CaveGame.Server
|
||||
|
||||
Thread.Sleep(TickRate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -16,19 +16,9 @@ using System.Threading.Tasks;
|
||||
namespace CaveGame.Server
|
||||
{
|
||||
|
||||
public class NetworkServer
|
||||
public class NetworkServer : SharedNetworkSubsystem
|
||||
{
|
||||
|
||||
public readonly int Port;
|
||||
|
||||
public int ProtocolVersion;
|
||||
|
||||
|
||||
public IMessageOutlet Output { get; set; }
|
||||
|
||||
private UdpClient udpClient;
|
||||
|
||||
|
||||
private ConcurrentQueue<NetworkMessage> incomingMessages;
|
||||
private ConcurrentQueue<Tuple<Packet, IPEndPoint>> outgoingMessages;
|
||||
|
||||
@@ -37,7 +27,8 @@ namespace CaveGame.Server
|
||||
public NetworkServer(int port)
|
||||
{
|
||||
|
||||
udpClient = new UdpClient(port, AddressFamily.InterNetwork);
|
||||
UdpSocket = new UdpClient(port, AddressFamily.InterNetwork);
|
||||
IOControlFixICMPBullshit();
|
||||
|
||||
Port = port;
|
||||
incomingMessages = new ConcurrentQueue<NetworkMessage>();
|
||||
@@ -45,16 +36,6 @@ namespace CaveGame.Server
|
||||
|
||||
}
|
||||
|
||||
private string DumpHex(byte[] data)
|
||||
{
|
||||
StringBuilder bob = new StringBuilder();
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
bob.Append(String.Format("{0:X2} ", data[i]));
|
||||
}
|
||||
return bob.ToString();
|
||||
}
|
||||
|
||||
private void NetworkThread()
|
||||
{
|
||||
if (!listening.Value)
|
||||
@@ -63,7 +44,7 @@ namespace CaveGame.Server
|
||||
while (listening.Value)
|
||||
{
|
||||
|
||||
bool canRead = udpClient.Available > 0;
|
||||
bool canRead = UdpSocket.Available > 0;
|
||||
|
||||
// Read in message if we have any data
|
||||
if (canRead)
|
||||
@@ -72,27 +53,22 @@ namespace CaveGame.Server
|
||||
IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
|
||||
try
|
||||
{
|
||||
byte[] data = udpClient.Receive(ref ep);
|
||||
byte[] data = UdpSocket.Receive(ref ep);
|
||||
|
||||
NetworkMessage nm = new NetworkMessage();
|
||||
nm.Sender = ep;
|
||||
nm.Packet = new Packet(data);
|
||||
nm.ReceiveTime = DateTime.Now;
|
||||
|
||||
|
||||
#if PACKETDEBUG
|
||||
Output?.Out(String.Format("PK_IN: [{0}] at [{1} {2}] from [{3}]", nm.Packet.Type.ToString(), nm.ReceiveTime.ToLongTimeString(), nm.ReceiveTime.Millisecond, nm.Sender.ToString()));
|
||||
Output?.Out(String.Format("DATUM: [{0}]", DumpHex(nm.Packet.Payload)));
|
||||
Output?.Out("");
|
||||
#endif
|
||||
|
||||
PacketsReceived++;
|
||||
InternalReceiveCount += nm.Packet.Payload.Length;
|
||||
TotalBytesReceived += nm.Packet.Payload.Length;
|
||||
incomingMessages.Enqueue(nm);
|
||||
} catch(SocketException ex)
|
||||
{
|
||||
Output?.Out(ex.Message);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Output?.Out("server: "+nm.ToString());
|
||||
}
|
||||
@@ -105,18 +81,16 @@ namespace CaveGame.Server
|
||||
bool have = outgoingMessages.TryDequeue(out msg);
|
||||
if (have)
|
||||
{
|
||||
#if PACKETDEBUG
|
||||
Output?.Out(String.Format("PK_OUT: [{0}] at [{1} {2}] to [{3}]", msg.Item1.Type.ToString(), DateTime.Now.ToLongTimeString(), DateTime.Now.Millisecond, msg.Item2.ToString()));
|
||||
Output?.Out(String.Format("DATUM: [{0}]", DumpHex(msg.Item1.Payload)));
|
||||
Output?.Out("");
|
||||
#endif
|
||||
msg.Item1.Send(udpClient, msg.Item2);
|
||||
Packet packet = msg.Item1;
|
||||
IPEndPoint target = msg.Item2;
|
||||
packet.Send(UdpSocket, target);
|
||||
PacketsSent++;
|
||||
TotalBytesSent += packet.Payload.Length;
|
||||
InternalSendCount += packet.Payload.Length;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// If Nothing happened, take a nap
|
||||
if (!canRead && (numToWrite == 0))
|
||||
Thread.Sleep(1);
|
||||
@@ -127,10 +101,7 @@ namespace CaveGame.Server
|
||||
{
|
||||
listening.Value = true;
|
||||
Output?.Out(String.Format("server: listening on port {0}", Port), Color.Coral);
|
||||
}
|
||||
public void Run() {
|
||||
Task.Factory.StartNew(NetworkThread);
|
||||
Output?.Out("server: Network listener thread created", Color.Coral);
|
||||
}
|
||||
|
||||
public bool HaveIncomingMessage()
|
||||
@@ -147,15 +118,21 @@ namespace CaveGame.Server
|
||||
{
|
||||
return msg;
|
||||
}
|
||||
throw new Exception("No Message Queued! Used HaveIncomingMessage() to check!");
|
||||
throw new Exception("No Message Queued! Use HaveIncomingMessage() to check!");
|
||||
}
|
||||
|
||||
public void SendPacket(Packet packet, IPEndPoint target)
|
||||
{
|
||||
//Output?.Out("server: Sending packet " + packet.Type.ToString(), Color.Coral);
|
||||
outgoingMessages.Enqueue(new Tuple<Packet, IPEndPoint>(packet, target));
|
||||
}
|
||||
|
||||
|
||||
public override void Update(GameTime gt)
|
||||
{
|
||||
base.Update(gt);
|
||||
|
||||
}
|
||||
|
||||
public void Cleanup() { }
|
||||
public void Close()
|
||||
{
|
||||
|
@@ -13,38 +13,49 @@ using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using System.Collections.Concurrent;
|
||||
using CaveGame.Core.Game.Tiles;
|
||||
using DataManagement;
|
||||
|
||||
namespace CaveGame.Server
|
||||
{
|
||||
|
||||
|
||||
public class ServerWorld : Core.World, IServerWorld
|
||||
{
|
||||
|
||||
|
||||
|
||||
public int WorldSeed => Metadata.Seed;
|
||||
public string WorldName => Metadata.Name;
|
||||
|
||||
private ConcurrentQueue<IEntity> entityQueue;
|
||||
public void SpawnEntity(IEntity entity) => entityQueue.Enqueue(entity);
|
||||
|
||||
private ConcurrentQueue<IEntity> EntityQueue { get; set; }
|
||||
public void SpawnEntity(IEntity entity) => EntityQueue.Enqueue(entity);
|
||||
|
||||
private Queue<Point> TileNetworkUpdateQueue { get; set; }
|
||||
private Queue<Point> WallNetworkUpdateQueue { get; set; }
|
||||
|
||||
public void RequestTileNetworkUpdate(Point position) => TileNetworkUpdateQueue.Enqueue(position);
|
||||
public void RequestWallNetworkUpdate(Point position) => WallNetworkUpdateQueue.Enqueue(position);
|
||||
|
||||
public GameServer Server { get; set; }
|
||||
public Generator Generator { get; set; }
|
||||
|
||||
public Dictionary<ChunkCoordinates, bool> LoadedChunks;
|
||||
|
||||
protected DelayedTask serverTileUpdateTask;
|
||||
protected DelayedTask serverRandomTileUpdateTask;
|
||||
protected RepeatingIntervalTask TileUpdateTask { get; set; }
|
||||
protected RepeatingIntervalTask RandomTileUpdateTask { get; set; }
|
||||
//protected RepeatingIntervalTask
|
||||
|
||||
|
||||
|
||||
public override List<FurnitureTile> Furniture { get; protected set; }
|
||||
|
||||
public WorldMetadata Metadata { get; private set; }
|
||||
|
||||
|
||||
public ServerWorld(WorldMetadata metadata)
|
||||
public ServerWorld(WorldMetadata metadata) : base()
|
||||
{
|
||||
TileNetworkUpdateQueue = new Queue<Point>();
|
||||
WallNetworkUpdateQueue = new Queue<Point>();
|
||||
|
||||
Context = NetworkContext.Server;
|
||||
//SessionType = GameSessionType.
|
||||
|
||||
|
||||
Metadata = metadata;
|
||||
|
||||
CreateDirectoryIfNull(Path.Combine("Worlds", WorldName));
|
||||
@@ -63,13 +74,55 @@ namespace CaveGame.Server
|
||||
worldXml.WriteEndDocument();
|
||||
worldXml.Close();
|
||||
|
||||
entityQueue = new ConcurrentQueue<IEntity>();
|
||||
serverTileUpdateTask = new DelayedTask(ApplyTileUpdates, 1 / 10.0f);
|
||||
serverRandomTileUpdateTask = new DelayedTask(ApplyRandomTileTicksToLoadedChunks, 1 / 5.0f);
|
||||
WorldTimedTasks.Add(new(ProcessTileUpdateRequests, 1 / 10.0f));
|
||||
WorldTimedTasks.Add(new(DoRandomTileTicks, 1 / 5.0f));
|
||||
WorldTimedTasks.Add(new(SendTileNetworkUpdates, 1 / 5.0f));
|
||||
|
||||
|
||||
EntityQueue = new ConcurrentQueue<IEntity>();
|
||||
//serverTileUpdateTask = new RepeatingIntervalTask(TileUpdates, 1 / 10.0f);
|
||||
|
||||
//serverRandomTileUpdateTask = new RepeatingIntervalTask(ApplyRandomTileTicksToLoadedChunks, 1 / 5.0f);
|
||||
Generator = new Generator(WorldSeed);
|
||||
Tile.InitializeManager(WorldSeed);
|
||||
}
|
||||
|
||||
|
||||
public override void SetTile(int x, int y, Tile t)
|
||||
{
|
||||
base.SetTile(x, y, t);
|
||||
RequestTileNetworkUpdate(new Point(x, y));
|
||||
}
|
||||
|
||||
public virtual void SetTileNetworkUpdated(int x, int y)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void BreakTile(int x, int y)
|
||||
{
|
||||
GetTile(x, y).Drop(Server, this, new Point(x, y));
|
||||
SetTile(x, y, new Air());
|
||||
base.BreakTile(x, y);
|
||||
}
|
||||
|
||||
private void ProcessTileUpdateRequests()
|
||||
{
|
||||
|
||||
int count = TileUpdateQueue.Count;
|
||||
for (int i = 0; i < count-1; i++)
|
||||
{
|
||||
Point coords = TileUpdateQueue.Dequeue();
|
||||
//bool success = TileUpdateQueue.TryDequeue(out coords);
|
||||
if (GetTile(coords) is ITileUpdate tile)
|
||||
tile.TileUpdate(this, coords.X, coords.Y);
|
||||
|
||||
|
||||
foreach (var furn in Furniture.ToArray())
|
||||
furn.OnTileUpdate(this, coords.X, coords.Y);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CreateDirectoryIfNull(string fname)
|
||||
{
|
||||
if (!System.IO.Directory.Exists(fname))
|
||||
@@ -128,7 +181,6 @@ namespace CaveGame.Server
|
||||
Generator.HeightPass(ref chunk);
|
||||
//World.Chunks.Add(coords, chunk);
|
||||
Chunks.TryAdd(coords, chunk);
|
||||
chunk.ClearUpdateQueue();
|
||||
}
|
||||
|
||||
if (!chunk.DungeonPassCompleted)
|
||||
@@ -146,7 +198,6 @@ namespace CaveGame.Server
|
||||
//World.Chunks.Add(newCoords, thischunk);
|
||||
Chunks.TryAdd(newCoords, thischunk);
|
||||
Generator.HeightPass(ref thischunk);
|
||||
thischunk.ClearUpdateQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,6 +213,10 @@ namespace CaveGame.Server
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
||||
public Task<Chunk> LoadChunk(ChunkCoordinates coords) { return null; }// TODO: Implement
|
||||
public Task<bool> UnloadChunk(ChunkCoordinates coords) { return null; }// TODO: Implement
|
||||
|
||||
protected override void PhysicsStep()
|
||||
{
|
||||
foreach (IEntity entity in Entities.ToArray())
|
||||
@@ -169,12 +224,7 @@ namespace CaveGame.Server
|
||||
physicsObserver.ServerPhysicsTick(this, PhysicsStepIncrement);
|
||||
}
|
||||
|
||||
public override void BreakTile(int x, int y)
|
||||
{
|
||||
GetTile(x, y).Drop(Server, this, new Point(x, y));
|
||||
SetTile(x, y, new Air());
|
||||
base.BreakTile(x, y);
|
||||
}
|
||||
|
||||
public override void RemoveFurniture(Core.Furniture.FurnitureTile furn)
|
||||
{
|
||||
|
||||
@@ -183,37 +233,18 @@ namespace CaveGame.Server
|
||||
//base.RemoveFurniture(furn);
|
||||
}
|
||||
|
||||
private void SendTileNetworkUpdates()
|
||||
{
|
||||
foreach (var tileCoords in TileNetworkUpdateQueue.DequeueAll())
|
||||
Server.SendToAll(new PlaceTilePacket(tileCoords, GetTile(tileCoords)));
|
||||
|
||||
private void TileUpdates(Chunk chunk)
|
||||
{
|
||||
for (int x = 0; x < Globals.ChunkSize; x++)
|
||||
{
|
||||
for (int y = 0; y < Globals.ChunkSize; y++)
|
||||
{
|
||||
if (chunk.TileUpdate[x, y] == true)
|
||||
{
|
||||
chunk.TileUpdate[x, y] = false;
|
||||
|
||||
int worldX = (chunk.Coordinates.X * Globals.ChunkSize) + x;
|
||||
int worldY = (chunk.Coordinates.Y * Globals.ChunkSize) + y;
|
||||
foreach (var furn in Furniture.ToArray())
|
||||
furn.OnTileUpdate(this, worldX, worldY);
|
||||
|
||||
|
||||
if (chunk.GetTile(x, y) is ITileUpdate tile)
|
||||
tile.TileUpdate(this, worldX, worldY);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var wallCoords in WallNetworkUpdateQueue.DequeueAll())
|
||||
Server.SendToAll(new PlaceWallPacket(wallCoords, GetWall(wallCoords)));
|
||||
}
|
||||
|
||||
private void ApplyTileUpdates()
|
||||
{
|
||||
foreach (var kvp in Chunks)
|
||||
TileUpdates(kvp.Value);
|
||||
}
|
||||
|
||||
|
||||
private async void ApplyRandomTileTicksToLoadedChunks()
|
||||
private async void DoRandomTileTicks()
|
||||
{
|
||||
await (Task.Run(() =>
|
||||
{
|
||||
@@ -267,15 +298,10 @@ namespace CaveGame.Server
|
||||
|
||||
public override void Update(GameTime gt)
|
||||
{
|
||||
for (int i = 0; i < entityQueue.Count; i++)
|
||||
{
|
||||
bool success = entityQueue.TryDequeue(out var newEntity);
|
||||
if (success)
|
||||
Entities.Add(newEntity);
|
||||
}
|
||||
|
||||
serverRandomTileUpdateTask.Update(gt);
|
||||
serverTileUpdateTask.Update(gt);
|
||||
for (int i = 0; i < EntityQueue.Count; i++)
|
||||
if (EntityQueue.TryDequeue(out IEntity entity))
|
||||
Entities.Add(entity);
|
||||
|
||||
|
||||
foreach (var ent in Entities.ToArray())
|
||||
|
1
Server/World/ChunkManager.cs
Normal file
1
Server/World/ChunkManager.cs
Normal file
@@ -0,0 +1 @@
|
||||
|
Reference in New Issue
Block a user