|
Presumably "client" in this case means a specific box under your control and one that remains under your control. It will not ever be one that a customer uses. Nor does it represent a test box as a stand in for multiple customers.
If so...
You log into the client machine.
Then see if you can access that path.
If not then determine the exact permissions needed, both on the client box and the server box to access that path.
Then you figure out what user the application is running on the client box and you set up the permissions for that user.
If this is intended to run on customer machines (boxes outside of your control of any sort) then you need a different design. You need to 'deliver' the report as a file to any standard idiom just like you would for any internet web content. I believe Crystal reports supports such a mechanism but it does require setting up the server that way. Then the client app would need to retrieve the report (just like getting any other web file) and display it (just like displaying any other web file.)
Alternatively you use a different web server and deliver the file into that web server. And then the same process occurs (get the web file and display it.)
|
|
|
|
|
Hi,
I have a small WPF application which gets some data (~300 rows) from an API and gets displayed in a DataGrid. Up to this point everything works well. Some Header-columns of the DataGrid have nested textboxes, which should serve as search-boxes. I bound their text to a property in my ViewModel and wrote a filter for the CollectionView. If I enter a filter-text everything is okay and I get the result I expect. The problem appears when I try to remove my filter-text again. When I want to remove the last character from the text-box the UI freezes for a few seconds. I think this comes from loading all the rows into the DataGrid again. Has anyone faced this problem as well?
Thanks for your help in advance!
|
|
|
|
|
Based on no code and a vague problem description:
300 rows is trivial once they're in memory. How are you "loading again"? Going back to the "API"?
Since your filter seems to be tied to a keyboard handler, I would look at that. Maybe you need a clearer "Apply / Clear (filter)" function.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
As a suggestion
Identify the columns that actually need filtering
Move the filter entry from the headers to textboxes above the datagrid
Apply/clear the filter via a command button(s)
This divorces the filtering process from the datagrid, allows you to apply the filter to the underlying data in the VM rather than relying on the binding to the header textboxes. You will also apply the filter once (when the user clicks the command button) rather than every time the header textboxes change content.
Never underestimate the power of human stupidity -
RAH
I'm old. I know stuff - JSOP
|
|
|
|
|
Hello
I am making WMI queries to remote computers that are in our production hall. The first connection with ManegementScope takes realy long. If the first connection is done the next connection is then much faster. How can i speed up this connection time. That's the code i am using:
public void WMI_Connect()
{
System.Management.ConnectionOptions options = new System.Management.ConnectionOptions();
options.Username = "user";
options.Password = "password";
WMI_path = "\\\\" + MAE_Selection.MAE_IP_PCU + "\\root\\cimv2";
ManagementScope scope = new ManagementScope(WMI_path, options);
try
{
// Start WMIconnect
scope.Connect();
// WMI Connection done (8-10 seconds)
// The method in that i am doing the WMI queries
Read_General_Data_WMI();
}
catch (Exception ex)
{
using (StreamWriter sw = File.AppendText((Start.error_path)))
{
sw.WriteLine(ex);
WMI_Con_State = "Connection_failed";
}
}
}
|
|
|
|
|
Pre-load it 10 seconds before you need it.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
"Once and Future Computing" again?
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Hi, thanks for answer
Yes, i am doing actualy as you suggest. But the problem is, if i want to make WMI connections to several remote PCs, just the connection taking 10 seconds. Is it really not possible to shorten it?
|
|
|
|
|
Nope. There's no way to speed that up.
|
|
|
|
|
Sorry if this is the wrong place to ask or post is too long. I've studied examples and read up on factory design, factory pattern, abstract factory, & factory method; I followed a tutorial for a c# wpf rpg game that works well. But I'd like to enhance and expand on it so that I can understand the fundamentals of c# and object-oriented programming. There are seven factories in the game, for example. The factories I have in-game are an item factory, a Quest factory, a recipe factory, a monster factory, a spell factory, a trader factory, and a world factory. Is it possible to implement an abstract factory that combines all the factories? Would keeping them separate be best? Thank you for any assistance you may provide as well as any feedback you provide to.
here are the factories.
Itemfactory.cs
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Engine.Actions;
using Engine.Models;
using Engine.Shared;
using SOSCSRPG.Core;
namespace Engine.Factories
{
public static class ItemFactory
{
private const string GAME_DATA_FILENAME =
".\\GameData\\GameItems.xml";
private static readonly List<GameItem> _standardGameItems = new
List<GameItem>
();
static ItemFactory()
{
if(File.Exists(GAME_DATA_FILENAME))
{
XmlDocument data = new XmlDocument();
data.LoadXml(File.ReadAllText(GAME_DATA_FILENAME));
LoadItemsFromNodes(data.SelectNodes("/GameItems/Weapons/Weapon"));
LoadItemsFromNodes(data.SelectNodes("/GameItems/HealingItems/HealingItem"));
LoadItemsFromNodes(data.SelectNodes("/GameItems/MiscellaneousItems/MiscellaneousItem"));
}
else
{
throw new FileNotFoundException($"Missing data file:
{GAME_DATA_FILENAME}");
}
}
public static GameItem CreateGameItem(int itemTypeID)
{
return _standardGameItems.FirstOrDefault(item =>
item.ItemTypeID ==
itemTypeID)?.Clone();
}
private static void LoadItemsFromNodes(XmlNodeList nodes)
{
if(nodes == null)
{
return;
}
foreach(XmlNode node in nodes)
{
GameItem.ItemCategory itemCategory =
DetermineItemCategory(node.Name);
GameItem gameItem =
new GameItem(itemCategory,
node.AttributeAsInt("ID"),
node.AttributeAsString("Name"),
node.AttributeAsInt("Price"),
itemCategory ==
GameItem.ItemCategory.Weapon);
if(itemCategory == GameItem.ItemCategory.Weapon)
{
gameItem.Action =
new AttackWithWeapon(gameItem,
node.AttributeAsString("DamageDice"));
}
else if(itemCategory ==
GameItem.ItemCategory.Consumable)
{
gameItem.Action =
new Heal(gameItem,
node.AttributeAsInt("HitPointsToHeal"));
}
_standardGameItems.Add(gameItem);
}
}
private static GameItem.ItemCategory
DetermineItemCategory(string itemType)
{
switch(itemType)
{
case "Weapon":
return GameItem.ItemCategory.Weapon;
case "HealingItem":
return GameItem.ItemCategory.Consumable;
default:
return GameItem.ItemCategory.Miscellaneous;
}
}
}
}
MonsterFactory.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Engine.Models;
using Engine.Services;
using Engine.Shared;
using SOSCSRPG.Core;
namespace Engine.Factories
{
public static class MonsterFactory
{
private const string GAME_DATA_FILENAME =
".\\GameData\\Monsters.xml";
private static readonly GameDetails s_gameDetails;
private static readonly List<Monster> s_baseMonsters = new
List<Monster>();
static MonsterFactory()
{
if(File.Exists(GAME_DATA_FILENAME))
{
s_gameDetails =
GameDetailsService.ReadGameDetails();
XmlDocument data = new XmlDocument();
data.LoadXml(File.ReadAllText(GAME_DATA_FILENAME));
string rootImagePath =
data.SelectSingleNode("/Monsters")
.AttributeAsString("RootImagePath");
LoadMonstersFromNodes(data.SelectNodes("/Monsters/Monster"),
rootImagePath);
}
else
{
throw new FileNotFoundException($"Missing data
file:
{GAME_DATA_FILENAME}");
}
}
public static Monster GetMonsterFromLocation(Location
location)
{
if (!location.MonstersHere.Any())
{
return null;
}
location.
int totalChances = location.MonstersHere.Sum(m =>
m.ChanceOfEncountering);
(in case the total
chances is not 100).
int randomNumber =
DiceService.Instance.Roll(totalChances, 1).Value;
to the
runningTotal
variable.
runningTotal,
int runningTotal = 0;
foreach (MonsterEncounter monsterEncounter in
location.MonstersHere)
{
runningTotal += monsterEncounter.ChanceOfEncountering;
if (randomNumber <= runningTotal)
{
return GetMonster(monsterEncounter.MonsterID);
}
}
list.
return GetMonster(location.MonstersHere.Last().MonsterID);
}
private static void LoadMonstersFromNodes(XmlNodeList nodes,
string
rootImagePath)
{
if(nodes == null)
{
return;
}
foreach(XmlNode node in nodes)
{
var attributes = s_gameDetails.PlayerAttributes;
attributes.First(a => a.Key.Equals("DEX")).BaseValue =
Convert.ToInt32(node.SelectSingleNode("./Dexterity").InnerText);
attributes.First(a =>
a.Key.Equals("DEX")).ModifiedValue =
Convert.ToInt32(node.SelectSingleNode("./Dexterity").InnerText);
Monster monster =
new Monster(node.AttributeAsInt("ID"),
node.AttributeAsString("Name"),
$".{rootImagePath}
{node.AttributeAsString("ImageName")}",
node.AttributeAsInt("MaximumHitPoints"),
attributes,
ItemFactory.CreateGameItem(node.AttributeAsInt("WeaponID")),
node.AttributeAsInt("RewardXP"),
node.AttributeAsInt("Gold"));
XmlNodeList lootItemNodes =
node.SelectNodes("./LootItems/LootItem");
if(lootItemNodes != null)
{
foreach(XmlNode lootItemNode in lootItemNodes)
{
monster.AddItemToLootTable(lootItemNode.AttributeAsInt("ID"),
lootItemNode.AttributeAsInt("Percentage"));
}
}
s_baseMonsters.Add(monster);
}
}
private static Monster GetMonster(int id)
{
Monster newMonster = s_baseMonsters.FirstOrDefault(m =>
m.ID ==
id).Clone();
foreach (ItemPercentage itemPercentage in
newMonster.LootTable)
{
table
if (DiceService.Instance.Roll(100).Value <=
itemPercentage.Percentage)
{
newMonster.AddItemToInventory(ItemFactory.CreateGameItem(itemPercentage.ID));
}
}
return newMonster;
}
}
}
QuestFactory.cs
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Engine.Models;
using Engine.Shared;
namespace Engine.Factories
{
internal static class QuestFactory
{
private const string GAME_DATA_FILENAME =
".\\GameData\\Quests.xml";
private static readonly List<Quest> _quests = new
List<Quest>();
static QuestFactory()
{
if(File.Exists(GAME_DATA_FILENAME))
{
XmlDocument data = new XmlDocument();
data.LoadXml(File.ReadAllText(GAME_DATA_FILENAME));
LoadQuestsFromNodes(data.SelectNodes("/Quests/Quest"));
}
else
{
throw new FileNotFoundException($"Missing data file:
{GAME_DATA_FILENAME}");
}
}
private static void LoadQuestsFromNodes(XmlNodeList nodes)
{
foreach(XmlNode node in nodes)
{
its reward items
List<ItemQuantity> itemsToComplete = new
List<ItemQuantity>();
List<ItemQuantity> rewardItems = new List<ItemQuantity>
();
foreach(XmlNode childNode in
node.SelectNodes("./ItemsToComplete/Item"))
{
GameItem item = ItemFactory.CreateGameItem(childNode.AttributeAsInt("ID"));
itemsToComplete.Add(new ItemQuantity(item,
childNode.AttributeAsInt("Quantity")));
}
foreach(XmlNode childNode in
node.SelectNodes("./RewardItems/Item"))
{
GameItem item = ItemFactory.CreateGameItem(childNode.AttributeAsInt("ID"));
rewardItems.Add(new ItemQuantity(item,
childNode.AttributeAsInt("Quantity")));
}
_quests.Add(new Quest(node.AttributeAsInt("ID"),
node.SelectSingleNode("./Name")?.InnerText ?? "",
node.SelectSingleNode("./Description")?.InnerText
?? "",
itemsToComplete,
node.AttributeAsInt("RewardExperiencePoints"),
node.AttributeAsInt("RewardGold"),
rewardItems));
}
}
internal static Quest GetQuestByID(int id)
{
return _quests.FirstOrDefault(quest => quest.ID == id);
}
}
}
RecipeFactory.cs
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Engine.Models;
using Engine.Shared;
namespace Engine.Factories
{
public static class RecipeFactory
{
private const string GAME_DATA_FILENAME =
".\\GameData\\Recipes.xml";
private static readonly List<Recipe> _recipes = new
List<Recipe>();
static RecipeFactory()
{
if(File.Exists(GAME_DATA_FILENAME))
{
XmlDocument data = new XmlDocument();
data.LoadXml(File.ReadAllText(GAME_DATA_FILENAME));
LoadRecipesFromNodes(data.SelectNodes("/Recipes/Recipe"));
}
else
{
throw new FileNotFoundException($"Missing data file:
{GAME_DATA_FILENAME}");
}
}
private static void LoadRecipesFromNodes(XmlNodeList nodes)
{
foreach(XmlNode node in nodes)
{
var ingredients = new List<ItemQuantity>();
foreach(XmlNode childNode in
node.SelectNodes("./Ingredients/Item"))
{
GameItem item = ItemFactory.CreateGameItem(childNode.AttributeAsInt("ID"));
ingredients.Add(new ItemQuantity(item,
childNode.AttributeAsInt("Quantity")));
}
var outputItems = new List<ItemQuantity>();
foreach (XmlNode childNode in
node.SelectNodes("./OutputItems/Item"))
{
GameItem item = ItemFactory.CreateGameItem(childNode.AttributeAsInt("ID"));
outputItems.Add(new ItemQuantity(item,
childNode.AttributeAsInt("Quantity")));
}
Recipe recipe =
new Recipe(node.AttributeAsInt("ID"),
node.SelectSingleNode("./Name")?.InnerText ??
"",
ingredients, outputItems);
_recipes.Add(recipe);
}
}
public static Recipe RecipeByID(int id)
{
return _recipes.FirstOrDefault(x => x.ID == id);
}
}
}
Traderfactory.cs
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Engine.Models;
using Engine.Shared;
namespace Engine.Factories
{
public static class TraderFactory
{
private const string GAME_DATA_FILENAME =
".\\GameData\\Traders.xml";
private static readonly List<Trader> _traders = new
List<Trader>();
static TraderFactory()
{
if(File.Exists(GAME_DATA_FILENAME))
{
XmlDocument data = new XmlDocument();
data.LoadXml(File.ReadAllText(GAME_DATA_FILENAME));
LoadTradersFromNodes(data.SelectNodes("/Traders/Trader"));
}
else
{
throw new FileNotFoundException($"Missing data file:
{GAME_DATA_FILENAME}");
}
}
private static void LoadTradersFromNodes(XmlNodeList nodes)
{
foreach(XmlNode node in nodes)
{
Trader trader =
new Trader(node.AttributeAsInt("ID"),
node.SelectSingleNode("./Name")?.InnerText ?? "");
foreach(XmlNode childNode in
node.SelectNodes("./InventoryItems/Item"))
{
int quantity =
childNode.AttributeAsInt("Quantity");
add.
with
enchantments.
for(int i = 0; i < quantity; i++)
{
trader.AddItemToInventory(ItemFactory.CreateGameItem(childNode.AttributeAsInt("ID")));
}
}
_traders.Add(trader);
}
}
public static Trader GetTraderByID(int id)
{
return _traders.FirstOrDefault(t => t.ID == id);
}
}
}
WorldFactory.cs
using System.IO;
using System.Xml;
using Engine.Models;
using Engine.Shared;
namespace Engine.Factories
{
internal static class WorldFactory
{
private const string GAME_DATA_FILENAME =
".\\GameData\\Locations.xml";
internal static World CreateWorld()
{
World world = new World();
if(File.Exists(GAME_DATA_FILENAME))
{
XmlDocument data = new XmlDocument();
data.LoadXml(File.ReadAllText(GAME_DATA_FILENAME));
string rootImagePath =
data.SelectSingleNode("/Locations")
.AttributeAsString("RootImagePath");
LoadLocationsFromNodes(world,
rootImagePath,
data.SelectNodes("/Locations/Location"));
}
else
{
throw new FileNotFoundException($"Missing data file:
{GAME_DATA_FILENAME}");
}
return world;
}
private static void LoadLocationsFromNodes(World world, string
rootImagePath,
XmlNodeList nodes)
{
if(nodes == null)
{
return;
}
foreach(XmlNode node in nodes)
{
Location location =
new Location(node.AttributeAsInt("X"),
node.AttributeAsInt("Y"),
node.AttributeAsString("Name"),
node.SelectSingleNode("./Description")?.InnerText ??
"",
$".{rootImagePath}
{node.AttributeAsString("ImageName")}");
AddMonsters(location,
node.SelectNodes("./Monsters/Monster"));
AddQuests(location,
node.SelectNodes("./Quests/Quest"));
AddTrader(location, node.SelectSingleNode("./Trader"));
world.AddLocation(location);
}
}
private static void AddMonsters(Location location, XmlNodeList
monsters)
{
if(monsters == null)
{
return;
}
foreach(XmlNode monsterNode in monsters)
{
location.AddMonster(monsterNode.AttributeAsInt("ID"),
monsterNode.AttributeAsInt("Percent"));
}
}
private static void AddQuests(Location location, XmlNodeList
quests)
{
if(quests == null)
{
return;
}
foreach(XmlNode questNode in quests)
{
location.QuestsAvailableHere
.Add(QuestFactory.GetQuestByID(questNode.AttributeAsInt("ID")));
}
}
private static void AddTrader(Location location, XmlNode
traderHere)
{
if(traderHere == null)
{
return;
}
location.TraderHere =
TraderFactory.GetTraderByID(traderHere.AttributeAsInt("ID"));
}
}
}
SpellFactory.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Engine.Models;
namespace Engine.Factories
{
public static class SpellFactory
{
private static readonly List<spells> _standardSpell = new
List<Spells>
();
static SpellFactory()
{
_standardSpell.Add(new Spell(8000, "Fireball", 5));
_standardSpell.Add(new Spell(8001, "Lightning", 5));
_standardSpell.Add(new Spell(8002, "Frost Bolt", 5));
}
public static Spell CreateSpell(int SpellID)
{
standardSpell = _standardSpell.FirstOrDefault(spell =>
spell.SpellID == SpellID);
if (standardSpell != null)
{
return standardSpell.Clone();
}
return null;
}
}
}
|
|
|
|
|
I hate buzzwords, like "factory".
Define your entities, and your collections of entities, and then use xml serialization to populate them. You'll have a LOT less code to deal with.
I also suggest that you store your different entity types in their own xml files, because when you write new data, you have to write the entire file.
".45 ACP - because shooting twice is just silly" - JSOP, 2010 ----- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010 ----- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
I've heard of xml the game actually uses xml files for some things. But how would you xml serialization?
|
|
|
|
|
|
thanks for the links. I am new to c# and still learning the concepts of it. how would xml serialization help me? would it help me more than combining all factories into an abstract factory?
|
|
|
|
|
When your game is running the data is all in memory of the computer. When your program stops this memory will be cleared. So if you wish to save the game, you need to store the state on disk. As disk files have a sequential list of bytes, we refer to the concept of converting your in memory data to a sequential sequence of data "serialization". Converting it back is "deserialization". XML is one of better known formats you can use to represent your data in a file. Another (probably more popular these days) is JSON - I would stick to one of these until you KNOW that another option is better. If you do not need to keep data after your program close (and maybe in the start you don't) you can simply skip this.
Your example code referring to this as a Factory is - a stretch. A factory is used when you need to create a new object - but you need some code that controls which object is created (so if you want to create a "Weapon" object, the Factory might have logic to figure out if it should create a Sword or a Gun object).
So the most important next step for you, is to stop referring to these as Factories. That will just confuse you (as here, you keep asking factory this, factory that - but you do not need a factory, nor do you have a factory)
In your example the XML is read "manually". What I mean with this, is there is code that look for certain named data in the XML file, and then place that into the memory object. The main advantage of this is: 1) Easy to debug, 2) Easy to deal with multiple formats - if you need to read old saved games for example. The disadvantage is a lot of code that takes time to write and maintain. Garry already provided links for the alternative approach, where you basically let the computer come up with an XML structure that match your data. If you do not want to convert data manually as done in your example, then that is how you would avoid all this code.
|
|
|
|
|
I see thanks for the answer I've been looking at the links Garry posted to better understand XML serialization. So the item factory class etc are not factories nor do I have a factory, to begin with? sorry, the tutorial I'm following got a little confusing why I thought those classes were factories, but I see I was mistaken.
|
|
|
|
|
They're not "factories"; they're deserializers. Maybe "data repositories".
I have two generic methods for XML serializing and deserializing any object. I sense you have a lot of duplicate code with "magic strings".
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
|
"Factories" typically create "new" (empty) objects; you're simply restoring from existing data. Your static (data) collections constitute "data repositories".
So, calling your classes "factories" is a misnomer.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
I was mistaken. You are right; classes those are. I was just informed that by someone on another forum. Now I need to figure out if I want to go factory with them, then abstract factory, or XML serialization, like someone else suggested. Which one would be the better choice? I have seven so-called factories in the game/tutorial I've been following.
|
|
|
|
|
I think you need a better handle on serializing a class. I think you have an opportunity to make your code more "generic" (which means fewer lines).
Examples of XML Serialization | Microsoft Docs
Generic Methods - C# Programming Guide | Microsoft Docs
Maybe your tutorial "started" with XML; in my case, for game tables, I typically build them in code as classes, and serialize / deserialize them to / from XML, if needed. Just find them easier to maintain and integrate that way; even for 100 entries or so. Stick everything in a "data class library".
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
modified 21-Dec-21 16:18pm.
|
|
|
|
|
Would XML serialization be better for what I'm trying to do? Some of the factory classes will have a lot of subtypes in them, so wouldn't a factory or abstract factory be better? Let's say, for example. I took Itemfactory.cs, gameitem.cs, and Inventory.cs wouldn't those benefit from being a factory or even abstract factory?
itemfactory.cs
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Engine.Actions;
using Engine.Models;
using Engine.Shared;
using SOSCSRPG.Core;
namespace Engine.Factories
{
public static class ItemFactory
{
private const string GAME_DATA_FILENAME =
".\\GameData\\GameItems.xml";
private static readonly List<GameItem> _standardGameItems = new
List<GameItem>
();
static ItemFactory()
{
if(File.Exists(GAME_DATA_FILENAME))
{
XmlDocument data = new XmlDocument();
data.LoadXml(File.ReadAllText(GAME_DATA_FILENAME));
LoadItemsFromNodes(data.SelectNodes("/GameItems/Weapons/Weapon"));
LoadItemsFromNodes(data.SelectNodes("/GameItems/HealingItems/HealingItem"));
LoadItemsFromNodes(data.SelectNodes("/GameItems/MiscellaneousItems/MiscellaneousItem"));
}
else
{
throw new FileNotFoundException($"Missing data file:
{GAME_DATA_FILENAME}");
}
}
public static GameItem CreateGameItem(int itemTypeID)
{
return _standardGameItems.FirstOrDefault(item =>
item.ItemTypeID ==
itemTypeID)?.Clone();
}
private static void LoadItemsFromNodes(XmlNodeList nodes)
{
if(nodes == null)
{
return;
}
foreach(XmlNode node in nodes)
{
GameItem.ItemCategory itemCategory =
DetermineItemCategory(node.Name);
GameItem gameItem =
new GameItem(itemCategory,
node.AttributeAsInt("ID"),
node.AttributeAsString("Name"),
node.AttributeAsInt("Price"),
itemCategory ==
GameItem.ItemCategory.Weapon);
if(itemCategory == GameItem.ItemCategory.Weapon)
{
gameItem.Action =
new AttackWithWeapon(gameItem,
node.AttributeAsString("DamageDice"));
}
else if(itemCategory ==
GameItem.ItemCategory.Consumable)
{
gameItem.Action =
new Heal(gameItem,
node.AttributeAsInt("HitPointsToHeal"));
}
_standardGameItems.Add(gameItem);
}
}
private static GameItem.ItemCategory
DetermineItemCategory(string itemType)
{
switch(itemType)
{
case "Weapon":
return GameItem.ItemCategory.Weapon;
case "HealingItem":
return GameItem.ItemCategory.Consumable;
default:
return GameItem.ItemCategory.Miscellaneous;
}
}
}
}
gameitem.cs
using Engine.Actions;
using Newtonsoft.Json;
namespace Engine.Models
{
public class GameItem
{
public enum ItemCategory
{
Miscellaneous,
Weapon,
Consumable
}
[JsonIgnore]
public ItemCategory Category { get; }
public int ItemTypeID { get; }
[JsonIgnore]
public string Name { get; }
[JsonIgnore]
public int Price { get; }
[JsonIgnore]
public bool IsUnique { get; }
[JsonIgnore]
public IAction Action { get; set; }
public GameItem(ItemCategory category, int itemTypeID, string name, int price,
bool isUnique = false, IAction action = null)
{
Category = category;
ItemTypeID = itemTypeID;
Name = name;
Price = price;
IsUnique = isUnique;
Action = action;
}
public void PerformAction(LivingEntity actor, LivingEntity target)
{
Action?.Execute(actor, target);
}
public GameItem Clone()
{
return new GameItem(Category, ItemTypeID, Name, Price, IsUnique, Action);
}
}
}
Inventory.cs
using System.Collections.Generic;
using System.Linq;
using Engine.Shared;
using Newtonsoft.Json;
namespace Engine.Models
{
public class Inventory
{
#region Backing variables
private readonly List<GameItem> _backingInventory =
new List<GameItem>();
private readonly List<GroupedInventoryItem> _backingGroupedInventoryItems =
new List<GroupedInventoryItem>();
#endregion
#region Properties
public IReadOnlyList<GameItem> Items => _backingInventory.AsReadOnly();
[JsonIgnore]
public IReadOnlyList<GroupedInventoryItem> GroupedInventory =>
_backingGroupedInventoryItems.AsReadOnly();
[JsonIgnore]
public IReadOnlyList<GameItem> Weapons =>
_backingInventory.ItemsThatAre(GameItem.ItemCategory.Weapon).AsReadOnly();
[JsonIgnore]
public IReadOnlyList<GameItem> Consumables =>
_backingInventory.ItemsThatAre(GameItem.ItemCategory.Consumable).AsReadOnly();
[JsonIgnore]
public bool HasConsumable => Consumables.Any();
#endregion
#region Constructors
public Inventory(IEnumerable<GameItem> items = null)
{
if(items == null)
{
return;
}
foreach(GameItem item in items)
{
_backingInventory.Add(item);
AddItemToGroupedInventory(item);
}
}
#endregion
#region Public functions
public bool HasAllTheseItems(IEnumerable<ItemQuantity> items)
{
return items.All(item => Items.Count(i => i.ItemTypeID == item.ItemID) >= item.Quantity);
}
public Inventory AddItem(GameItem item)
{
return AddItems(new List<GameItem> { item });
}
public Inventory AddItems(IEnumerable<GameItem> items)
{
return new Inventory(Items.Concat(items));
}
public Inventory RemoveItem(GameItem item)
{
return RemoveItems(new List<GameItem> { item });
}
public Inventory RemoveItems(IEnumerable<GameItem> items)
{
List<GameItem> workingInventory = Items.ToList();
IEnumerable<GameItem> itemsToRemove = items.ToList();
foreach (GameItem item in itemsToRemove)
{
workingInventory.Remove(item);
}
return new Inventory(workingInventory);
}
public Inventory RemoveItems(IEnumerable<ItemQuantity> itemQuantities)
{
Inventory workingInventory = new Inventory(Items);
foreach (ItemQuantity itemQuantity in itemQuantities)
{
for (int i = 0; i < itemQuantity.Quantity; i++)
{
workingInventory =
workingInventory
.RemoveItem(workingInventory
.Items
.First(item => item.ItemTypeID == itemQuantity.ItemID));
}
}
return workingInventory;
}
#endregion
#region Private functions
private void AddItemToGroupedInventory(GameItem item)
{
if(item.IsUnique)
{
_backingGroupedInventoryItems.Add(new GroupedInventoryItem(item, 1));
}
else
{
if(_backingGroupedInventoryItems.All(gi => gi.Item.ItemTypeID != item.ItemTypeID))
{
_backingGroupedInventoryItems.Add(new GroupedInventoryItem(item, 0));
}
_backingGroupedInventoryItems.First(gi => gi.Item.ItemTypeID ==
item.ItemTypeID).Quantity++;
}
}
#endregion
}
}
modified 21-Dec-21 19:30pm.
|
|
|
|
|
Me telling you to use XML serializing (or not) will do you no good until you understand the process better; that's what the links are for; including any links in the article.
One typically "saves" (things like inventory) when you expect to quit and restart a game (restore); that's a valid context for serialization. The rest is up to you.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
i see i will look in to that i've been reading up on the links trying to get a better understanding
|
|
|
|
|
Hey all,
I am currently downloading files for .net desktop development workload.
Just wondering - is there any way to retrieve the installer files for offline installation should I need it in the future?
Cheers
|
|
|
|
|