Skip to content

Commit

Permalink
Makes client.images respect changes (OpenDreamProject#1565)
Browse files Browse the repository at this point in the history
* kinda working I guess

* oh wait I can just update the appearance

* call parents

* client.images test

* boom

* fix

* remove viscontents test from testgame

* move client image to session only, and remove properly

* Remove unneeded dict assignment

* same shitcode in rendertarget rental

* Actually, vis_contents += image is a bug!
  • Loading branch information
amylizzle authored Jan 4, 2024
1 parent 1515f0d commit 3846bfa
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 59 deletions.
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

0 comments on commit 3846bfa

Please sign in to comment.