I have 3 projects. 1 works but I want to refactor and use an asset from Unity store.
2nd project is the asset only with my mission system modified/merged to work with the asset and it works fine. Awesome.
So the 3rd project is the one I need to work, it is my original project with the asset imported in.
The issue I am having is the mission system, for some reason the ApplicationManager instance is not being seen inside the itempickup used like "ApplicationManager.instance" BUT it works in the 2nd project, they are literal copy/paste and no idea why it is not seen?
error CS0103: The name 'ApplicationManager' does not exist in the current context
EDIT:
It seems only the assets scripts are not seeing the ApplicationManager, I tested with my other scripts and they see it just fine, not sure what to look at to get them to work in this project since they work in the 2nd project fine.
EDIT 2: So it seems it simething about how he made the asset. If I move the AppMan to HIS folder labeled PickUp (for items) it now sees the script. How the &(* do I remove or fix that restriction?? Never seen it before. Once I move it to that folder all my other scripts now lose the reference.
Application manager:
public class ApplicationManager : MonoBehaviour
{
private static ApplicationManager _Instance = null;
public static ApplicationManager instance
{
get
{
// If we don't have an instance yet find it in the scene hierarchy
if (_Instance == null)
{
_Instance = (ApplicationManager)FindObjectOfType(typeof(ApplicationManager));
}
// Return the instance
return _Instance;
}
}
}
And the Itempickup:
public abstract class ItemPickupBase : Interactable
{
[SerializeField]
protected List<GameState> _setOnCollect = new List<GameState>();
protected void PickUpItem(ICharacter character, IItem item, bool playPickUpSound = true)
{
if (item == null)
{
Debug.LogError("Item Instance is null, can't pick up anything.");
return;
}
int addedCount = 0;
int originalCount = item.StackCount;
string rejectReason = string.Empty;
if (m_AddType == AddType.AddToMatchingContainer)
{
var containers = character.Inventory.GetContainersWithTag(item.Definition.Tag);
foreach (var container in containers)
{
if (container.GetAllowedCount(item, item.StackCount, out rejectReason) > 0)
addedCount += container.AddItem(item);
if (addedCount == originalCount)
break;
}
if (originalCount > 1)
item.StackCount = originalCount - addedCount;
}
if (addedCount != originalCount)
{
var containers = character.Inventory.Containers;
foreach (var container in containers)
{
if (container.GetAllowedCount(item, item.StackCount, out rejectReason) > 0)
addedCount += container.AddItem(item);
if (addedCount == originalCount)
break;
}
}
if (addedCount > 0)
{
string pickupUpMessage = $"Pickup up {item.Name}";
if (addedCount > 1)
pickupUpMessage += $" x {addedCount}";
MessageDisplayerUI.PushMessage(pickupUpMessage, item.Definition.Icon);
if (playPickUpSound)
m_PickUpSound.Play2D(1f, SelectionType.Random);
if (addedCount >= originalCount)
if (ApplicationManager.instance && _setOnCollect.Count > 0)
{
foreach (GameState state in _setOnCollect)
{
ApplicationManager.instance.SetGameState(state.Key, state.Value);
}
}
Destroy(gameObject);
}
else
{
MessageDisplayerUI.PushMessage(rejectReason != string.Empty ? rejectReason : "Inventory Full", Color.red);
}
}
}
Not sure what to try since this is almost a literal copy/paste from the original and it is not working. The only difference I can see is the ItemPickup in the 2nd project is a public class and the one I am having issues with is a public abstract class.
But when I try to access the ApplicationManager in another script it still does not see it so I figured that was not the issue.
Related
I'm trying to write a script in space-engineers, and I have a collection of a class _Filter, which resides inside of another class _Inventory. Here is the code that I'm trying to execute:
public void InventorySetup(_Inventory inventory)
{
if (inventory.InvBlock != null) // Check if block exists
{
string[] data = inventory.InvBlock.CustomData.Split('\n'); // Break customData into lines
foreach (string nextline in data) // Iterate each line
{
if (nextline.Length > 0) // Line must contain information
{
string[] lineblocks = nextline.Split(' '); // Break each line into blocks
if (lineblocks.Length > 1) // There must be more than one block to have filter candidate and desired update
{
string[] itemID = new string[2];
if (lineblocks[0].Contains(":"))
itemID = lineblocks[0].Split(':'); // split the type from subType
else if (lineblocks[0].Contains("!"))
itemID = new string[] { "", "" };
else
itemID = new string[] { "null", "null" };
foreach (_Filter nextFilter in inventory.Filters)
{
if (ContainsCIS(nextFilter.ItemType, itemID[0]) && ContainsCIS(nextFilter.ItemSubType, itemID[1]))
{
for (int i = 1; i < lineblocks.Length; i++)
{
switch (lineblocks[i][0])
{
case '#':
nextFilter.Target = (MyFixedPoint)float.Parse(lineblocks[i].Replace('#', ' '));
break;
case '+':
if (ContainsCIS(lineblocks[i], "in"))
nextFilter.IN_BOUND = true;
if (ContainsCIS(lineblocks[i], "out"))
nextFilter.OUT_BOUND = true;
break;
case '-':
if (ContainsCIS(lineblocks[i], "in"))
// nextFilter.IN_BOUND = false;
if (ContainsCIS(lineblocks[i], "out"))
nextFilter.OUT_BOUND = false;
break;
}
}
}
}
}
if (nextline[0] == '&')
{
if (ContainsCIS(nextline, "empty"))
{
if (nextline.Contains("-"))
inventory.EMPTY = false;
else
inventory.EMPTY = true;
}
if (ContainsCIS(nextline, "fill"))
{
if (nextline.Contains("-"))
inventory.FILL = false;
else
inventory.FILL = true;
}
if (ContainsCIS(nextline, "active"))
{
if (nextline.Contains("-"))
inventory.ACTIVE = false;
else
inventory.ACTIVE = true;
}
if (ContainsCIS(nextline, "clean"))
{
if (nextline.Contains("-"))
inventory.CLEAN = false;
else
inventory.CLEAN = true;
}
if (ContainsCIS(nextline, "reset"))
inventory.Reset();
}
}
}
}
}
So basically what's going on, there's a member within the _Inventory class that refers directly to the block who's inventory I'm trying to configure. This member has it's own member called CustomData, which is a string object that can be edited in game. So I split it into an array of each line, and then process each line based on the contextual nature of each.
First, the line gets broken up into "blocks" by once again splitting each line by a space character, and then analyzing further. If the number of blocks is greater than 1, this means there is an expected "target filter" and some sort of following qualifier. Either a change to its white-list/black-list setting, or a change to the target maximum value (0 means no limit and is the default value for this member).
Now the _Inventory class already contains a pre-existing collection of _Filter class, and merely updates the members of it by means of iteration. So for example, if I want to black-list "IN_BOUND" ores, I would add the line "ore: -in". or if I want to black-list out bound steel plates, ":steelplate -out".
(a name before the colon depicts the category, and one after the colon, the specific type of item. Exclamation mark means all items in the collection). The ContainCIS() method is something I made simply to search for a contained string "Case In-Sensitively". Besides changing filters, the _Inventory class also possesses a few bool members for controlling desired functionality. They are self-named EMPTY, FILL, ACTIVE, CLEAN (the clean bool has to do with production blocks that sometimes get stuffed with the wrong materials, non-relevant to my problem)
My actual problem:
When this code is called, if I only have a single _Inventory in the root collection, everything works out fine. HOWEVER, if I have more than one, the bools are updated normally, but the filters GET UPDATED IN REVERSE ORDER.
So say for example I have _Inventory A, and _Inventory B. If I add the line to the custom data of the block that is referred to by "A", then the correct bool changes. But if I change a filter setting on "A", it updates to "B" instead.
EDIT:
Here's the classes and the method which calls the InventorySetup():
public class _Inventory
{
public IMyTerminalBlock InvBlock;
public _BlockType BlockType; // Cargo, Assembler, Refinery
public _Filter[] Filters; // Expected inventory candidates (Refer to _Filter libraries)
public bool FILL; // Attempt fill action on all IN_BOUND "true" candidates
public bool EMPTY; // Attempt empty action on all OUT_BOUND "true" candidates
public bool ACTIVE; // Actively being manipulated by program ("Use conveyor system" property will be disabled on prod. blocks)
public bool CLEAN; // Actively clear overburdened assembler inputs, or un-scheduled refinery inputs (not used for cargos)
public _Inventory(IMyTerminalBlock invBlock, _BlockType blockType, _Filter[] filters, bool active = true)
{
InvBlock = invBlock;
BlockType = blockType;
Filters = filters;
FILL = false;
EMPTY = false;
ACTIVE = active;
CLEAN = true;
}
public void Reset()
{
foreach (_Filter nextFilter in Filters)
{
nextFilter.Target = 0;
nextFilter.IN_BOUND = true;
nextFilter.OUT_BOUND = true;
}
}
}
public class _Filter
{
public string ItemType;
public string ItemSubType;
public MyFixedPoint Target;
public int Priority;
public bool IN_BOUND;
public bool OUT_BOUND;
public _Filter(string itemType = "null")
{
ItemType = itemType.Split(':')[0];
ItemSubType = itemType.Split(':')[1];
Target = 0; // 0 means no target value, any amount aloud
Priority = 0; // Priority for in-bound requests (WIP)
IN_BOUND = true; // Default to whitelist items in & out of inventory
OUT_BOUND = true;
}
}
public void InventoryListUpdate()
{
Inventories.RemoveAll(x => x.InvBlock == null);
Inventories.RemoveAll(x => !x.InvBlock.CustomName.Contains(Signature));
foreach (IMyCargoContainer nextCargo in Cargos)
{
if (Inventories.FindIndex(x => x.InvBlock == nextCargo) < 0 && nextCargo.CustomName.Contains(Signature))
Inventories.Add(new _Inventory((IMyTerminalBlock)nextCargo, _BlockType.CARGO, FullLibrary));
}
foreach (IMyRefinery nextRefinery in Refineries)
{
if (Inventories.FindIndex(x => x.InvBlock == nextRefinery) < 0 && nextRefinery.CustomName.Contains(Signature))
Inventories.Add(new _Inventory((IMyTerminalBlock)nextRefinery, _BlockType.ASSEMBLER, RefineryLibrary));
}
foreach (IMyAssembler nextAssembler in Assemblers)
{
if (Inventories.FindIndex(x => x.InvBlock == nextAssembler) < 0 && nextAssembler.CustomName.Contains(Signature))
Inventories.Add(new _Inventory((IMyTerminalBlock)nextAssembler, _BlockType.ASSEMBLER, AssembleLibrary, false));
}
foreach (_Inventory nextInventory in Inventories)
{
if (bInventoryRunning && nextInventory.ACTIVE)
InventoryUpdate(nextInventory);
else
InventorySetup(nextInventory);
}
}
So when I started up the code in space engineers today, it suddenly started to work as intended... I have absolutely no idea how or why. I'm leaning towards a memory leak issue related to how the game handles its in-game scripts, however there is the slight possibility that cleaning the code up somehow "massaged" it to do as intended. As I stated before, it was behaving as expected to some degree, it just had un-expected behaviour as the higher collection grew in size. Since each _Inventory was being worked on individually, there should have been no way for its members to get transposed onto another, unless some weird GC-voodoo was happening in the background. As comforting as it is to have my script running properly, it's an even worse feeling knowing I may never find out why it was messing up in the first place, as I have no real solid grounding from which to avoid this problem in the future. Thankyou all for your input.
I know it's been awhile since I posted this, but I feel like I have a responsibility to bring further conclusions to the issue I was having. I only just realized that the problem revolved around a particular class array that I had added to the container class. The _Filter[] within _Inventory, had been passed by reference, rather than being "cloned", something I have just recently become aware of, so every time each individual _Inventory object was being iterated through, their contained arrays were all pointing to the same thing. I have managed to find a way to properly clone each element from the original libraries as needed.
I need to list the romos there are in my lobby scene. For now, this is the code I've used but I don't know why it isnt working. Is this the correct way?
public override void OnRoomListUpdate(List<RoomInfo> roomList)
{
print(roomList.Count + " Rooms");
base.OnRoomListUpdate(roomList);
foreach (var Item in roomList)
{
RoomName = Item.Name;
PlayerAmount = Item.PlayerCount;
MaxPlayers = Item.MaxPlayers;
PhotonNetwork.Instantiate("RoomPrefab", transform.position, transform.rotation);
RoomPrefab.transform.Find("RoomName").GetComponent<Text>().text = RoomName;
RoomPrefab.transform.Find("PlayerInt").GetComponent<Text>().text = PlayerAmount.ToString();
if(MaxPlayers == 4)
{
GameObject.Find("IPlayerA").GetComponent<Image>().sprite = Four;
}
else if (MaxPlayers == 2)
{
GameObject.Find("IPlayerA").GetComponent<Image>().sprite = Two;
}
else if (MaxPlayers == 3)
{
GameObject.Find("IPlayerA").GetComponent<Image>().sprite = Three;
}
RoomPrefab.transform.SetParent(ScrollView.transform, false);
}
}
I need to specify that I'm using Photon's PUN2, so GetRoomList won't work.
PhotonNetwork.GetRoomList() is gone in PUN2. You get rooms list and updates from ILobbyCallbacks.OnRoomListUpdate(List roomList) callback. You can optionally cache it, update it and clear it when needed.
Also you can check updates from PUN to PUN2 here
https://doc.photonengine.com/en-us/pun/v2/getting-started/migration-notes
The OnRoomListUpdate() method is called only when you've explicitly joined the lobby via PhotonNetwork.JoinLobby(). It's not enough just to be connected to the MasterServer as Jevgeni Geurtsen suggested, at least in PUN v2.15 it works this way for me.
A previously working Dictionary foreach loop is now suddenly broken (shown below). The dictionary stores data in the form of a struct, and is sorted/indexed based on a custom enum.
Previously it was working fine. Upon inspection/breakpoints, the data does exist/IS there, however Unity/C#/Something doesn't seem to be able to see the data suddenly.
There is no modification to that data in the foreach loop, the purpose is to simply determine if a List parameter in each struct is empty or not and set a boolean.
I'm at a total loss as to why this is happening, or what could cause it, so any suggestions is appreciated.
Original Class
TargetController.UpdateSensesListData();
foreach(KeyValuePair<Controller.TypeEnum, Controller.DataStruct> list in TargetController.SensesList)
{
if(list.Value.objects.Count > 0)
{
booleanVar = true;
break;
}
}
Controller Class
public class DataStruct
{
public int priority;
public Senses thisSense;
public List<GameObject> objects = new List<GameObject>();
}
public void Start()
{
//SensesPriorityList is set in the Unity Inspector. Its simply a list
// of the TypeEnums that are used as keys for the dictionary.
if(SensesPriorityList.count > 0)
{
for(int i = 0; i < SensesPriorityList.Count; i++)
{
DataStruct data = new DataStruct
{
priority = i,
sense = Getsense(SensesPriorityList[i]),
objects = new List<GameObject>()
};
SensesList.Add(SensesPriorityList[i], data);
}
}
}
public void UpdateSensesListData()
{
foreach(KeyValuePair<TypeEnum, DataStruct> sense in SensesList)
{
if(sense.Value.sense != null)
sense.Value.Objects = sense.Value.sense.UpdateSense();
if(sense.Value.objects.Count > 0)
break;
}
}
In the above example, "DictionaryVariable" DOES have data (is not null), and the second item in the dictionary has data (the count > 0) so it should for all intents and purposes be setting the bool to true. but its not. When I looked, list reads as "Null" (but upon closer inspection, the dictionary is not null, but rather the OtherClass.Struct data is null - when it is not)
I am working on C# add-ins in Enterprise Architect to give a restriction to user so that only a particular child element can be added to a specific parent element.
For example if child element A must be dropped on parent element B it is deleted if child element A is dragged and dropped on parent element C. I am using EA_OnPostNewElement method and a delete method for the same and it works fine.
My doubt is, after the user has dropped the child element on the specific parent, after some time he can drag the child element outside the parent element and add it as a child to any other element in the diagram.
Is there a way to add a restriction here by observing the changes made by user on Enterprise architect GUI and bring back the child element to original parent location. Kindly help.
You need to use both EA_OnContextItemChanged and EA_OnNotifyContextItemModified so you can achieve it .
declare a dictonry
public Dictionary<int, int> lstChildElements = new Dictionary<int, int>();
and here is the sample code
public void EA_OnContextItemChanged(EA.Repository Repository, string GUID, EA.ObjectType ot)
{
EA.Element addedElement = Repository.GetElementByGuid(GUID);
if (addedElement == null)
return;
int identifiedParentID = 0;
bool isAvailable = lstChildElements.TryGetValue(addedElement.ElementID, out identifiedParentID);
if (!isAvailable)
{
if (addedElement.Stereotype == "Child" && addedElement.ParentID != 0)
{
EA.Element parentElemnt = Session.Repository.GetElementByID(addedElement.ParentID);
if (parentElemnt != null)
if (parentElemnt.Stereotype == "anyCustomDefined")
lstChildElements.Add(addedElement.ElementID, addedElement.ParentID);
}
}
}
public void EA_OnNotifyContextItemModified(EA.Repository Repository, string GUID, EA.ObjectType ot)
{
EA.Element addedElement = Repository.GetElementByGuid(GUID);
if (addedElement == null)
return;
int identifiedParentID = 0;
bool isAvailable = lstChildElements.TryGetValue(addedElement.ElementID, out identifiedParentID);
if (isAvailable)
{
if (addedElement.Stereotype == "Child" && addedElement.ParentID != 0)
{
EA.Element parentElemnt = Repository.GetElementByID(addedElement.ParentID);
if (parentElemnt != null)
if (parentElemnt.Stereotype != "anyCustomDefined")
{
addedElement.ParentID = identifiedParentID != 0 ? identifiedParentID : addedElement.ParentID;
addedElement.Update();
lstChildElements[addedElement.ElementID] = addedElement.ParentID;
}
}
else if (addedElement.Stereotype == "Child" && addedElement.ParentID == 0)
{
addedElement.ParentID = identifiedParentID;
addedElement.Update();
}
}
}
Hope it helps..!
and for updating in diagram need to reload it.
EA.Diagram activeDiagram = Session.Repository.GetCurrentDiagram();
if (activeDiagram != null)
Session.Repository.ReloadDiagram(activeDiagram.DiagramID);
or
Repository.RefreshOpenDiagrams();
Both the codes can be used for reloading the diagram.
You can use the context events to keep track of the selected element and it's owner.
I'm not sure if the event EA_OnNotifyContextItemModified is being fired when you change the owner of an element.
But even it that is not the case you can verify if it still has the same owner after a new element has been selected.
I am currently translating old generated C# code which is full of goto. Please dont comment on that, I know its horrible.
Anyway, is there a way / extension / whatever to make goto-statements more readable? Its a pain to find the place where the code jumps to. I dont want to use the search-function since it makes me lose my orientation.
All I found is this:
http://visualstudiogallery.msdn.microsoft.com/4b286b9c-4dd5-416b-b143-e31d36dc622b
and it doesnt work.
Can you recommend anything?
A bit late maybe, but you can build your own using Visual Studio Extensibility (and therefore add custom behavior as well): Inside the Editor: Tags and Classifier. The steps are:
1) Create an Editor Classifier project (builtin project type)
2) Delete the existing class files
3) Add the code below. It will colorize all 'goto' statements in code portions in red:
internal class GotoTagger : ITagger<GotoTag>
{
private ITextSearchService _textSearchService;
private ITextStructureNavigator _textStructureNavigator;
event EventHandler<SnapshotSpanEventArgs> ITagger<GotoTag>.TagsChanged { add { } remove { } }
public GotoTagger(ITextSearchService textSearchService, ITextStructureNavigator textStructureNavigator)
{
_textSearchService = textSearchService;
_textStructureNavigator = textStructureNavigator;
}
public IEnumerable<ITagSpan<GotoTag>> GetTags(NormalizedSnapshotSpanCollection spans)
{
if (spans.Count == 0)
yield break;
if (spans.Count > 0)
{
// look for 'goto' occurrences
foreach (SnapshotSpan span in _textSearchService.FindAll(new FindData("goto", spans[0].Snapshot, FindOptions.WholeWord | FindOptions.MatchCase, _textStructureNavigator)))
{
yield return new TagSpan<GotoTag>(span, new GotoTag());
}
}
}
}
[Export(typeof(IViewTaggerProvider))]
[TagType(typeof(TextMarkerTag))]
[ContentType("code")] // only for code portion. Could be changed to csharp to colorize only C# code for example
internal class GotoTaggerProvider : IViewTaggerProvider
{
[Import]
internal ITextSearchService TextSearchService { get; set; }
[Import]
internal ITextStructureNavigatorSelectorService TextStructureNavigatorSelector { get; set; }
public ITagger<T> CreateTagger<T>(ITextView textView, ITextBuffer buffer) where T : ITag
{
if (textView.TextBuffer != buffer)
return null;
return new GotoTagger(TextSearchService, TextStructureNavigatorSelector.GetTextStructureNavigator(buffer)) as ITagger<T>;
}
}
internal class GotoTag : TextMarkerTag
{
public GotoTag() : base("goto") { }
}
[Export(typeof(EditorFormatDefinition))]
[Name("goto")]
[UserVisible(true)]
internal class GotoFormatDefinition : MarkerFormatDefinition
{
public GotoFormatDefinition()
{
BackgroundColor = Colors.Red;
ForegroundColor = Colors.White;
DisplayName = "Goto Word";
ZOrder = 5;
}
}
You can consider DevExpress CodeRush. goto statements will get an arrow like this: . Hovering over the arrow highlights the statement following the label (if it's already visible), and clicking it makes it visible and moves the cursor to that statement.
Try ReSharper's Navigate to function exits.
Or Coderush's flow break icons
Also note, that you can use "Ctrl" + "-" to jump back to the last place in the code, you were looking at.
This is probably very obvious, but it seemed to me like CSharpie might be unaware of this hotkey.