mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
* Physics worlds * Paul's a good boy * Build working * Ingame and not lagging to hell * Why didn't you commit ahhhhh * Hard collisions working * Solver parity * Decent broadphase work done * BroadPhase outline done * BroadPhase working * waiting for pvs * Fix static PVS AABB * Stop static bodies from awakening * Optimise a bunch of stuff * Even more broadphase stuff * I'm fucking stupid * Optimise fixture updates * Collision solver start * Building * A is for Argumentative * Fix contact caching island flags * Circle shapes actually workeded * Damping * DS2 consumables only * Slightly more stable * Even slightlier more stablier * VV your heart out * Initial joint support * 90% of joints I just wanted to push as I'd scream if I lost progress * JOINT PURGATORY * Joints barely functional lmao * Okay these joints slightly more functional * Remove station FrictionJoint * Also that * Some Box2D ports * Cleanup mass * Edge shape * Active contacts * Fix active contacts * Optimise active contacts even more * Boxes be stacking * I would die for smug oh my fucking god * In which everything is fixed * Distance joints working LETS GO * Remove frequency on distancejoint * Fix some stuff and break joints * Crashing fixed mehbeh * ICollideSpecial and more resilience * auto-clear * showbb vera * Slap that TODO in there * Fix restartround crash * Random fixes * Fix fixture networking * Add intersection method for broadphase * Fix contacts * Licenses done * Optimisations * Fix wall clips * Config caching for island * allocations optimisations * Optimise casts * Optimise events queue for physics * Contact manager optimisations * Optimise controllers * Sloth joint or something idk * Controller graph * Remove content cvar * Random cleanup * Finally remove VirtualController * Manifold structs again * Optimise this absolute retardation * Optimise * fix license * Cleanup physics interface * AHHHHHHHHHHHHH * Fix collisions again * snivybus * Fix potential nasty manifold bug * Tests go snivy * Disable prediction for now * Spans * Fix ShapeTypes * fixes * ch ch changeesss * Kinematic idea * Prevent static bodies from waking * Pass WorldAABB to MoveEvent * Fix collisions * manifold structs fucking WOOORRKKKINNGGG * Better pushing * Fix merge ickies * Optimise MoveEvents * Use event for collisions performance * Fix content tests * Do not research tests * Fix most conflicts * Paul's trying to kill me * Maybe collisions work idk * Make us whole again * Smug is also trying to kill me * nani * shitty collisions * Settling * Do not research collisions * SHIP IT * Fix joints * PVS moment * Fix other assert * Fix locker collisions * serializable sleeptime * Aether2D contacts * Physics is no longer crashing (and burning) * Add to the TODO list Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
260 lines
9.5 KiB
C#
260 lines
9.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using Robust.Client.Graphics;
|
|
using Robust.Client.ResourceManagement;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Maths;
|
|
using Robust.Shared.Physics.Broadphase;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Robust.Client.Placement
|
|
{
|
|
public abstract class PlacementMode
|
|
{
|
|
public readonly PlacementManager pManager;
|
|
|
|
/// <summary>
|
|
/// Holds the current tile we are hovering our mouse over
|
|
/// </summary>
|
|
public TileRef CurrentTile { get; set; }
|
|
|
|
/// <summary>
|
|
/// Local coordinates of our cursor on the map
|
|
/// </summary>
|
|
public EntityCoordinates MouseCoords { get; set; }
|
|
|
|
/// <summary>
|
|
/// Texture resources to draw to represent the entity we are trying to spawn
|
|
/// </summary>
|
|
public List<Texture>? TexturesToDraw { get; set; }
|
|
|
|
/// <summary>
|
|
/// Color set to the ghost entity when it has a valid spawn position
|
|
/// </summary>
|
|
public Color ValidPlaceColor { get; set; } = new(20, 180, 20); //Default valid color is green
|
|
|
|
/// <summary>
|
|
/// Color set to the ghost entity when it has an invalid spawn position
|
|
/// </summary>
|
|
public Color InvalidPlaceColor { get; set; } = new(180, 20, 20); //Default invalid placement is red
|
|
|
|
/// <summary>
|
|
/// Used for line and grid placement to determine how spaced apart the entities should be
|
|
/// </summary>
|
|
protected float GridDistancing = 1f;
|
|
|
|
/// <summary>
|
|
/// Whether this mode requires us to verify the player is spawning within a certain range of themselves
|
|
/// </summary>
|
|
public virtual bool RangeRequired => false;
|
|
|
|
/// <summary>
|
|
/// Whether this mode can use the line placement mode
|
|
/// </summary>
|
|
public virtual bool HasLineMode => false;
|
|
|
|
/// <summary>
|
|
/// Whether this mode can use the grid placement mode
|
|
/// </summary>
|
|
public virtual bool HasGridMode => false;
|
|
|
|
protected PlacementMode(PlacementManager pMan)
|
|
{
|
|
pManager = pMan;
|
|
}
|
|
|
|
public virtual string ModeName => GetType().Name;
|
|
|
|
/// <summary>
|
|
/// Aligns the location of placement based on cursor location
|
|
/// </summary>
|
|
/// <param name="mouseScreen"></param>
|
|
/// <returns>Returns whether the current position is a valid placement position</returns>
|
|
public abstract void AlignPlacementMode(ScreenCoordinates mouseScreen);
|
|
|
|
/// <summary>
|
|
/// Verifies the location of placement is a valid position to place at
|
|
/// </summary>
|
|
/// <param name="mouseScreen"></param>
|
|
/// <returns></returns>
|
|
public abstract bool IsValidPosition(EntityCoordinates position);
|
|
|
|
public virtual void Render(DrawingHandleWorld handle)
|
|
{
|
|
if (TexturesToDraw == null)
|
|
{
|
|
SetSprite();
|
|
DebugTools.AssertNotNull(TexturesToDraw);
|
|
}
|
|
|
|
if (TexturesToDraw == null || TexturesToDraw.Count == 0)
|
|
return;
|
|
|
|
IEnumerable<EntityCoordinates> locationcollection;
|
|
switch (pManager.PlacementType)
|
|
{
|
|
case PlacementManager.PlacementTypes.None:
|
|
locationcollection = SingleCoordinate();
|
|
break;
|
|
case PlacementManager.PlacementTypes.Line:
|
|
locationcollection = LineCoordinates();
|
|
break;
|
|
case PlacementManager.PlacementTypes.Grid:
|
|
locationcollection = GridCoordinates();
|
|
break;
|
|
default:
|
|
locationcollection = SingleCoordinate();
|
|
break;
|
|
}
|
|
|
|
var size = TexturesToDraw[0].Size;
|
|
foreach (var coordinate in locationcollection)
|
|
{
|
|
var worldPos = coordinate.ToMapPos(pManager.EntityManager);
|
|
var pos = worldPos - (size/(float)EyeManager.PixelsPerMeter) / 2f;
|
|
var color = IsValidPosition(coordinate) ? ValidPlaceColor : InvalidPlaceColor;
|
|
|
|
foreach (var texture in TexturesToDraw)
|
|
{
|
|
handle.DrawTexture(texture, pos, color);
|
|
}
|
|
}
|
|
}
|
|
|
|
public IEnumerable<EntityCoordinates> SingleCoordinate()
|
|
{
|
|
yield return MouseCoords;
|
|
}
|
|
|
|
public IEnumerable<EntityCoordinates> LineCoordinates()
|
|
{
|
|
var (x, y) = MouseCoords.ToMapPos(pManager.EntityManager) - pManager.StartPoint.ToMapPos(pManager.EntityManager);
|
|
float iterations;
|
|
Vector2 distance;
|
|
if (Math.Abs(x) > Math.Abs(y))
|
|
{
|
|
iterations = Math.Abs(x / GridDistancing);
|
|
distance = new Vector2(x > 0 ? 1 : -1, 0) * GridDistancing;
|
|
}
|
|
else
|
|
{
|
|
iterations = Math.Abs(y / GridDistancing);
|
|
distance = new Vector2(0, y > 0 ? 1 : -1) * GridDistancing;
|
|
}
|
|
|
|
for (var i = 0; i <= iterations; i++)
|
|
{
|
|
yield return new EntityCoordinates(pManager.StartPoint.EntityId, pManager.StartPoint.Position + distance * i);
|
|
}
|
|
}
|
|
|
|
// This name is a nice reminder of our origins. Never forget.
|
|
public IEnumerable<EntityCoordinates> GridCoordinates()
|
|
{
|
|
var placementdiff = MouseCoords.ToMapPos(pManager.EntityManager) - pManager.StartPoint.ToMapPos(pManager.EntityManager);
|
|
var distanceX = new Vector2(placementdiff.X > 0 ? 1 : -1, 0) * GridDistancing;
|
|
var distanceY = new Vector2(0, placementdiff.Y > 0 ? 1 : -1) * GridDistancing;
|
|
|
|
var iterationsX = Math.Abs(placementdiff.X / GridDistancing);
|
|
var iterationsY = Math.Abs(placementdiff.Y / GridDistancing);
|
|
|
|
for (var x = 0; x <= iterationsX; x++)
|
|
{
|
|
for (var y = 0; y <= iterationsY; y++)
|
|
{
|
|
yield return new EntityCoordinates(pManager.StartPoint.EntityId, pManager.StartPoint.Position + distanceX * x + distanceY * y);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the tile ref for a grid, or a map.
|
|
/// </summary>
|
|
public TileRef GetTileRef(EntityCoordinates coordinates)
|
|
{
|
|
var mapCoords = coordinates.ToMap(pManager.EntityManager);
|
|
var gridId = coordinates.GetGridId(pManager.EntityManager);
|
|
return gridId.IsValid() ? pManager.MapManager.GetGrid(gridId).GetTileRef(MouseCoords)
|
|
: new TileRef(mapCoords.MapId, gridId,
|
|
MouseCoords.ToVector2i(pManager.EntityManager, pManager.MapManager), Tile.Empty);
|
|
}
|
|
|
|
public TextureResource GetSprite(string key)
|
|
{
|
|
return pManager.ResourceCache.GetResource<TextureResource>(new ResourcePath("/Textures/") / key);
|
|
}
|
|
|
|
public bool TryGetSprite(string key, [NotNullWhen(true)] out TextureResource? sprite)
|
|
{
|
|
return pManager.ResourceCache.TryGetResource(new ResourcePath(@"/Textures/") / key, out sprite);
|
|
}
|
|
|
|
public void SetSprite()
|
|
{
|
|
if (pManager.CurrentTextures == null)
|
|
return;
|
|
|
|
TexturesToDraw = pManager.CurrentTextures.Select(o => o.TextureFor(pManager.Direction)).ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if the player is spawning within a certain range of his character if range is required on this mode
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public bool RangeCheck(EntityCoordinates coordinates)
|
|
{
|
|
if (!RangeRequired)
|
|
return true;
|
|
|
|
if (pManager.PlayerManager.LocalPlayer?.ControlledEntity == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var range = pManager.CurrentPermission!.Range;
|
|
if (range > 0 && !pManager.PlayerManager.LocalPlayer.ControlledEntity.Transform.Coordinates.InRange(pManager.EntityManager, coordinates, range))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
public bool IsColliding(EntityCoordinates coordinates)
|
|
{
|
|
var bounds = pManager.ColliderAABB;
|
|
var mapCoords = coordinates.ToMap(pManager.EntityManager);
|
|
var (x, y) = mapCoords.Position;
|
|
|
|
var collisionBox = Box2.FromDimensions(
|
|
bounds.Left + x,
|
|
bounds.Bottom + y,
|
|
bounds.Width,
|
|
bounds.Height);
|
|
|
|
return EntitySystem.Get<SharedBroadPhaseSystem>().TryCollideRect(collisionBox, mapCoords.MapId);
|
|
}
|
|
|
|
protected Vector2 ScreenToWorld(Vector2 point)
|
|
{
|
|
return pManager.eyeManager.ScreenToMap(point).Position;
|
|
}
|
|
|
|
protected Vector2 WorldToScreen(Vector2 point)
|
|
{
|
|
return pManager.eyeManager.WorldToScreen(point);
|
|
}
|
|
|
|
protected EntityCoordinates ScreenToCursorGrid(ScreenCoordinates coords)
|
|
{
|
|
var mapCoords = pManager.eyeManager.ScreenToMap(coords.Position);
|
|
if (!pManager.MapManager.TryFindGridAt(mapCoords, out var grid))
|
|
{
|
|
return EntityCoordinates.FromMap(pManager.EntityManager, pManager.MapManager, mapCoords);
|
|
}
|
|
|
|
return EntityCoordinates.FromMap(pManager.EntityManager, grid.GridEntityId, mapCoords);
|
|
}
|
|
}
|
|
}
|