Index: binaries/data/mods/public/simulation/components/BuildingAI.js
===================================================================
--- binaries/data/mods/public/simulation/components/BuildingAI.js	(revision 18179)
+++ binaries/data/mods/public/simulation/components/BuildingAI.js	(working copy)
@@ -37,7 +37,7 @@
 	for (let ent of msg.added)
 	{
 		let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
-		if (!cmpIdentity)
+		if (msg.visible[ent] || !cmpIdentity)
 			continue;
 		if (MatchesClassList(cmpIdentity.GetClassesList(), classes))
 			++this.archersGarrisoned;
@@ -46,7 +46,7 @@
 	for (let ent of msg.removed)
 	{
 		let cmpIdentity = Engine.QueryInterface(ent, IID_Identity);
-		if (!cmpIdentity)
+		if (msg.visible[ent] || !cmpIdentity)
 			continue;
 		if (MatchesClassList(cmpIdentity.GetClassesList(), classes))
 			--this.archersGarrisoned;
Index: binaries/data/mods/public/simulation/components/GarrisonHolder.js
===================================================================
--- binaries/data/mods/public/simulation/components/GarrisonHolder.js	(revision 18179)
+++ binaries/data/mods/public/simulation/components/GarrisonHolder.js	(working copy)
@@ -1,3 +1,6 @@
+/**
+ * @class Defines an entity's ability to garrison units.
+ */
 function GarrisonHolder() {}
 
 GarrisonHolder.prototype.Schema =
@@ -45,6 +48,14 @@
 						"<element name='Z'>" +
 							"<data type='decimal'/>" +
 						"</element>" +
+						"<optional>" +
+							"<element name='VisibleGarrisonAllowedClasses'>" +
+								"<attribute name='datatype'>" +
+									"<value>tokens</value>" +
+								"</attribute>" +
+								"<text/>" +
+							"</element>" +
+						"</optional>" +
 					"</interleave>" +
 				"</element>" +
 			"</zeroOrMore>" +
@@ -72,7 +83,7 @@
 			o.x = +offset.X;
 			o.y = +offset.Y;
 			o.z = +offset.Z;
-			this.visibleGarrisonPoints.push({"offset":o, "entity": null});
+			this.visibleGarrisonPoints.push({ "offset": o, "entity": null, "allowedClass": offset.VisibleGarrisonAllowedClasses });
 		}
 	}
 };
@@ -100,7 +111,6 @@
 	return IsOwnedByPlayer(player, ent);
 };
 
-
 /**
  * Return the list of entities garrisoned inside
  */
@@ -204,6 +214,19 @@
 };
 
 /**
+ * Returns true if the unit is allowed be visible on that garrison point, false otherwise.
+ */
+GarrisonHolder.prototype.AllowedToVisibleGarrisoning = function(visibleGarrisonPoint, entity)
+{
+	let allowedClassesList = visibleGarrisonPoint.allowedClass._string;
+	// If classlist is empty, everybody can garrison.
+	if (!allowedClassesList) 
+		return true; 
+	
+	return MatchesClassList(Engine.QueryInterface(entity, IID_Identity).GetClassesList(), allowedClassesList);
+};
+
+/**
  * Garrison a unit inside.
  * Returns true if successful, false if not
  * The timer for AutoHeal is started here
@@ -225,12 +248,14 @@
 		{
 			if (vgp.entity)
 				continue;
-			visibleGarrisonPoint = vgp;
-			break;
+			if (this.AllowedToVisibleGarrisoning(vgp, entity))
+			{
+				visibleGarrisonPoint = vgp;
+				break;
+			}
 		}
 	}
-
-	if (visibleGarrisonPoint)
+	if (visibleGarrisonPoint && this.AllowedToVisibleGarrisoning(visibleGarrisonPoint, entity))
 	{
 		visibleGarrisonPoint.entity = entity;
 		cmpPosition.SetTurretParent(this.entity, visibleGarrisonPoint.offset);
@@ -241,9 +266,21 @@
 	else
 		cmpPosition.MoveOutOfWorld();
 
+	let visible = {};
+	visible[entity] = this.IsVisiblyGarrisoned(entity);
+	// Should only be called after the garrison has been performed else the visible Garrison Points are not updated yet.
+	Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
+		"added": [entity],
+		"removed": [],
+		"visible": visible
+	});
 	return true;
 };
 
+/**
+ * Garrison units inside the entity
+ * @return true if successful, false if not
+ */
 GarrisonHolder.prototype.PerformGarrison = function(entity)
 {
 	if (!this.HasEnoughHealth())
@@ -250,10 +287,10 @@
 		return false;
 
 	// Check if the unit is allowed to be garrisoned inside the building
-	if(!this.AllowedToGarrison(entity))
+	if (!this.AllowedToGarrison(entity))
 		return false;
 
-	// check the capacity
+	// Check the capacity
 	var extraCount = 0;
 	var cmpGarrisonHolder = Engine.QueryInterface(entity, IID_GarrisonHolder);
 	if (cmpGarrisonHolder)
@@ -278,8 +315,6 @@
 	if (cmpAura && cmpAura.HasGarrisonAura())
 		cmpAura.ApplyGarrisonBonus(this.entity);
 
-	Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [entity], "removed": [] });
-
 	var cmpUnitAI = Engine.QueryInterface(entity, IID_UnitAI);
 	if (cmpUnitAI && cmpUnitAI.IsUnderAlert())
 		Engine.PostMessage(cmpUnitAI.GetAlertRaiser(), MT_UnitGarrisonedAfterAlert, {"holder": this.entity, "unit": entity});
@@ -326,7 +361,15 @@
 
 	var cmpNewPosition = Engine.QueryInterface(entity, IID_Position);
 	this.entities.splice(entityIndex, 1);
-
+	
+	let visible = {};
+	visible[entity] = this.IsVisiblyGarrisoned(entity);
+	// Should only be called before the ejection has been performed else the visible Garrison Points will be empty.
+	Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
+		"added": [],
+		"removed": [entity],
+		"visible": visible
+	});
 	for (var vgp of this.visibleGarrisonPoints)
 	{
 		if (vgp.entity != entity)
@@ -356,7 +399,6 @@
 	cmpNewPosition.SetHeightOffset(0);
 	// TODO: what direction should they face in?
 
-	Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [], "removed": [entity] });
 
 	return true;
 };
@@ -597,8 +639,9 @@
  */
 GarrisonHolder.prototype.OnGlobalOwnershipChanged = function(msg)
 {
+	let msgEntity = msg.entity;
 	// the ownership change may be on the garrisonholder
-	if (this.entity == msg.entity)
+	if (this.entity == msgEntity)
 	{
 		var entities = [];
 		for each (var entity in this.entities)
@@ -612,28 +655,36 @@
 	}
 
 	// or on some of its garrisoned units
-	var entityIndex = this.entities.indexOf(msg.entity);
+	let entityIndex = this.entities.indexOf(msgEntity);
 	if (entityIndex != -1)
 	{
 		// If the entity is dead, remove it directly instead of ejecting the corpse
-		var cmpHealth = Engine.QueryInterface(msg.entity, IID_Health);
+		let cmpHealth = Engine.QueryInterface(msgEntity, IID_Health);
 		if (cmpHealth && cmpHealth.GetHitpoints() == 0)
 		{
 			this.entities.splice(entityIndex, 1);
-			Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [], "removed": [msg.entity] });
+			let visible = {};
+			visible[msgEntity] = this.IsVisiblyGarrisoned(msgEntity);
+			Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, {
+				"added": [],
+				"removed": [msgEntity],
+				"visible": visible
+			});
 			this.UpdateGarrisonFlag();
 
 			for (var pt of this.visibleGarrisonPoints)
-				if (pt.entity == msg.entity)
+				if (pt.entity == msgEntity)
 					pt.entity = null;
 		}
-		else if (msg.to == -1 || !IsOwnedByMutualAllyOfEntity(this.entity, msg.entity))
-			this.EjectOrKill([msg.entity]);
+		else if (msg.to == -1 || !IsOwnedByMutualAllyOfEntity(this.entity, msgEntity))
+			this.EjectOrKill([msgEntity]);
 	}
 };
 
 /**
  * Update list of garrisoned entities if one gets renamed (e.g. by promotion)
+ * vgpEntity is only defined in some peculiar case where we want to reuse the same visibleGarrisonPoint,
+ * in case of promotion for example, and thus should always be allowed. 
  */
 GarrisonHolder.prototype.OnGlobalEntityRenamed = function(msg)
 {
@@ -670,7 +721,6 @@
 	}
 };
 
-
 /**
  * Eject all foreign garrisoned entities which are no more allied
  */
@@ -687,7 +737,7 @@
 GarrisonHolder.prototype.EjectOrKill = function(entities)
 {
 	var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
-	// Eject the units which can be ejected (if not in world, it generally means this holder
+	// Eject the units which can be ejected (if not in world, it often means this holder
 	// is inside a holder which kills its entities, so do not eject)
 	if (cmpPosition.IsInWorld())
 	{
@@ -710,13 +760,31 @@
 		this.entities.splice(entityIndex, 1);
 		killedEntities.push(entity);
 	}
-
 	if (killedEntities.length > 0)
-		Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { "added" : [], "removed" : killedEntities });
+	{
+		let visibleEntitiesIds = {};
+		for (let ent of killedEntities)
+			visibleEntitiesIds[ent] = this.IsVisiblyGarrisoned(ent);
+		Engine.PostMessage(this.entity, MT_GarrisonedUnitsChanged, { 
+			"added": [], 
+			"removed": killedEntities,
+			"visible": visibleEntitiesIds
+		});
+	}
 	this.UpdateGarrisonFlag();
 };
 
 /**
+ * Gives insight about the unit type of garrisoning.
+ * @return{bool} returns true if the unit is visible on the structure
+ * @param {int} the entity's id
+ */
+GarrisonHolder.prototype.IsVisiblyGarrisoned = function(entity)
+{
+	return this.visibleGarrisonPoints.some(point => point.entity == entity);
+};
+
+/**
  * Checks if an entity is ejectable on destroy if possible
  */
 GarrisonHolder.prototype.IsEjectable = function(entity)
