Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Makes client.images respect changes #1565

Merged
merged 15 commits into from
Jan 4, 2024
Merged
53 changes: 19 additions & 34 deletions OpenDreamClient/Rendering/ClientImagesSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@
using Vector3 = Robust.Shared.Maths.Vector3;

namespace OpenDreamClient.Rendering;

internal sealed class ClientImagesSystem : SharedClientImagesSystem {
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly ClientAppearanceSystem _appearanceSystem = default!;

private readonly Dictionary<Vector3, List<int>> _turfClientImages = new();
private readonly Dictionary<EntityUid, List<int>> _amClientImages = new();
private readonly Dictionary<int, DreamIcon> _idToIcon = new();
private readonly Dictionary<Vector3, List<NetEntity>> _turfClientImages = new();
private readonly Dictionary<EntityUid, List<NetEntity>> _amClientImages = new();

public override void Initialize() {
SubscribeNetworkEvent<AddClientImageEvent>(OnAddClientImage);
Expand All @@ -22,45 +20,30 @@ public override void Initialize() {
public override void Shutdown() {
_turfClientImages.Clear();
_amClientImages.Clear();
_idToIcon.Clear();
}

public bool TryGetClientImages(EntityUid entity, Vector3? tileCoords, [NotNullWhen(true)] out List<DreamIcon>? result){
result = null;
List<int>? resultIDs;
public bool TryGetClientImages(EntityUid entity, Vector3? tileCoords, [NotNullWhen(true)] out List<NetEntity>? result){
if(entity == EntityUid.Invalid && tileCoords is not null) {
if(!_turfClientImages.TryGetValue(tileCoords.Value, out resultIDs))
if(!_turfClientImages.TryGetValue(tileCoords.Value, out result))
return false;
} else {
if(!_amClientImages.TryGetValue(entity, out resultIDs))
if(!_amClientImages.TryGetValue(entity, out result))
return false;
}
result = new List<DreamIcon>();
foreach(int distinctID in resultIDs)
if(_idToIcon.TryGetValue(distinctID, out DreamIcon? icon))
result.Add(icon);
return result.Count > 0;
}

private void OnAddClientImage(AddClientImageEvent e) {
EntityUid ent = _entityManager.GetEntity(e.AttachedEntity);
if(ent == EntityUid.Invalid) {
if(!_turfClientImages.TryGetValue(e.TurfCoords, out var iconList))
iconList = new List<int>();
if(!_idToIcon.ContainsKey(e.ImageAppearance)){
DreamIcon icon = new DreamIcon(_gameTiming, _appearanceSystem, e.ImageAppearance);
_idToIcon[e.ImageAppearance] = icon;
}
iconList.Add(e.ImageAppearance);
iconList = new List<NetEntity>();
iconList.Add(e.ImageEntity);
_turfClientImages[e.TurfCoords] = iconList;
} else {
if(!_amClientImages.TryGetValue(ent, out var iconList))
iconList = new List<int>();
if(!_idToIcon.ContainsKey(e.ImageAppearance)){
DreamIcon icon = new DreamIcon(_gameTiming, _appearanceSystem, e.ImageAppearance);
_idToIcon[e.ImageAppearance] = icon;
}
iconList.Add(e.ImageAppearance);
iconList = new List<NetEntity>();
iconList.Add(e.ImageEntity);
_amClientImages[ent] = iconList;
}

Expand All @@ -69,17 +52,19 @@ private void OnAddClientImage(AddClientImageEvent e) {
private void OnRemoveClientImage(RemoveClientImageEvent e) {
EntityUid ent = _entityManager.GetEntity(e.AttachedEntity);
if(ent == EntityUid.Invalid) {
if(!_turfClientImages.TryGetValue(e.TurfCoords, out var iconList))
return;
iconList.Remove(e.ImageAppearance);
_turfClientImages[e.TurfCoords] = iconList;
_idToIcon.Remove(e.ImageAppearance);
if(!_turfClientImages.TryGetValue(e.TurfCoords, out var iconList))
return;
iconList.Remove(e.ImageEntity);
if(iconList.Count == 0)
_turfClientImages.Remove(e.TurfCoords);

} else {
if(!_amClientImages.TryGetValue(ent, out var iconList))
return;
iconList.Remove(e.ImageAppearance);
_amClientImages[ent] = iconList;
_idToIcon.Remove(e.ImageAppearance);
iconList.Remove(e.ImageEntity);
if(iconList.Count == 0)
_amClientImages.Remove(ent);

}
}
}
18 changes: 9 additions & 9 deletions OpenDreamClient/Rendering/DreamViewOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,14 +304,17 @@ private void ProcessIconComponents(DreamIcon icon, Vector2 position, EntityUid u
//client images act as either an overlay or replace the main icon
//notably they cannot be applied to overlays, so don't check for them if this is an under/overlay
//note also that we use turfCoords and not current.Position because we want world-coordinates, not screen coordinates. This is only used for turfs.
if(parentIcon == null && _clientImagesSystem.TryGetClientImages(current.Uid, turfCoords, out List<DreamIcon>? attachedClientImages)){
foreach(DreamIcon CI in attachedClientImages){
if(CI.Appearance == null)
if(parentIcon == null && _clientImagesSystem.TryGetClientImages(current.Uid, turfCoords, out List<NetEntity>? attachedClientImages)){
foreach(NetEntity CINetEntity in attachedClientImages){
EntityUid imageEntity = _entityManager.GetEntity(CINetEntity);
if (!_spriteQuery.TryGetComponent(imageEntity, out var sprite))
continue;
if(CI.Appearance.Override)
current.MainIcon = CI;
if(sprite.Icon.Appearance == null)
continue;
if(sprite.Icon.Appearance.Override)
current.MainIcon = sprite.Icon;
else
ProcessIconComponents(CI, current.Position, uid, isScreen, ref tieBreaker, result, current, false);
ProcessIconComponents(sprite.Icon, current.Position, uid, isScreen, ref tieBreaker, result, current, false);
}
}

Expand Down Expand Up @@ -360,8 +363,6 @@ private IRenderTexture RentRenderTarget(Vector2i size) {
} else {
result = _clyde.CreateRenderTarget(size, new(RenderTargetColorFormat.Rgba8Srgb));
}

_renderTargetCache[size] = listResult; //put the shorter list back
}

return result;
Expand All @@ -372,7 +373,6 @@ private void ReturnRenderTarget(IRenderTexture rental) {
storeList = new List<IRenderTexture>(4);

storeList.Add(rental);
_renderTargetCache[rental.Size] = storeList;
}

private void ClearRenderTarget(IRenderTexture target, DrawingHandleWorld handle, Color clearColor) {
Expand Down
31 changes: 31 additions & 0 deletions OpenDreamRuntime/Objects/Types/DreamObjectImage.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using OpenDreamRuntime.Procs;
using OpenDreamRuntime.Rendering;
using OpenDreamShared.Dream;
using Robust.Shared.Map;

namespace OpenDreamRuntime.Objects.Types;

Expand All @@ -9,6 +11,7 @@ public sealed class DreamObjectImage : DreamObject {
private DreamObject? _loc;
private DreamList _overlays;
private DreamList _underlays;
private EntityUid _entity = EntityUid.Invalid;

/// <summary>
/// All the args in /image/New() after "icon" and "loc", in their correct order
Expand Down Expand Up @@ -100,6 +103,10 @@ protected override void SetVar(string varName, DreamValue value) {
newAppearance.Direction = Appearance!.Direction;

Appearance = newAppearance;
if(_entity != EntityUid.Invalid) {
DMISpriteComponent sprite = EntityManager.GetComponent<DMISpriteComponent>(_entity);
sprite.SetAppearance(Appearance!);
}
break;
case "loc":
value.TryGetValueAsDreamObject(out _loc);
Expand Down Expand Up @@ -178,6 +185,10 @@ protected override void SetVar(string varName, DreamValue value) {
default:
if (AtomManager.IsValidAppearanceVar(varName)) {
AtomManager.SetAppearanceVar(Appearance!, varName, value);
if(_entity != EntityUid.Invalid) {
DMISpriteComponent sprite = EntityManager.GetComponent<DMISpriteComponent>(_entity);
sprite.SetAppearance(Appearance!);
}
break;
}

Expand All @@ -189,4 +200,24 @@ protected override void SetVar(string varName, DreamValue value) {
public DreamObject? GetAttachedLoc(){
return this._loc;
}

/// <summary>
/// Get or create the entity associated with this image. Used for putting this image in the world ie, with vis_contents
/// The associated entity is deleted when the image is.
/// </summary>
public EntityUid GetEntity() {
if(_entity == EntityUid.Invalid) {
_entity = EntityManager.SpawnEntity(null, new MapCoordinates(0, 0, MapId.Nullspace));
DMISpriteComponent sprite = EntityManager.AddComponent<DMISpriteComponent>(_entity);
sprite.SetAppearance(Appearance!);
}
return _entity;
}

protected override void HandleDeletion() {
if(_entity != EntityUid.Invalid) {
EntityManager.DeleteEntity(_entity);
}
base.HandleDeletion();
}
}
21 changes: 12 additions & 9 deletions OpenDreamRuntime/Rendering/ServerClientImagesSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,31 @@
using OpenDreamShared.Rendering;
using OpenDreamRuntime.Objects;
using Vector3 = Robust.Shared.Maths.Vector3;
using Robust.Server.GameStates;

namespace OpenDreamRuntime.Rendering;
public sealed class ServerClientImagesSystem : SharedClientImagesSystem {
[Dependency] private readonly ServerAppearanceSystem _serverAppearanceSystem = default!;
[Dependency] private readonly AtomManager _atomManager = default!;

[Dependency] private readonly PvsOverrideSystem _pvsOverrideSystem = default!;
public void AddImageObject(DreamConnection connection, DreamObjectImage imageObject) {
DreamObject? loc = imageObject.GetAttachedLoc();
if(loc == null)
return;

EntityUid locEntity = EntityUid.Invalid;
Vector3 turfCoords = Vector3.Zero;
int locAppearanceID = 0;

int imageAppearanceID = _serverAppearanceSystem.AddAppearance(imageObject.Appearance!);

if(loc is DreamObjectMovable movable)
locEntity = movable.Entity;
else if(loc is DreamObjectTurf turf)
turfCoords = new Vector3(turf.X, turf.Y, turf.Z);

NetEntity ent = GetNetEntity(locEntity);
RaiseNetworkEvent(new AddClientImageEvent(ent, turfCoords, imageAppearanceID), connection.Session.ConnectedClient);
EntityUid imageObjectEntity = imageObject.GetEntity();
NetEntity imageObjectNetEntity = GetNetEntity(imageObjectEntity);
if (imageObjectEntity != EntityUid.Invalid)
_pvsOverrideSystem.AddSessionOverride(imageObjectEntity, connection.Session!);
RaiseNetworkEvent(new AddClientImageEvent(ent, turfCoords, imageObjectNetEntity), connection.Session!.Channel);
}

public void RemoveImageObject(DreamConnection connection, DreamObjectImage imageObject) {
Expand All @@ -36,15 +37,17 @@ public void RemoveImageObject(DreamConnection connection, DreamObjectImage image
EntityUid locEntity = EntityUid.Invalid;
Vector3 turfCoords = Vector3.Zero;

int imageAppearanceID = _serverAppearanceSystem.AddAppearance(imageObject.Appearance!);

if(loc is DreamObjectMovable)
locEntity = ((DreamObjectMovable)loc).Entity;
else if(loc is DreamObjectTurf turf)
turfCoords = new Vector3(turf.X, turf.Y, turf.Z);


NetEntity ent = GetNetEntity(locEntity);
RaiseNetworkEvent(new RemoveClientImageEvent(ent, turfCoords, imageAppearanceID), connection.Session.ConnectedClient);
EntityUid imageObjectEntity = imageObject.GetEntity();
if (imageObjectEntity != EntityUid.Invalid)
_pvsOverrideSystem.RemoveSessionOverride(imageObjectEntity, connection.Session!);
NetEntity imageObjectNetEntity = GetNetEntity(imageObject.GetEntity());
RaiseNetworkEvent(new RemoveClientImageEvent(ent, turfCoords, imageObjectNetEntity), connection.Session!.Channel);
}
}
12 changes: 6 additions & 6 deletions OpenDreamShared/Rendering/SharedClientImagesSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public class SharedClientImagesSystem : EntitySystem {
public sealed class AddClientImageEvent : EntityEventArgs {
public Vector3 TurfCoords;
public NetEntity AttachedEntity; //if this is NetEntity.Invalid (ie, a turf) use the TurfCoords instead
public int ImageAppearance;
public NetEntity ImageEntity;

public AddClientImageEvent(NetEntity attachedEntity, Vector3 turfCoords, int imageAppearance) {
public AddClientImageEvent(NetEntity attachedEntity, Vector3 turfCoords, NetEntity imageEntity) {
TurfCoords = turfCoords;
ImageAppearance = imageAppearance;
ImageEntity = imageEntity;
AttachedEntity = attachedEntity;
}
}
Expand All @@ -25,11 +25,11 @@ public AddClientImageEvent(NetEntity attachedEntity, Vector3 turfCoords, int ima
public sealed class RemoveClientImageEvent : EntityEventArgs {
public Vector3 TurfCoords;
public NetEntity AttachedEntity; //if this is NetEntity.Invalid (ie, a turf) use the TurfCoords instead
public int ImageAppearance;
public NetEntity ImageEntity;

public RemoveClientImageEvent(NetEntity attachedEntity, Vector3 turfCoords, int imageAppearance) {
public RemoveClientImageEvent(NetEntity attachedEntity, Vector3 turfCoords, NetEntity imageEntity) {
TurfCoords = turfCoords;
ImageAppearance = imageAppearance;
ImageEntity = imageEntity;
AttachedEntity = attachedEntity;
}
}
Expand Down
4 changes: 3 additions & 1 deletion TestGame/code.dm
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
New()
..()
loc = locate(5, 5, 1)
//color = rgb(rand(0,255), rand(0,255), rand(0,255))

Login()
world.log << "login ran"
Expand Down Expand Up @@ -181,6 +180,9 @@
for(var/turf/T in range(src, 2))
var/image/turf_image = image(icon = 'icons/hanoi.dmi', loc=T, icon_state="1")
src.client.images += turf_image
spawn(25)
src << "changing image"
i.icon_state = "5"
spawn(50)
src.client.images.Cut()

Expand Down
Loading