2 using Microsoft.Xna.Framework;
3 using Microsoft.Xna.Framework.Graphics;
4 using Microsoft.Xna.Framework.Input;
6 using System.Collections.Generic;
15 private class RemoteDecal
17 public readonly UInt32 DecalId;
18 public readonly
int SpriteIndex;
19 public Vector2 NormalizedPos;
20 public readonly
float Scale;
22 public RemoteDecal(UInt32 decalId,
int spriteIndex, Vector2 normalizedPos,
float scale)
25 SpriteIndex = spriteIndex;
26 NormalizedPos = normalizedPos;
31 private float serverUpdateDelay;
32 private float remoteWaterVolume, remoteOxygenPercentage;
33 private NetworkFireSource[] remoteFireSources =
null;
34 private readonly List<BackgroundSection> remoteBackgroundSections =
new List<BackgroundSection>();
35 private readonly List<RemoteDecal> remoteDecals =
new List<RemoteDecal>();
37 private readonly HashSet<Decal> pendingDecalUpdates =
new HashSet<Decal>();
39 private double lastAmbientLightEditTime;
41 private float drawSurface;
45 get {
return drawSurface; }
48 if (Math.Abs(drawSurface - value) < 0.00001f) {
return; }
49 drawSurface = MathHelper.Clamp(value,
rect.Y -
rect.Height,
rect.Y);
78 private float paintAmount = 0.0f;
79 private float minimumPaintAmountToDraw;
87 if (decals.Count == 0 && paintAmount < minimumPaintAmountToDraw) {
return false; }
90 if (worldRect.X > worldView.Right || worldRect.Right < worldView.X) {
return false; }
91 if (worldRect.Y < worldView.Y - worldView.Height || worldRect.Y - worldRect.Height > worldView.Y) {
return false; }
104 private GUIComponent CreateEditingHUD(
bool inGame =
false)
109 CanTakeKeyBoardFocus =
false
111 new SerializableEntityEditor(listBox.Content.RectTransform,
this, inGame, showName:
true, titleFont: GUIStyle.LargeFont);
128 if (!lClick && !rClick) {
return; }
134 if (entity ==
this) {
continue; }
135 if (!entity.
IsMouseOn(position)) {
continue; }
150 partial
void UpdateProjSpecific(
float deltaTime,
Camera _)
154 drawSurface = Math.Max(MathHelper.Lerp(
157 deltaTime * 10.0f),
rect.Y -
rect.Height);
161 serverUpdateDelay -= deltaTime;
162 if (serverUpdateDelay <= 0.0f)
166 if (networkUpdatePending)
168 networkUpdateTimer += deltaTime;
169 if (networkUpdateTimer > 0.2f)
171 if (!pendingSectionUpdates.Any() && !pendingDecalUpdates.Any())
175 GameMain.Client?.CreateEntityEvent(
this,
new StatusEventData(), requireControlledCharacter:
false);
177 foreach (Decal decal
in pendingDecalUpdates)
179 GameMain.Client?.CreateEntityEvent(
this,
new DecalEventData(decal));
181 pendingDecalUpdates.Clear();
182 foreach (
int pendingSectionUpdate
in pendingSectionUpdates)
184 GameMain.Client?.CreateEntityEvent(
this,
new BackgroundSectionsEventData(pendingSectionUpdate));
186 pendingSectionUpdates.Clear();
187 networkUpdatePending =
false;
188 networkUpdateTimer = 0.0f;
215 if (!primaryMouseButtonHeld && !secondaryMouseButtonHeld && !doubleClicked && !secondaryDoubleClicked) {
return; }
220 if (hull ==
null || hull.IdFreed) {
return; }
223 const float waterIncrement = 100000.0f;
224 if (primaryMouseButtonHeld)
226 SetWaterVolume(hull.WaterVolume + waterIncrement * deltaTime);
228 else if (secondaryMouseButtonHeld)
230 SetWaterVolume(hull.WaterVolume - waterIncrement * deltaTime);
237 else if (secondaryDoubleClicked)
242 void SetWaterVolume(
float newVolume)
245 hull.WaterVolume = newVolume;
246 hull.networkUpdatePending =
true;
247 hull.serverUpdateDelay = 0.5f;
252 bool networkUpdate =
false;
254 if (primaryMouseButtonHeld)
256 new FireSource(position, hull, isNetworkMessage:
true);
257 networkUpdate =
true;
259 else if (secondaryMouseButtonHeld || secondaryDoubleClicked)
261 for (
int index = hull.FireSources.Count - 1; index >= 0; index--)
263 var currentFireSource = hull.FireSources[index];
265 if (secondaryMouseButtonHeld)
267 const float extinguishAmount = 120f;
268 currentFireSource.Extinguish(deltaTime, extinguishAmount);
269 networkUpdate =
true;
273 currentFireSource.Remove();
274 networkUpdate =
true;
281 hull.networkUpdatePending =
true;
282 hull.serverUpdateDelay = 0.5f;
287 private void DrawDecals(SpriteBatch spriteBatch)
293 foreach (
Decal d
in decals)
295 d.
Draw(spriteBatch,
this, depth);
300 public override void Draw(SpriteBatch spriteBatch,
bool editing,
bool back =
true)
305 DrawDecals(spriteBatch);
314 float hideTimeAfterEdit = 3.0f;
315 if (lastAmbientLightEditTime > Timing.TotalTime - hideTimeAfterEdit * 2.0f)
317 alpha = Math.Min((
float)(Timing.TotalTime - lastAmbientLightEditTime) / hideTimeAfterEdit - 1.0f, 1.0f);
327 GUI.DrawRectangle(spriteBatch,
328 new Vector2(drawRect.X, -drawRect.Y),
329 new Vector2(
rect.Width,
rect.Height),
334 GUI.DrawRectangle(spriteBatch,
335 new Vector2(drawRect.X, -drawRect.Y + drawRect.Height - waterHeight),
336 new Vector2(drawRect.Width, waterHeight),
337 Color.Blue * 0.25f, isFilled:
true);
340 GUI.DrawRectangle(spriteBatch,
341 new Vector2(drawRect.X, -drawRect.Y),
342 new Vector2(
rect.Width,
rect.Height),
343 Color.Blue * alpha,
false, (
ID % 255) * 0.000001f, (
int)Math.Max(MathF.Ceiling(1.5f /
Screen.
Selected.
Cam.
Zoom), 1.0f));
345 GUI.DrawRectangle(spriteBatch,
351 GUIStyle.SmallFont.DrawString(spriteBatch,
"Pressure: " + ((
int)pressure -
rect.Y).ToString() +
352 " - Oxygen: " + ((
int)
OxygenPercentage),
new Vector2(drawRect.X + 5, -drawRect.Y + 5), Color.White);
353 GUIStyle.SmallFont.DrawString(spriteBatch, waterVolume +
" / " +
Volume,
new Vector2(drawRect.X + 5, -drawRect.Y + 20), Color.White);
357 drawProgressBar(50,
new Point(0, 0), Math.Min(waterVolume /
Volume, 1.0f), Color.Cyan);
361 drawProgressBar(50,
new Point(0, 0), (waterVolume -
Volume) / maxExcessWater, GUIStyle.Red);
364 if (lethalPressure > 0)
366 drawProgressBar(50,
new Point(20, 0), lethalPressure / 100.0f, Color.Red);
369 void drawProgressBar(
int height, Point offset,
float fillAmount, Color color)
371 GUI.DrawRectangle(spriteBatch,
new Rectangle(drawRect.Center.X - 2 + offset.X, -drawRect.Y - 2 + drawRect.Height / 2 + offset.Y, 14, height+4), Color.Black * 0.8f, depth: 0.01f, isFilled:
true);
373 int barHeight = (int)(fillAmount * height);
374 GUI.DrawRectangle(spriteBatch,
new Rectangle(drawRect.Center.X + offset.X, -drawRect.Y + drawRect.Height / 2 + height - barHeight + offset.Y, 10, barHeight), color, isFilled:
true);
380 GUI.DrawRectangle(spriteBatch, fireSourceRect, GUIStyle.Red,
false, 0, 5);
381 GUI.DrawRectangle(spriteBatch,
new Rectangle(fireSourceRect.X - (
int)fs.
DamageRange, fireSourceRect.Y, fireSourceRect.Width + (
int)fs.
DamageRange * 2, fireSourceRect.Height), GUIStyle.Orange,
false, 0, 5);
387 GUI.DrawRectangle(spriteBatch, fireSourceRect, GUIStyle.Red,
false, 0, 5);
388 GUI.DrawRectangle(spriteBatch,
new Rectangle(fireSourceRect.X - (
int)fs.
DamageRange, fireSourceRect.Y, fireSourceRect.Width + (
int)fs.
DamageRange * 2, fireSourceRect.Height), GUIStyle.Orange,
false, 0, 5);
393 GUI.DrawLine(spriteBatch,
new Vector2(drawRect.X, -
WorldSurface),
new Vector2(drawRect.Right, -
WorldSurface), Color.Cyan * 0.5f);
394 for (
int i = 0; i < waveY.Length - 1; i++)
396 GUI.DrawLine(spriteBatch,
398 new Vector2(drawRect.X +
WaveWidth * (i + 1), -
WorldSurface - waveY[i + 1] - 10), Color.Blue * 0.5f);
404 if (e is
Hull linkedHull)
411 linkedHull.WorldRect.Width, linkedHull.WorldRect.Height);
421 GUI.DrawLine(spriteBatch,
422 new Vector2(currentHullRect.X, -currentHullRect.Y),
423 new Vector2(connectedHullRect.X, -connectedHullRect.Y),
424 GUIStyle.Green, width: 2);
434 Vector2 drawPos = drawOffset +
new Vector2(
rect.Location.X + sectionSize.X / 2,
rect.Location.Y - sectionSize.Y / 2);
444 GUI.DrawRectangle(spriteBatch,
445 new Vector2(drawOffset.X +
rect.X + section.
Rect.X, -(drawOffset.Y +
rect.Y + section.
Rect.Y)),
446 new Vector2(sectionSize.X, sectionSize.Y),
451 Vector2 sectionPos =
new Vector2(drawPos.X + section.
Rect.Location.X, -(drawPos.Y + section.
Rect.Location.Y));
452 Vector2 randomOffset =
new Vector2(section.
Noise.X - 0.5f, section.
Noise.Y - 0.5f) * 15.0f;
462 if (entityGrid.
WorldRect.X > cam.WorldView.Right || entityGrid.
WorldRect.Right < cam.WorldView.X) {
continue; }
463 if (entityGrid.
WorldRect.Y - entityGrid.
WorldRect.Height > cam.WorldView.Y || entityGrid.
WorldRect.Y < cam.WorldView.Y - cam.WorldView.Height) {
continue; }
466 foreach (
Hull hull
in allEntities)
468 hull.UpdateVertices(cam, entityGrid, renderer);
473 private static readonly Vector3[] corners =
new Vector3[6];
474 private static readonly Vector2[] uvCoords =
new Vector2[4];
475 private static readonly Vector3[] prevCorners =
new Vector3[2];
476 private static readonly Vector2[] prevUVs =
new Vector2[2];
491 float top =
rect.Y + submarinePos.Y;
492 float bottom = top -
rect.Height;
493 float renderSurface = drawSurface + submarinePos.Y;
498 Matrix transform = cam.
Transform * Matrix.CreateOrthographic(GameMain.GraphicsWidth, GameMain.GraphicsHeight, -1, 1) * 0.5f;
503 corners[0] =
new Vector3(
rect.X,
rect.Y, 0.0f);
504 corners[1] =
new Vector3(
rect.X +
rect.Width,
rect.Y, 0.0f);
506 corners[2] =
new Vector3(corners[1].X,
rect.Y -
rect.Height, 0.0f);
507 corners[3] =
new Vector3(corners[0].X, corners[2].Y, 0.0f);
509 for (
int i = 0; i < 4; i++)
511 corners[i] +=
new Vector3(submarinePos, 0.0f);
512 uvCoords[i] = Vector2.Transform(
new Vector2(corners[i].X, -corners[i].Y), transform);
530 renderer.
IndoorsVertices[entityGrid] =
new VertexPositionColorTexture[WaterRenderer.DefaultIndoorsBufferSize];
541 start = Math.Max(start, 0);
544 end = Math.Min(end, waveY.Length - 1);
550 for (
int i = start; i < end; i++)
553 corners[0] =
new Vector3(x, top, 0.0f);
555 corners[3] =
new Vector3(corners[0].X, renderSurface + waveY[i], 0.0f);
558 corners[1] =
new Vector3(x + width, top, 0.0f);
560 corners[2] =
new Vector3(corners[1].X, renderSurface + waveY[i + 1], 0.0f);
563 corners[4] =
new Vector3(x, bottom, 0.0f);
565 corners[5] =
new Vector3(x + width, bottom, 0.0f);
567 Vector2[] uvCoords =
new Vector2[4];
568 for (
int n = 0; n < 4; n++)
570 uvCoords[n] = Vector2.Transform(
new Vector2(corners[n].X, -corners[n].Y), transform);
577 prevCorners[0] = corners[0];
578 prevCorners[1] = corners[3];
579 prevUVs[0] = uvCoords[0];
580 prevUVs[1] = uvCoords[3];
584 if (i == end - 1 || i == start || Math.Abs(prevCorners[1].Y - corners[2].Y) > 0.01f)
594 prevCorners[0] = corners[1];
595 prevCorners[1] = corners[2];
596 prevUVs[0] = uvCoords[1];
597 prevUVs[1] = uvCoords[2];
606 const float SurfaceSize = 10.0f;
607 const float SineFrequency1 = 0.01f;
608 const float SineFrequency2 = 0.05f;
611 float surfaceScale = 1.0f - MathHelper.Clamp(corners[3].Y - (top - SurfaceSize), 0.0f, 1.0f);
613 Vector3 surfaceOffset =
new Vector3(0.0f, -SurfaceSize, 0.0f);
614 surfaceOffset.Y += (float)Math.Sin((
rect.X + i *
WaveWidth) * SineFrequency1 + renderer.
WavePos.X * 0.25f) * 2;
615 surfaceOffset.Y += (float)Math.Sin((
rect.X + i *
WaveWidth) * SineFrequency2 - renderer.
WavePos.X) * 2;
616 surfaceOffset *= surfaceScale;
618 Vector3 surfaceOffset2 =
new Vector3(0.0f, -SurfaceSize, 0.0f);
619 surfaceOffset2.Y += (float)Math.Sin((
rect.X + i *
WaveWidth + width) * SineFrequency1 + renderer.
WavePos.X * 0.25f) * 2;
620 surfaceOffset2.Y += (float)Math.Sin((
rect.X + i *
WaveWidth + width) * SineFrequency2 - renderer.
WavePos.X) * 2;
621 surfaceOffset2 *= surfaceScale;
625 renderer.
IndoorsVertices[entityGrid][posInBuffer + 0] =
new VertexPositionColorTexture(corners[3] + surfaceOffset, renderer.
IndoorsWaterColor, Vector2.Zero);
626 renderer.
IndoorsVertices[entityGrid][posInBuffer + 1] =
new VertexPositionColorTexture(corners[2] + surfaceOffset2, renderer.
IndoorsWaterColor, Vector2.Zero);
629 renderer.
IndoorsVertices[entityGrid][posInBuffer + 3] =
new VertexPositionColorTexture(corners[3] + surfaceOffset, renderer.
IndoorsWaterColor, Vector2.Zero);
636 if (surfaceScale > 0)
661 if (!(extraData is
IEventData eventData)) {
throw new Exception($
"Malformed hull event: expected {nameof(Hull)}.{nameof(IEventData)}"); }
666 case StatusEventData statusEventData:
667 SharedStatusWrite(msg);
669 case BackgroundSectionsEventData backgroundSectionsEventData:
670 SharedBackgroundSectionsWrite(msg, backgroundSectionsEventData);
672 case DecalEventData decalEventData:
673 var decal = decalEventData.Decal;
674 int decalIndex = decals.IndexOf(decal);
675 msg.
WriteByte((
byte)(decalIndex < 0 ? 255 : decalIndex));
679 throw new Exception($
"Malformed hull event: did not expect {eventData.GetType().Name}");
693 out
float newWaterVolume,
696 remoteWaterVolume = newWaterVolume;
697 remoteFireSources = newFireSources;
700 SharedBackgroundSectionRead(
704 int i = bsnu.SectionIndex;
705 Color color = bsnu.Color;
706 float colorStrength = bsnu.ColorStrength;
708 var remoteBackgroundSection = remoteBackgroundSections.Find(s => s.Index == i);
709 if (remoteBackgroundSection !=
null)
711 remoteBackgroundSection.SetColorStrength(colorStrength);
712 remoteBackgroundSection.SetColor(color);
723 if (decalCount == 0) { decals.Clear(); }
724 remoteDecals.Clear();
725 for (
int i = 0; i < decalCount; i++)
732 remoteDecals.Add(
new RemoteDecal(decalId, spriteIndex,
new Vector2(normalizedXPos, normalizedYPos), decalScale));
736 BallastFloraBehavior.NetworkHeader header = (BallastFloraBehavior.NetworkHeader) msg.
ReadByte();
737 if (header == BallastFloraBehavior.NetworkHeader.Spawn)
753 throw new Exception($
"Malformed incoming hull event: {eventType} is not a supported event type");
756 if (serverUpdateDelay > 0.0f) {
return; }
761 private void ApplyRemoteState()
770 remoteBackgroundSections.Clear();
772 if (remoteDecals.Count > 0)
775 foreach (RemoteDecal remoteDecal
in remoteDecals)
777 float decalPosX = MathHelper.Lerp(
rect.X,
rect.Right, remoteDecal.NormalizedPos.X);
778 float decalPosY = MathHelper.Lerp(
rect.Y -
rect.Height,
rect.Y, remoteDecal.NormalizedPos.Y);
784 AddDecal(remoteDecal.DecalId,
new Vector2(decalPosX, decalPosY), remoteDecal.Scale, isNetworkEvent:
true, spriteIndex: remoteDecal.SpriteIndex);
786 remoteDecals.Clear();
789 if (remoteFireSources is
null) {
return; }
794 for (
int i = 0; i < remoteFireSources.Length; i++)
796 Vector2 pos = remoteFireSources[i].Position;
797 float size = remoteFireSources[i].Size;
802 newFire.Position = pos;
803 newFire.Size =
new Vector2(size, newFire.Size.Y);
813 for (
int i =
FireSources.Count - 1; i >= remoteFireSources.Length; i--)
821 remoteFireSources =
null;
Color GetStrengthAdjustedColor()
static BallastFloraPrefab Find(Identifier identifier)
Vector2 ScreenToWorld(Vector2 coords)
void Draw(SpriteBatch spriteBatch, Hull hull, float depth)
IEnumerable< MapEntity > GetAllEntities()
virtual Vector2 WorldPosition
readonly ushort ID
Unique, but non-persistent identifier. Stays the same if the entities are created in the exactly same...
virtual float DamageRange
RectTransform RectTransform
static SubEditorScreen SubEditorScreen
void ClientEventRead(IReadMessage msg, float sendingTime)
void DrawSectionColors(SpriteBatch spriteBatch)
static void UpdateCheats(float deltaTime, Camera cam)
override bool IsMouseOn(Vector2 position)
override void Draw(SpriteBatch spriteBatch, bool editing, bool back=true)
override void UpdateEditing(Camera cam, float deltaTime)
override bool IsVisible(Rectangle worldView)
Decal AddDecal(UInt32 decalId, Vector2 worldPosition, float scale, bool isNetworkEvent, int? spriteIndex=null)
List< DummyFireSource > FakeFireSources
const int MaxDecalsPerHull
static readonly List< EntityGrid > EntityGrids
BallastFloraBehavior BallastFlora
static Hull FindHull(Vector2 position, Hull guess=null, bool useWorldCoordinates=true, bool inclusive=true)
Returns the hull which contains the point (or null if it isn't inside any)
static void UpdateVertices(Camera cam, WaterRenderer renderer)
override bool DrawOverWater
void ClientEventWrite(IWriteMessage msg, NetEntityEvent.IData extraData=null)
override bool SelectableInEditor
override bool DrawBelowWater
List< BackgroundSection > BackgroundSections
List< FireSource > FireSources
static GUIComponent editingHUD
static IEnumerable< MapEntity > HighlightedEntities
static void PositionEditingHUD()
readonly List< MapEntity > linkedTo
virtual bool IsMouseOn(Vector2 position)
void Draw(ISpriteBatch spriteBatch, Vector2 pos, float rotate=0.0f, float scale=1.0f, SpriteEffects spriteEffect=SpriteEffects.None)
static bool IsLayerVisible(MapEntity entity)
static bool RectContains(Rectangle rect, Vector2 pos, bool inclusive=false)
override Vector2? Position
VertexPositionTexture[] vertices
readonly WaterVertexData IndoorsSurfaceBottomColor
Dictionary< EntityGrid, int > PositionInIndoorsBuffer
Dictionary< EntityGrid, VertexPositionColorTexture[]> IndoorsVertices
readonly WaterVertexData IndoorsWaterColor
readonly WaterVertexData IndoorsSurfaceTopColor
Interface for entities that the clients can send events to the server
int ReadRangedInteger(int min, int max)
Single ReadRangedSingle(Single min, Single max, int bitCount)
Identifier ReadIdentifier()
Interface for entities that the server can send events to the clients
void WriteRangedInteger(int val, int min, int max)
void WriteRangedSingle(Single val, Single min, Single max, int bitCount)