❔ Design Pattern

This doesnt make sense to me, its clearly inside my library: System.IO.FileNotFoundException: 'Could not load file or assembly 'System.Configuration.ConfigurationManager, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified.'
347 Replies
Pobiega
Pobiega2y ago
@Protagonist still there?
Protagonist
ProtagonistOP2y ago
i have now moved to appsettings.json, and redoing my methods to work with json this was old post ish
Pobiega
Pobiega2y ago
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace ConfigurableLibrary;

public class ConfigurableLibraryClass
{
private readonly IOptions<ConfigurableLibraryOptions> _options;

public ConfigurableLibraryClass(IOptions<ConfigurableLibraryOptions> options)
{
_options = options;
}

public void PrintOptions()
{
var values = _options.Value;

Console.WriteLine(values.Name);
Console.WriteLine(values.Count);
}
}

public class ConfigurableLibraryOptions
{
public const string SectionName = "ConfigurableLib";

public string Name { get; set; }
public int Count { get; set; }

internal bool Validate()
{
if (string.IsNullOrEmpty(Name))
return false;

if (Count <= 0)
return false;

return true;
}
}

public static class ConfigurableLibraryExtensions
{
public static IServiceCollection AddConfigurableLibrary(this IServiceCollection services)
{
services
.AddOptions<ConfigurableLibraryOptions>()
.BindConfiguration(ConfigurableLibraryOptions.SectionName)
.Validate(o => o.Validate());

services.AddTransient<ConfigurableLibraryClass>();

return services;
}

public static IServiceCollection AddConfigurableLibrary(this IServiceCollection services,
Action<ConfigurableLibraryOptions> configure)
{
services
.AddConfigurableLibrary()
.Configure(configure);

return services;
}
}
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace ConfigurableLibrary;

public class ConfigurableLibraryClass
{
private readonly IOptions<ConfigurableLibraryOptions> _options;

public ConfigurableLibraryClass(IOptions<ConfigurableLibraryOptions> options)
{
_options = options;
}

public void PrintOptions()
{
var values = _options.Value;

Console.WriteLine(values.Name);
Console.WriteLine(values.Count);
}
}

public class ConfigurableLibraryOptions
{
public const string SectionName = "ConfigurableLib";

public string Name { get; set; }
public int Count { get; set; }

internal bool Validate()
{
if (string.IsNullOrEmpty(Name))
return false;

if (Count <= 0)
return false;

return true;
}
}

public static class ConfigurableLibraryExtensions
{
public static IServiceCollection AddConfigurableLibrary(this IServiceCollection services)
{
services
.AddOptions<ConfigurableLibraryOptions>()
.BindConfiguration(ConfigurableLibraryOptions.SectionName)
.Validate(o => o.Validate());

services.AddTransient<ConfigurableLibraryClass>();

return services;
}

public static IServiceCollection AddConfigurableLibrary(this IServiceCollection services,
Action<ConfigurableLibraryOptions> configure)
{
services
.AddConfigurableLibrary()
.Configure(configure);

return services;
}
}
this is the library
using ConfigurableLibrary;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();

var services = new ServiceCollection();

services.AddSingleton<IConfiguration>(configuration);

services.AddConfigurableLibrary();

var provider = services.BuildServiceProvider();

var thing = provider.GetRequiredService<ConfigurableLibraryClass>();

thing.PrintOptions();
using ConfigurableLibrary;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

var configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();

var services = new ServiceCollection();

services.AddSingleton<IConfiguration>(configuration);

services.AddConfigurableLibrary();

var provider = services.BuildServiceProvider();

var thing = provider.GetRequiredService<ConfigurableLibraryClass>();

thing.PrintOptions();
this is the consuming console app
{
"ConfigurableLib":{
"Name": "Steve",
"Count": 123
}
}
{
"ConfigurableLib":{
"Name": "Steve",
"Count": 123
}
}
thats the config file, in json I could easily change the AddJsonFile to be xml, or ini, or yaml, or whatever other format I want Its a bit of turkey stuffing, but I hope you get the core concept here @Protagonist lemme know if something isn't clear and you need a more in depth explanation.
Protagonist
ProtagonistOP2y ago
okay so without the consuming app console including the DI then it wouldnt function at all in the console app?
Pobiega
Pobiega2y ago
well, no, since there would be no IConfiguration registered. as mentioned before, this is the modern way of doing things and it gives the consumer all the power
Protagonist
ProtagonistOP2y ago
public static class AppConfigDeserializer
{

public static World DeserializeWorldFromAppConfig(IConfiguration configuration)
{
var worldConfig = configuration.GetSection("World");
var width = int.Parse(worldConfig["Width"]);
var height = int.Parse(worldConfig["Height"]);

var world = new World(width, height);

var creatures = DeserializeCreaturesFromAppConfig(configuration, world);
var worldObjects = DeserializeWorldObjectsFromAppConfig(configuration, world);

foreach (var creature in creatures)
{
world.AddCreature(creature);
}

foreach (var worldObject in worldObjects)
{
world.AddWorldObject(worldObject);
}

return world;
}


public static List<Creature> DeserializeCreaturesFromAppConfig(IConfiguration configuration, World world)
{
var creatures = new List<Creature>();

foreach (var creatureSection in configuration.GetSection("Creatures").GetChildren())
{
var name = creatureSection["Name"];
int x, y, health;

if (!int.TryParse(creatureSection["X"], out x)
|| !int.TryParse(creatureSection["Y"], out y)
|| !int.TryParse(creatureSection["Health"], out health))
{
// Handle parsing errors
Console.WriteLine($"Error parsing creature attributes for creature '{name}'");
continue;
}

var creature = new Creature(name, new Position(x, y), health);
creatures.Add(creature);
}

return creatures;
}

...
public static class AppConfigDeserializer
{

public static World DeserializeWorldFromAppConfig(IConfiguration configuration)
{
var worldConfig = configuration.GetSection("World");
var width = int.Parse(worldConfig["Width"]);
var height = int.Parse(worldConfig["Height"]);

var world = new World(width, height);

var creatures = DeserializeCreaturesFromAppConfig(configuration, world);
var worldObjects = DeserializeWorldObjectsFromAppConfig(configuration, world);

foreach (var creature in creatures)
{
world.AddCreature(creature);
}

foreach (var worldObject in worldObjects)
{
world.AddWorldObject(worldObject);
}

return world;
}


public static List<Creature> DeserializeCreaturesFromAppConfig(IConfiguration configuration, World world)
{
var creatures = new List<Creature>();

foreach (var creatureSection in configuration.GetSection("Creatures").GetChildren())
{
var name = creatureSection["Name"];
int x, y, health;

if (!int.TryParse(creatureSection["X"], out x)
|| !int.TryParse(creatureSection["Y"], out y)
|| !int.TryParse(creatureSection["Health"], out health))
{
// Handle parsing errors
Console.WriteLine($"Error parsing creature attributes for creature '{name}'");
continue;
}

var creature = new Creature(name, new Position(x, y), health);
creatures.Add(creature);
}

return creatures;
}

...
public static List<WorldObject> DeserializeWorldObjectsFromAppConfig(IConfiguration configuration, World world)
{
var worldObjects = new List<WorldObject>();

var worldObjectsConfig = configuration.GetSection("WorldObjects");

foreach (var worldObjectConfig in worldObjectsConfig.GetChildren())
{
var name = worldObjectConfig["name"];
var x = int.Parse(worldObjectConfig["x"]);
var y = int.Parse(worldObjectConfig["y"]);
var isLootable = bool.Parse(worldObjectConfig["isLootable"]);
var isRemoveable = bool.Parse(worldObjectConfig["isRemoveable"]);
var isEquipped = bool.Parse(worldObjectConfig["isEquipped"]);

WorldObject worldObject;

if (worldObjectConfig.Key == "AttackItem")
{
var damage = int.Parse(worldObjectConfig["damage"]);
var range = int.Parse(worldObjectConfig["range"]);
worldObject = new AttackItem(damage,name,range,new Position(x,y),isLootable,isRemoveable,isEquipped);
}
else if (worldObjectConfig.Key == "DefenceItem")
{
var reduceHitpoint = int.Parse(worldObjectConfig["reduceHitpoint"]);
worldObject = new DefenceItem(name, reduceHitpoint,new Position(x,y),isLootable,isRemoveable,isEquipped);
}
else
{
throw new ArgumentException("Invalid world object type");
}

world.AddWorldObject(worldObject);
worldObjects.Add(worldObject);
}

return worldObjects;
}


}
public static List<WorldObject> DeserializeWorldObjectsFromAppConfig(IConfiguration configuration, World world)
{
var worldObjects = new List<WorldObject>();

var worldObjectsConfig = configuration.GetSection("WorldObjects");

foreach (var worldObjectConfig in worldObjectsConfig.GetChildren())
{
var name = worldObjectConfig["name"];
var x = int.Parse(worldObjectConfig["x"]);
var y = int.Parse(worldObjectConfig["y"]);
var isLootable = bool.Parse(worldObjectConfig["isLootable"]);
var isRemoveable = bool.Parse(worldObjectConfig["isRemoveable"]);
var isEquipped = bool.Parse(worldObjectConfig["isEquipped"]);

WorldObject worldObject;

if (worldObjectConfig.Key == "AttackItem")
{
var damage = int.Parse(worldObjectConfig["damage"]);
var range = int.Parse(worldObjectConfig["range"]);
worldObject = new AttackItem(damage,name,range,new Position(x,y),isLootable,isRemoveable,isEquipped);
}
else if (worldObjectConfig.Key == "DefenceItem")
{
var reduceHitpoint = int.Parse(worldObjectConfig["reduceHitpoint"]);
worldObject = new DefenceItem(name, reduceHitpoint,new Position(x,y),isLootable,isRemoveable,isEquipped);
}
else
{
throw new ArgumentException("Invalid world object type");
}

world.AddWorldObject(worldObject);
worldObjects.Add(worldObject);
}

return worldObjects;
}


}
Deserilize class
public class Game
{

public void Start()
{
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();

var world = AppConfigDeserializer.DeserializeWorldFromAppConfig(configuration);
var creatures = AppConfigDeserializer.DeserializeCreaturesFromAppConfig(configuration, world);
var worldObjects = AppConfigDeserializer.DeserializeWorldObjectsFromAppConfig(configuration, world);


Creature.Play(world.Creatures[0], world.Creatures[1], world);
}
public class Game
{

public void Start()
{
IConfiguration configuration = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.Build();

var world = AppConfigDeserializer.DeserializeWorldFromAppConfig(configuration);
var creatures = AppConfigDeserializer.DeserializeCreaturesFromAppConfig(configuration, world);
var worldObjects = AppConfigDeserializer.DeserializeWorldObjectsFromAppConfig(configuration, world);


Creature.Play(world.Creatures[0], world.Creatures[1], world);
}
Game class @Pobiega I was just changing the methods to go to json instead of xml, does this look correct?
Pobiega
Pobiega2y ago
uhm I kinda hate it, since you are not actually using strict models for your configuration. I'd much prefer a .Get<T>(section) approach if thats all you want also, this doesnt seem to be "configuration" at all this seems to be straight up loading/saving application data and for that, you can just use JsonSerializer directly.
Protagonist
ProtagonistOP2y ago
I thought it was configuring since im not hardcoding anything and everything can be configured in the file I had no idea about any of this so i was just searching too what would i change to make this configurable?
Pobiega
Pobiega2y ago
you're not loading configuration as such you are loading application state thats better done with just raw json serializiaton
Protagonist
ProtagonistOP2y ago
by application state do u mean how some variables will be changing? for example health Im not sure what to do from now on also i get this error System.IO.FileNotFoundException: 'Could not load file or assembly 'Microsoft.Extensions.Configuration.Abstractions, Version=7.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'. The system cannot find the file specified.'
Pobiega
Pobiega2y ago
something is weird with your builds/nuget restores you ahd the same for configurationmanager anyways, json serializaiton is easy the absolute simplest version is just this
public static T GetFromJsonFile<T>(string path)
{
var data = File.ReadAllText(path);
return JsonSerializer.Deserialize<T>(data);
}
public static T GetFromJsonFile<T>(string path)
{
var data = File.ReadAllText(path);
return JsonSerializer.Deserialize<T>(data);
}
Protagonist
ProtagonistOP2y ago
public static class AppConfigDeserializer
{

public static World DeserializeWorldFromAppConfig(string path)
{
var worldConfig = GetFromJsonFile<World>(path);
var worldSizeX = worldConfig.MaxX;
var worldSizeY = worldConfig.MaxY;

var world = new World(worldSizeX, worldSizeY);

var creatures = DeserializeCreaturesFromAppConfig(path);
var worldObjects = DeserializeWorldObjectsFromAppConfig(path);

foreach (var creature in creatures)
{
world.AddCreature(creature);
}

foreach (var worldObject in worldObjects)
{
world.AddWorldObject(worldObject);
}

return world;
}

public static List<Creature> DeserializeCreaturesFromAppConfig(string path)
{
var creatures = GetFromJsonFile<List<Creature>>(path);

return creatures;
}

public static List<WorldObject> DeserializeWorldObjectsFromAppConfig(string path)
{
var worldObjects = GetFromJsonFile<List<WorldObject>>(path);

return worldObjects;
}

public static T GetFromJsonFile<T>(string path)
{
var data = File.ReadAllText(path);
return JsonSerializer.Deserialize<T>(data);
}

}
public static class AppConfigDeserializer
{

public static World DeserializeWorldFromAppConfig(string path)
{
var worldConfig = GetFromJsonFile<World>(path);
var worldSizeX = worldConfig.MaxX;
var worldSizeY = worldConfig.MaxY;

var world = new World(worldSizeX, worldSizeY);

var creatures = DeserializeCreaturesFromAppConfig(path);
var worldObjects = DeserializeWorldObjectsFromAppConfig(path);

foreach (var creature in creatures)
{
world.AddCreature(creature);
}

foreach (var worldObject in worldObjects)
{
world.AddWorldObject(worldObject);
}

return world;
}

public static List<Creature> DeserializeCreaturesFromAppConfig(string path)
{
var creatures = GetFromJsonFile<List<Creature>>(path);

return creatures;
}

public static List<WorldObject> DeserializeWorldObjectsFromAppConfig(string path)
{
var worldObjects = GetFromJsonFile<List<WorldObject>>(path);

return worldObjects;
}

public static T GetFromJsonFile<T>(string path)
{
var data = File.ReadAllText(path);
return JsonSerializer.Deserialize<T>(data);
}

}
so something like this?
public class Game
{
public void Start()
{
var world = AppConfigDeserializer.DeserializeWorldFromAppConfig("appsettings.json");
var creatures = AppConfigDeserializer.DeserializeCreaturesFromAppConfig("appsettings.json");
var worldObjects = AppConfigDeserializer.DeserializeWorldObjectsFromAppConfig("appsettings.json");

foreach (var creature in creatures)
{
world.AddCreature(creature);
}

foreach (var worldObject in worldObjects)
{
world.AddWorldObject(worldObject);
}

Creature.Play(world.Creatures[0], world.Creatures[1], world);
}
}
public class Game
{
public void Start()
{
var world = AppConfigDeserializer.DeserializeWorldFromAppConfig("appsettings.json");
var creatures = AppConfigDeserializer.DeserializeCreaturesFromAppConfig("appsettings.json");
var worldObjects = AppConfigDeserializer.DeserializeWorldObjectsFromAppConfig("appsettings.json");

foreach (var creature in creatures)
{
world.AddCreature(creature);
}

foreach (var worldObject in worldObjects)
{
world.AddWorldObject(worldObject);
}

Creature.Play(world.Creatures[0], world.Creatures[1], world);
}
}
Pobiega
Pobiega2y ago
what does your World class look like?
Protagonist
ProtagonistOP2y ago
Protagonist
ProtagonistOP2y ago
it includes methods aswell
Pobiega
Pobiega2y ago
thats fine with that structure, you can literally store an entire world as a json object and deserialize it with a single line of code
var world = GetFromJsonFile<World>("world.json");
var world = GetFromJsonFile<World>("world.json");
is all you need it will load creatures and attackitems and defenceitems too, from the json structure
Protagonist
ProtagonistOP2y ago
And this part will work just fine if i do so correct?
Pobiega
Pobiega2y ago
public void Start()
{
var world = GetFromJsonFile<World>("world.json");

Creature.Play(world.Creatures[0], world.Creatures[1], world);
}
public void Start()
{
var world = GetFromJsonFile<World>("world.json");

Creature.Play(world.Creatures[0], world.Creatures[1], world);
}
:p
Protagonist
ProtagonistOP2y ago
So the creatures and the worldobjects wouldnt need to be added to the world because it will already be added to it this way?
Pobiega
Pobiega2y ago
yes
Protagonist
ProtagonistOP2y ago
And the appsettings.json file, what adjustments would have to be made to it
{
"World": {
"worldSizeX": "100",
"worldSizeY": "100"
},
"Creatures": {
"Creature": [
{
"name": "Mo",
"x": "10",
"y": "10",
"health": "100"
},
{
"name": "Bob",
"x": "15",
"y": "15",
"health": "100"
}
]
},
"WorldObjects": {
"AttackItem": [
{
"name": "sword",
"damage": "5",
"x": "13",
"y": "15",
"range": "5",
"isLootable": "True",
"isRemoveable": "True",
"isEquipped": "True"
},
{
"name": "dagger",
"damage": "10",
"x": "23",
"y": "25",
"range": "5",
"isLootable": "True",
"isRemoveable": "True",
"isEquipped": "True"
}
],
"DefenceItem": {
"name": "Chestplate",
"reduceHitpoint": "70",
"x": "12",
"y": "12",
"isLootable": "True",
"isRemoveable": "True",
"isEquipped": "True"
}
}
}
{
"World": {
"worldSizeX": "100",
"worldSizeY": "100"
},
"Creatures": {
"Creature": [
{
"name": "Mo",
"x": "10",
"y": "10",
"health": "100"
},
{
"name": "Bob",
"x": "15",
"y": "15",
"health": "100"
}
]
},
"WorldObjects": {
"AttackItem": [
{
"name": "sword",
"damage": "5",
"x": "13",
"y": "15",
"range": "5",
"isLootable": "True",
"isRemoveable": "True",
"isEquipped": "True"
},
{
"name": "dagger",
"damage": "10",
"x": "23",
"y": "25",
"range": "5",
"isLootable": "True",
"isRemoveable": "True",
"isEquipped": "True"
}
],
"DefenceItem": {
"name": "Chestplate",
"reduceHitpoint": "70",
"x": "12",
"y": "12",
"isLootable": "True",
"isRemoveable": "True",
"isEquipped": "True"
}
}
}
Pobiega
Pobiega2y ago
{
"MaxX": 150,
"MaxY": 200,
"Creatures": [
{
"Name": "Steve",
"X": 5,
"Y": 10,
"Health": 22
}
],
"AttackItems": [
{
"name": "sword",
"damage": "5",
"x": "13",
"y": "15",
"range": "5",
"isLootable": "True",
"isRemoveable": "True",
"isEquipped": "True"
},
{
"name": "dagger",
"damage": "10",
"x": "23",
"y": "25",
"range": "5",
"isLootable": "True",
"isRemoveable": "True",
"isEquipped": "True"
}
],
"DefenceItems": [
{
"name": "Chestplate",
"reduceHitpoint": "70",
"x": "12",
"y": "12",
"isLootable": "True",
"isRemoveable": "True",
"isEquipped": "True"
}
]
}
{
"MaxX": 150,
"MaxY": 200,
"Creatures": [
{
"Name": "Steve",
"X": 5,
"Y": 10,
"Health": 22
}
],
"AttackItems": [
{
"name": "sword",
"damage": "5",
"x": "13",
"y": "15",
"range": "5",
"isLootable": "True",
"isRemoveable": "True",
"isEquipped": "True"
},
{
"name": "dagger",
"damage": "10",
"x": "23",
"y": "25",
"range": "5",
"isLootable": "True",
"isRemoveable": "True",
"isEquipped": "True"
}
],
"DefenceItems": [
{
"name": "Chestplate",
"reduceHitpoint": "70",
"x": "12",
"y": "12",
"isLootable": "True",
"isRemoveable": "True",
"isEquipped": "True"
}
]
}
its important that your variables correspond to the right keys in the json file thou so if the property on AttackItem is string Name it needs to be "Name" in the json not "name"
Protagonist
ProtagonistOP2y ago
Oh okay i see thank you i thought here it was just like the sectionName
Pobiega
Pobiega2y ago
no this is direct object deserialization the structure and names of your json must exactly match your classes
Protagonist
ProtagonistOP2y ago
that makes sense but heres another question
Protagonist
ProtagonistOP2y ago
Protagonist
ProtagonistOP2y ago
im inheriting from the worldobject class
Pobiega
Pobiega2y ago
thats fine.
Protagonist
ProtagonistOP2y ago
so some properties arent in the attackitem itself
Pobiega
Pobiega2y ago
thats fine.
Protagonist
ProtagonistOP2y ago
would the json file know this?
Pobiega
Pobiega2y ago
yes. or rather, the deserializer doesnt care AttackItem DOES have a Name property, even if its not declared inside AttackItem thats how inheritance works the child has the props of the parent, even if they are not declared there
Protagonist
ProtagonistOP2y ago
even if i dont specify it i can still say the attackitem has a name? thats nie nice
Pobiega
Pobiega2y ago
well yes, because it does
var x = new AttackItem();
x.Name = "Steve";
var x = new AttackItem();
x.Name = "Steve";
is valid (except for the fact that you dont have an empty ctor, but thats not important here)
Protagonist
ProtagonistOP2y ago
I didnt know that thank you what about the Position property in this case, im using x and y to map it in the json file what would i name those
Pobiega
Pobiega2y ago
what is a Position?
Protagonist
ProtagonistOP2y ago
The position of the creature or worldobjects so x and Y
Pobiega
Pobiega2y ago
class Position
{
public int X { get; set; }
public int Y { get; set; }
}
class Position
{
public int X { get; set; }
public int Y { get; set; }
}
?
Protagonist
ProtagonistOP2y ago
yes
Protagonist
ProtagonistOP2y ago
Protagonist
ProtagonistOP2y ago
everything has a position
Pobiega
Pobiega2y ago
{
"Name": "dagger",
"Damage": "10",
"Position": {
"X": "23",
"Y": "25"
},
"Range": "5",
"IsLootable": "True",
"IsRemoveable": "True",
"IsEquipped": "True"
}
{
"Name": "dagger",
"Damage": "10",
"Position": {
"X": "23",
"Y": "25"
},
"Range": "5",
"IsLootable": "True",
"IsRemoveable": "True",
"IsEquipped": "True"
}
Protagonist
ProtagonistOP2y ago
I see does the placement of the properties matter or no
Pobiega
Pobiega2y ago
nope just names and values
Protagonist
ProtagonistOP2y ago
so i was just thinking the Creature has a IsDead prop, for the bools like IsDead, IsEquipped etc. Do i have to put like a default value to it in the json file
Pobiega
Pobiega2y ago
no
Protagonist
ProtagonistOP2y ago
also do i have to mention all the properties of a class in there
Pobiega
Pobiega2y ago
they will by default have their default values, if left out of the json nope, if you are fine with them having their default value you can leave em out
Protagonist
ProtagonistOP2y ago
Protagonist
ProtagonistOP2y ago
wouldnt i need to parse all the integers
Pobiega
Pobiega2y ago
no oh sorry, you stringified your numbers dont do that
"Position": {
"X": 23,
"Y": 25
},
"Position": {
"X": 23,
"Y": 25
},
etc numbers should be numbers in json, not strings
Protagonist
ProtagonistOP2y ago
Makes sense
Protagonist
ProtagonistOP2y ago
"AttackItems": [ { "Name": "sword", "Hitpoint": 10, "Position": { "X": 23, "Y": 25 }, "Range": 5, "IsLootable": "True", "IsRemoveable": "True", "IsEquipped": "True" },
Protagonist
ProtagonistOP2y ago
Everything matches here right? System.InvalidOperationException: 'Each parameter in the deserialization constructor on type '_2DGameLibrary.AttackItem' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. The match can be case-insensitive.'
Pobiega
Pobiega2y ago
Your constructor doesnt match. Either make a parameterless one or one that matches the json
Protagonist
ProtagonistOP2y ago
so it matches with the params in the constructor instead of the actual properties itself
Pobiega
Pobiega2y ago
It can do either But the object must be constructed That's the rules of C# itself
Protagonist
ProtagonistOP2y ago
so why was it complaining earlier with the attack items naming Exception thrown: 'System.Text.Json.JsonException' in System.Text.Json.dll An unhandled exception of type 'System.Text.Json.JsonException' occurred in System.Text.Json.dll The JSON value could not be converted to System.Collections.Generic.List1[_2DGameLibrary.Creature].`
public Creature(string name, Position position, int hp)
{
Name = name;
Position = position;
HP = hp;
AttackItems = new List<AttackItem>();
DefenceItems = new List<DefenceItem>();
}
public Creature(string name, Position position, int hp)
{
Name = name;
Position = position;
HP = hp;
AttackItems = new List<AttackItem>();
DefenceItems = new List<DefenceItem>();
}
i dont put the IsDead inside the ctor but i tried earlier to give it a value in the ctor and still the same exception shows up
Angius
Angius2y ago
Looks like the JSON doesn't match the class Or it doesn't represent a list
Protagonist
ProtagonistOP2y ago
But it does ive even made sure it does
Protagonist
ProtagonistOP2y ago
Protagonist
ProtagonistOP2y ago
{
"maxX": 100,
"maxY": 100,
"creatures": [
{
"name": "Steve",
"position": {
"x": 10,
"y": 10
},
"hp": 100,
"attackItems": [],
"defenceItems": []
},
{
"name": "Bob",
"position": {
"x": 20,
"y": 20
},
"hp": 100,
"attackItems": [],
"defenceItems": []
}
],
"attackItems": [
{
"name": "sword",
"hitpoint": 10,
"position": {
"x": 23,
"y": 25
},
"range": 5,
"isLootable": true,
"isRemoveable": true,
"isEquipped": true
},
{
"name": "dagger",
"hitpoint": 10,
"position": {
"x": 15,
"y": 15
},
"range": 5,
"isLootable": true,
"isRemoveable": true,
"isEquipped": true
}
],
"defenceItems": [
{
"name": "Chestplate",
"reduceHitpoint": 70,
"position": {
"x": 12,
"y": 12
},
"isLootable": true,
"isRemoveable": true,
"isEquipped": true
}
]
}
{
"maxX": 100,
"maxY": 100,
"creatures": [
{
"name": "Steve",
"position": {
"x": 10,
"y": 10
},
"hp": 100,
"attackItems": [],
"defenceItems": []
},
{
"name": "Bob",
"position": {
"x": 20,
"y": 20
},
"hp": 100,
"attackItems": [],
"defenceItems": []
}
],
"attackItems": [
{
"name": "sword",
"hitpoint": 10,
"position": {
"x": 23,
"y": 25
},
"range": 5,
"isLootable": true,
"isRemoveable": true,
"isEquipped": true
},
{
"name": "dagger",
"hitpoint": 10,
"position": {
"x": 15,
"y": 15
},
"range": 5,
"isLootable": true,
"isRemoveable": true,
"isEquipped": true
}
],
"defenceItems": [
{
"name": "Chestplate",
"reduceHitpoint": 70,
"position": {
"x": 12,
"y": 12
},
"isLootable": true,
"isRemoveable": true,
"isEquipped": true
}
]
}
its specific to the creature section does it not look accurate
Angius
Angius2y ago
And you're trying to deserialize this JSON to List<Creature>?
Protagonist
ProtagonistOP2y ago
Yes because the world has a list of creatures World object*
Angius
Angius2y ago
Angius
Angius2y ago
A List<T> doesn't have maxX or maxY properties Nor does it have a creatures property
Protagonist
ProtagonistOP2y ago
One second
public class World
{
public int MaxX { get; set; }
public int MaxY { get; set; }
public List<Creature> Creatures { get; set; }
public List<AttackItem> AttackItems { get; set; }
public List<DefenceItem> DefenceItems { get; set; }

public World(int maxX, int maxY)
{
MaxX = maxX;
MaxY = maxY;
Creatures = new();
AttackItems = new();
DefenceItems = new();
}
public class World
{
public int MaxX { get; set; }
public int MaxY { get; set; }
public List<Creature> Creatures { get; set; }
public List<AttackItem> AttackItems { get; set; }
public List<DefenceItem> DefenceItems { get; set; }

public World(int maxX, int maxY)
{
MaxX = maxX;
MaxY = maxY;
Creatures = new();
AttackItems = new();
DefenceItems = new();
}
Angius
Angius2y ago
So you are not trying to deserialize it to List<Creature>? But to a World?
Protagonist
ProtagonistOP2y ago
well what im doing here is deseralizing the creatures then adding it to the world:
public static class AppConfigDeserializer
{
public static World DeserializeWorldFromAppConfig(string path)
{
var worldConfig = GetFromJsonFile<World>(path);
var worldSizeX = worldConfig.MaxX;
var worldSizeY = worldConfig.MaxY;

var world = new World(worldSizeX, worldSizeY);

var creatures = DeserializeCreaturesFromAppConfig(path);
var worldObjects = DeserializeWorldObjectsFromAppConfig(path);

foreach (var creature in creatures)
{
world.AddCreature(creature);
}

foreach (var worldObject in worldObjects)
{
world.AddWorldObject(worldObject);
}

return world;
}

public static List<Creature> DeserializeCreaturesFromAppConfig(string path)
{
var creatures = GetFromJsonFile<List<Creature>>(path);

return creatures;
}

public static List<WorldObject> DeserializeWorldObjectsFromAppConfig(string path)
{
var worldObjects = GetFromJsonFile<List<WorldObject>>(path);

return worldObjects;
}

public static T GetFromJsonFile<T>(string path)
{
var data = File.ReadAllText(path);
return JsonSerializer.Deserialize<T>(data);
}

}
public static class AppConfigDeserializer
{
public static World DeserializeWorldFromAppConfig(string path)
{
var worldConfig = GetFromJsonFile<World>(path);
var worldSizeX = worldConfig.MaxX;
var worldSizeY = worldConfig.MaxY;

var world = new World(worldSizeX, worldSizeY);

var creatures = DeserializeCreaturesFromAppConfig(path);
var worldObjects = DeserializeWorldObjectsFromAppConfig(path);

foreach (var creature in creatures)
{
world.AddCreature(creature);
}

foreach (var worldObject in worldObjects)
{
world.AddWorldObject(worldObject);
}

return world;
}

public static List<Creature> DeserializeCreaturesFromAppConfig(string path)
{
var creatures = GetFromJsonFile<List<Creature>>(path);

return creatures;
}

public static List<WorldObject> DeserializeWorldObjectsFromAppConfig(string path)
{
var worldObjects = GetFromJsonFile<List<WorldObject>>(path);

return worldObjects;
}

public static T GetFromJsonFile<T>(string path)
{
var data = File.ReadAllText(path);
return JsonSerializer.Deserialize<T>(data);
}

}
Angius
Angius2y ago
Deserialize it to a World Since it clearly is a World
Angius
Angius2y ago
It's neither
Angius
Angius2y ago
nor
Protagonist
ProtagonistOP2y ago
so how would i add creatures and worldobjects to the world then
Angius
Angius2y ago
Deserialize the JSON to the World Add a creature to that Done
var world = JsonSerializer.Deserialize<World>(json_string);
world.Creatures.Add(...);
world.WorldObjects.Add(...);
var world = JsonSerializer.Deserialize<World>(json_string);
world.Creatures.Add(...);
world.WorldObjects.Add(...);
Protagonist
ProtagonistOP2y ago
I dont get it, Theres a method that returns all the creatures from the json file and another with the of worldobjects, then we are adding all of these inside the world what am i changing exactly
Angius
Angius2y ago
What? You wanted to add a creature to the world, no? So you take the world Take the list of creatures in it And add a creature to that list You can't just pick and choose which part of the JSON you want to deserialize You deserialize all of it, then you modify the parts you need
Protagonist
ProtagonistOP2y ago
im new to all of this, can you show me a step towards the right direction code wise?
MODiX
MODiX2y ago
Angius#1586
sharplab.io (click here)
// Helpers
string MockReadFile(string file) => """ {
"X": 67,
"Y": 78,
"Name": "Lorem Ipsum",
"Things": [ {
"Name": "Cat",
"X": 89,
"Y": 18,
"Exists": true
// 41 more lines. Follow the link to view.
// Helpers
string MockReadFile(string file) => """ {
"X": 67,
"Y": 78,
"Name": "Lorem Ipsum",
"Things": [ {
"Name": "Cat",
"X": 89,
"Y": 18,
"Exists": true
// 41 more lines. Follow the link to view.
React with ❌ to remove this embed.
Angius
Angius2y ago
Here's an example
Protagonist
ProtagonistOP2y ago
but you are making the things and world inside the code the whole point of this is to make it configurable so everything is made inside the file then we just add them but in this case its hardcoded?
Angius
Angius2y ago
MockReadFile returns a JSON string Like what you would read from a file Replace it with File.ReadAllText() and there
Protagonist
ProtagonistOP2y ago
public static T GetFromJsonFile<T>(string path) { var data = File.ReadAllText(path); return JsonSerializer.Deserialize<T>(data); } but this? doesnt this read everything already?
Angius
Angius2y ago
Yeah, and it deserializes to a T That T has to be a representation of the JSON In my example, I could not use your GetFromJsonFile<List<Thing>>() Because the JSON I'm trying to get is not a List<Thing> It's a World So only GetFromJsonFile<World>() will work The generic parameter in JsonSerializer.Deserialize<T>() is not there to let you pick and choose which fragment of the JSON you want It's to pass a type that represents the JSON as a whole
Protagonist
ProtagonistOP2y ago
i believe i have fixed these errors thank you although more errors on the rise now 🙂
Protagonist
ProtagonistOP2y ago
kek
Protagonist
ProtagonistOP2y ago
its because nothing is being added to the world
Angius
Angius2y ago
It's because there are no creatures
Protagonist
ProtagonistOP2y ago
There are creatures in the json file
Angius
Angius2y ago
The error begs to differ Use the debugger to see what world actually contains
Protagonist
ProtagonistOP2y ago
nothing in any of its lists
Protagonist
ProtagonistOP2y ago
Angius
Angius2y ago
Naming matters foo is not the same as Foo So use PascalCase names in your JSON, like in your classes Or use JsonSerializerOptions to set up case-insensitive serialization
Protagonist
ProtagonistOP2y ago
"creatures": [ { "name": "Steve", "position": { "x": 10, "y": 10 }, "hp": 100, "attackItems": [], "defenceItems": [], "isDead": false }, { "name": "Bob", "position": { "x": 20, "y": 20 }, "hp": 100, "attackItems": [], "defenceItems": [], "isDead": false } do these refer to the properties or the ctor's param names
Angius
Angius2y ago
Properties You don't need the constructor for deserializing JSON It always uses the default, parameterless constructor, and then sets the properties
Protagonist
ProtagonistOP2y ago
Okay so i made the Creatures work System.InvalidOperationException: 'Each parameter in the deserialization constructor on type '_2DGameLibrary.AttackItem' must bind to an object property or field on deserialization. Each parameter name must match with a property or field on the object. The match can be case-insensitive.' this is what i get on the attackitems prob will get the same on defence items
Angius
Angius2y ago
Try just deleting the constructor?
Protagonist
ProtagonistOP2y ago
"AttackItems": [ { "Name": "sword", "Hitpoint": 10, "Position": { "X": 23, "Y": 25 }, "Range": 5, "IsLootable": true, "IsRemoveable": true }, { "Name": "dagger", "Hitpoint": 10, "Position": { "X": 15, "Y": 15 }, "Range": 5, "IsLootable": true, "IsRemoveable": true } ],
Protagonist
ProtagonistOP2y ago
oof it worked what does the ctor have to do also it seems to have added everything twice why did that interfere
Angius
Angius2y ago
Json serializer tries to use the default constructor and then sets the properties. In case there's no default constructor, one is provided, it has to be specifically set up. Every property needs to be set, there can't be more params than properties, and so on I don't understand that fully I just know it's a pain, so I don't use constructors for classes I'm serializing required properties do the job
Protagonist
ProtagonistOP2y ago
i see, thank you Everythings finally working, thank you guys ❤️ Now onto the next tasks zzzz Btw you see for tracing and logging, is this wrong?
Protagonist
ProtagonistOP2y ago
Protagonist
ProtagonistOP2y ago
since it logs important things
Angius
Angius2y ago
Looks good to me Depends on how you do this logging, though, I'd probably get fancy with changing the colour depending on the log level
Protagonist
ProtagonistOP2y ago
oo that sounds nice
Protagonist
ProtagonistOP2y ago
to me using even 3 of these would make sense if i had different types of creatures but i only have one type
Protagonist
ProtagonistOP2y ago
how else would i make these work
Protagonist
ProtagonistOP2y ago
these are all my classes
Protagonist
ProtagonistOP2y ago
Also, to add on i dont think theres a reason but interfaces or abstract classes? should i add any here
Pobiega
Pobiega2y ago
This is getting dangerously close to "do my assignment for me" territory
Protagonist
ProtagonistOP2y ago
i'd disagree, the logic was all done already, it was just configuration that i havent heard of and a question about if my logging was done correctly. Also im just asking for some insight on what design patterns would make sense since i only have one type of creature The way i worded it made it seem otherwise my apologies
Pobiega
Pobiega2y ago
Not the config stuff The whole "what design patterns should I apply and how, and interfaces/abstract" stuff Normally you pick design patterns before coding your entire app :p
Protagonist
ProtagonistOP2y ago
oopsies Not how but I need to pick 3 design patterns its the requiremnet but looking at most of them they would only make sense if i had more than one creature
Pobiega
Pobiega2y ago
Yeah, for a simple app like this most patterns would just make the code harder to read
Protagonist
ProtagonistOP2y ago
can you suggest 3 that would make sense with what i currently have?
Pobiega
Pobiega2y ago
No. That would fall under "do the assignment for you" umbrella You need to think about your design and what patterns would make sense, that's the point
Protagonist
ProtagonistOP2y ago
Yh youre right apologies what if none of these apply to my application but i would still need to use 3 does that mean id have to go back and update all the logic again
Pobiega
Pobiega2y ago
To some extent, yes. But if you are ok with it being "bad" it won't be an entire rewrite You could slap on a factory literally just for the sake of it, but it would be obvious that's what it was If the pattern doesn't solve any problems, it tends to stand out
Protagonist
ProtagonistOP2y ago
Does the pattern have to be for multiple classes or can it just be for one class Right now i have nothing to solve but my main class (creature class) has no use of any design patterns but it does follow OOP and SOLID principles
Pobiega
Pobiega2y ago
I mean, thats for you and/or your professor to decide? you could just slap a "CreatureFactory" in there and call it done but it would feel "slapped on" 🙂
Protagonist
ProtagonistOP2y ago
the thing is its a requirement so i have to if i do that im sure the teacher would point it out what and why and how will be asked
Pobiega
Pobiega2y ago
then you might need to redo parts of your app. Strategy pattern could be used to give your creatures different AI for example
Protagonist
ProtagonistOP2y ago
For example if i add "Types" and they dont have anything special other than it being a certain type and thats all would that count as useless or could it contribute towards a factory or decorator design?
Pobiega
Pobiega2y ago
once again, thats up to your professor to decide. IMHO If you just add a decorator pattern for the sake of adding one, that shouldnt count you likely didnt learn anything
Protagonist
ProtagonistOP2y ago
what if i add one for types of movement so i have a move method and if the creature can swim or fly or crawl or walk
Pobiega
Pobiega2y ago
swim/fly/walk makes sense, if you add in obstacles water/trees etc
Protagonist
ProtagonistOP2y ago
what if we say crawl/walk/fly
Pobiega
Pobiega2y ago
how is crawl/walk different
Protagonist
ProtagonistOP2y ago
other than just states of moving, nothing but what if it belongs to a certain type of creature? maybe i could do like move +2 x and y with crawl
Pobiega
Pobiega2y ago
then isnt that just a prop on Creature?
Protagonist
ProtagonistOP2y ago
it is if it doesnt include any "benefits"
Pobiega
Pobiega2y ago
yup.
Protagonist
ProtagonistOP2y ago
if i do this would it be okay?
Pobiega
Pobiega2y ago
¯\_(ツ)_/¯ sure
Protagonist
ProtagonistOP2y ago
public class Dragon : Creature
{
public override List<AttackItem> AttackItems
{
get
{
foreach (var item in base.AttackItems)
{
item.Hitpoint += 5;
}
return base.AttackItems;
}
set { base.AttackItems = value; }
}


public Dragon(string name, Position position, int hp) : base(name, position, hp + 50)
{
Type = "Dragon";

}

public override void Move(int x, int y, World world)
{
base.Move(x + 2, y + 2, world);
}
}
public class Dragon : Creature
{
public override List<AttackItem> AttackItems
{
get
{
foreach (var item in base.AttackItems)
{
item.Hitpoint += 5;
}
return base.AttackItems;
}
set { base.AttackItems = value; }
}


public Dragon(string name, Position position, int hp) : base(name, position, hp + 50)
{
Type = "Dragon";

}

public override void Move(int x, int y, World world)
{
base.Move(x + 2, y + 2, world);
}
}
public class CreatureFactory
{
public static Creature Create(string creatureType, string name, Position position, int hp)
{
return creatureType.ToLower() switch
{
"dragon" => new Dragon(name, position, hp) { Type = "Dragon" },
"basilisk" => new Basilisk(name, position, hp) { Type = "Basilisk" },
_ => throw new ArgumentException("Invalid creature type"),
};
}


}
public class CreatureFactory
{
public static Creature Create(string creatureType, string name, Position position, int hp)
{
return creatureType.ToLower() switch
{
"dragon" => new Dragon(name, position, hp) { Type = "Dragon" },
"basilisk" => new Basilisk(name, position, hp) { Type = "Basilisk" },
_ => throw new ArgumentException("Invalid creature type"),
};
}


}
okay so, does this count as factory design pattern satisfy*
Florian Voß
Florian Voß2y ago
yes
Protagonist
ProtagonistOP2y ago
oo good
Protagonist
ProtagonistOP2y ago
ive also added decorator class
Protagonist
ProtagonistOP2y ago
thats 2/3 i wanted to ask, i have a logging system. I was wondering if that would technically count as an Observer design pattern
Protagonist
ProtagonistOP2y ago
Looks like this:
Protagonist
ProtagonistOP2y ago
Does this count? If so ive finally done 3/3
Florian Voß
Florian Voß2y ago
if you have a Subject that can notify a List of observers and update each observer then yes it should count as observer pattern. That is if you programmed towards abstractions and not concretions and the observers gotta be able to add and remove themselves to the list of observers
Pobiega
Pobiega2y ago
"dragon" => new Dragon(name, position, hp) { Type = "Dragon" }, Type should likely not be a string, and even if it should it should be set by the class (you don't want a Dragon instance with a type of "Cheese"), not as a settable field. public string Type { get; } = "Dragon"; in your dragon class would do this.
Florian Voß
Florian Voß2y ago
I agree that this is a code smell to pass the type as string to the Create method but I saw it implemented the exact same way when searching for factory pattern online. I think the best way would be to make the Create method or even the whole class generic instead:
public static Creature Create<T>(string name, Position position, int hp) where T : Creature, new(){
return new T(){
Name = name,
Position = position,
Hp = hp
};
}
public static Creature Create<T>(string name, Position position, int hp) where T : Creature, new(){
return new T(){
Name = name,
Position = position,
Hp = hp
};
}
Protagonist
ProtagonistOP2y ago
I dont have any classes or anything, just a loggin system. So im assuming this wouldnt count towards an "Observer" Pattern but its still notifiying when things are done and updates the user in a way, so could it not be counted as a observer design pattern even if its a string then putting something as "cheese" wouldnt count as a creature with the way i set the Create method up:
public static Creature Create(string creatureType, string name, Position position, int hp)
{
return creatureType.ToLower() switch
{
"dragon" => new Dragon(name, position, hp) { Type = "Dragon" },
"basilisk" => new Basilisk(name, position, hp) { Type = "Basilisk" },
_ => throw new ArgumentException("Invalid creature type"),
};
}
public static Creature Create(string creatureType, string name, Position position, int hp)
{
return creatureType.ToLower() switch
{
"dragon" => new Dragon(name, position, hp) { Type = "Dragon" },
"basilisk" => new Basilisk(name, position, hp) { Type = "Basilisk" },
_ => throw new ArgumentException("Invalid creature type"),
};
}
if its something other then these two it will throw an exception also its better this way because of my json file i can go back to these decorators anyway, im just wanting to know if the logging system will count towards an observer design pattern
Pobiega
Pobiega2y ago
I don't mean the input string
Protagonist
ProtagonistOP2y ago
oh the type for Type itself
Pobiega
Pobiega2y ago
I mean the hardcoded string value assigned to the Type property in your initializers That should not be specified here, imho
Protagonist
ProtagonistOP2y ago
but i dont think it should be a param for the method is that what you was thinking? then i pass it to the creature
Pobiega
Pobiega2y ago
No, it should be set in the classes Like so
Protagonist
ProtagonistOP2y ago
public Dragon(string name, Position position, int hp) : base(name, position, hp + 50) { Type = "Dragon";
} this is how ive set it since type is in the creature class
Pobiega
Pobiega2y ago
It should be marked abstract, or specified via an interface And as a get only property
Protagonist
ProtagonistOP2y ago
its just set as a property in the Creature Class:
public class Creature {
public string Type { get; set; }
}
public class Creature {
public string Type { get; set; }
}
should i just pass it in the dragons ctor? that way it wont be hard coded anymore thats one solution also this? any insight on this
Pobiega
Pobiega2y ago
... how would logging be related to the observer pattern? It's absolutely not
Protagonist
ProtagonistOP2y ago
because technically its updating the user if updates that happen maybe similar is the word
Pobiega
Pobiega2y ago
No. Not at all. That you are even trying to argue that tells me you have no idea what the observer pattern is :p
Protagonist
ProtagonistOP2y ago
not arguing just thinking
Pobiega
Pobiega2y ago
your code calling Console.WriteLine is NOT an implementation of a specific pattern
Protagonist
ProtagonistOP2y ago
That means even tracing wouldnt count correct
public static void Info(string message)
{
Console.ForegroundColor = ConsoleColor.Green;
_traceSource.TraceEvent(TraceEventType.Information, _id, message);
_id++;
_traceSource.Flush();
Console.ResetColor();
}
public static void Info(string message)
{
Console.ForegroundColor = ConsoleColor.Green;
_traceSource.TraceEvent(TraceEventType.Information, _id, message);
_id++;
_traceSource.Flush();
Console.ResetColor();
}
The thing is im stuck right now ive chosen 2/3 patterns
Pobiega
Pobiega2y ago
strategy seems like a low hanging fruit
Protagonist
ProtagonistOP2y ago
i tried doing strategy yesterday and my code blew up
Pobiega
Pobiega2y ago
you could have your creatures use a strategy implementation for their "thinking"
Protagonist
ProtagonistOP2y ago
i tried doing it with movement
Pobiega
Pobiega2y ago
so two dragons might behave differently
Protagonist
ProtagonistOP2y ago
public class Dragon : Creature
{
public Dragon(string name, Position position, int hp) : base(name, position, hp + 50)
{
Type = "Dragon";
}

public override void Move(int x, int y, World world)
{
base.Move(x + 2, y + 2, world);
// this creature flies writeline or something?
}
}
public class Dragon : Creature
{
public Dragon(string name, Position position, int hp) : base(name, position, hp + 50)
{
Type = "Dragon";
}

public override void Move(int x, int y, World world)
{
base.Move(x + 2, y + 2, world);
// this creature flies writeline or something?
}
}
i was thinking each type of creature will move differently something like this i implemented an interface called Imovement yesterday and a Fly movement and tried puttin in logic and so on, but then i remove it all cos it ended up getting confusing and not working the thing is my Move implementation of the code is in the creature class, and i tried making a Defaultimplementation and make it so that creature uses it and then say that when it comes to dragon it will fly, so print out fly and move x + 2 and y+ 2 but this didnt end up working
public class BasicMovement : IMovement
{
public virtual void Move(int x, int y, World world, Creature creature)
{
int newX = creature.Position.X + x;
int newY = creature.Position.Y + y;

// Check if the new position is outside the world's boundaries
if (newX < 0 || newY < 0 || newX >= world.MaxX || newY >= world.MaxY)
{
Logger.Warning($"Cannot move {creature.Type} {creature.Name} to ({newX}, {newY}). Movement outside world boundaries.");
return;
}

// Check if there are any obstacles in the way
if (CheckObstacles(newX, newY, creature))
{
Logger.Warning($"Obstacle detected. Cannot move {creature.Type}{creature.Name}.");
return;
}

// Move the creature
creature.Position.X = newX;
creature.Position.Y = newY;
}

private bool CheckObstacles(int x, int y, Creature creature)
{
// Check if there are any attack or defense items in the way
foreach (AttackItem item in creature.AttackItems)
{
if (item.Position.X == x && item.Position.Y == y)
{
return true; // obstacle found
}
}

foreach (DefenceItem item in creature.DefenceItems)
{
if (item.Position.X == x && item.Position.Y == y)
{
return true; // obstacle found
}
}

return false; // no obstacles found
}
}

public class FastMovement : BasicMovement
{
public override void Move(int x, int y, World world, Creature creature)
{
base.Move(x + 2, y + 2, world, creature);
}
}
public class BasicMovement : IMovement
{
public virtual void Move(int x, int y, World world, Creature creature)
{
int newX = creature.Position.X + x;
int newY = creature.Position.Y + y;

// Check if the new position is outside the world's boundaries
if (newX < 0 || newY < 0 || newX >= world.MaxX || newY >= world.MaxY)
{
Logger.Warning($"Cannot move {creature.Type} {creature.Name} to ({newX}, {newY}). Movement outside world boundaries.");
return;
}

// Check if there are any obstacles in the way
if (CheckObstacles(newX, newY, creature))
{
Logger.Warning($"Obstacle detected. Cannot move {creature.Type}{creature.Name}.");
return;
}

// Move the creature
creature.Position.X = newX;
creature.Position.Y = newY;
}

private bool CheckObstacles(int x, int y, Creature creature)
{
// Check if there are any attack or defense items in the way
foreach (AttackItem item in creature.AttackItems)
{
if (item.Position.X == x && item.Position.Y == y)
{
return true; // obstacle found
}
}

foreach (DefenceItem item in creature.DefenceItems)
{
if (item.Position.X == x && item.Position.Y == y)
{
return true; // obstacle found
}
}

return false; // no obstacles found
}
}

public class FastMovement : BasicMovement
{
public override void Move(int x, int y, World world, Creature creature)
{
base.Move(x + 2, y + 2, world, creature);
}
}
would this be okay for strategy pattern
Florian Voß
Florian Voß2y ago
Strategy Pattern is not only inheritance but also composition. So to complete your code, we let a Creature HAVE a MovementStrategy which delegates the work to the concrete MovementStrategy:
public class Creature{
public IMovement MoveStrategy { get; set; }
public void Move(int x, int y, World world, Creature creature){
MoveStrategy.Move(x, y, world, creature);
}
}
public class Creature{
public IMovement MoveStrategy { get; set; }
public void Move(int x, int y, World world, Creature creature){
MoveStrategy.Move(x, y, world, creature);
}
}
Protagonist
ProtagonistOP2y ago
Mhm i see, thank you Dragon Class
public class Dragon : Creature
{
public Dragon(string name, Position position, int hp) : base(name, position, hp + 50)
{
Type = "Dragon";
Movement = new FlyMovement();
}
}
public class Dragon : Creature
{
public Dragon(string name, Position position, int hp) : base(name, position, hp + 50)
{
Type = "Dragon";
Movement = new FlyMovement();
}
}
FlyMovement Class
public class FlyMovement : DefaultMovement
{
public override void Move(int x, int y, World world, Creature creature)
{
base.Move(x + 2, y + 2, world, creature);
Logger.Info("This Creature is flying");
}
}
public class FlyMovement : DefaultMovement
{
public override void Move(int x, int y, World world, Creature creature)
{
base.Move(x + 2, y + 2, world, creature);
Logger.Info("This Creature is flying");
}
}
Play method in creature class
public static void Play(Creature creature, Creature creature1, World world)
{
// keep track of whose turn it is
Creature currentCreature = creature;

while (!creature.isDead && !creature1.isDead)
{
if (currentCreature == creature)
{
int x = Random.Shared.Next(-5, 6);
int y = Random.Shared.Next(-5, 6);

creature.Move(x, y, world);

Logger.Info($"{creature.Type} {creature.Name} moved to ({creature.Position.X}, {creature.Position.Y})");


// try to loot a nearby object
bool lootSuccess = creature.Loot(world);
if (lootSuccess)
{
Logger.Info($"{creature.Type} {creature.Name} successfully looted an object.");
}
}
...
public static void Play(Creature creature, Creature creature1, World world)
{
// keep track of whose turn it is
Creature currentCreature = creature;

while (!creature.isDead && !creature1.isDead)
{
if (currentCreature == creature)
{
int x = Random.Shared.Next(-5, 6);
int y = Random.Shared.Next(-5, 6);

creature.Move(x, y, world);

Logger.Info($"{creature.Type} {creature.Name} moved to ({creature.Position.X}, {creature.Position.Y})");


// try to loot a nearby object
bool lootSuccess = creature.Loot(world);
if (lootSuccess)
{
Logger.Info($"{creature.Type} {creature.Name} successfully looted an object.");
}
}
...
else
{
// move creature1 to a random location
int x = Random.Shared.Next(-5, 6);
int y = Random.Shared.Next(-5, 6);

creature1.Move(x, y, world);

Logger.Info($"{creature1.Type} {creature1.Name} moved to ({creature1.Position.X}, {creature1.Position.Y})");
// try to loot a nearby object
bool lootSuccess = creature1.Loot(world);
if (lootSuccess)
{
Logger.Info($"{creature1.Type} {creature1.Name} successfully looted an object.");
}
}

// alternate the turns
currentCreature = currentCreature == creature ? creature1 : creature;

// combat happens after each turn
Combat(creature, creature1);

if (creature.isDead)
{
world.RemoveCreature(creature);
Logger.Info($"{creature.Type} {creature.Name} has been removed from the world");
}

if (creature1.isDead)
{
world.RemoveCreature(creature1);
Logger.Info($"{creature1.Type} {creature1.Name} has been removed from the world");
}
}

}
else
{
// move creature1 to a random location
int x = Random.Shared.Next(-5, 6);
int y = Random.Shared.Next(-5, 6);

creature1.Move(x, y, world);

Logger.Info($"{creature1.Type} {creature1.Name} moved to ({creature1.Position.X}, {creature1.Position.Y})");
// try to loot a nearby object
bool lootSuccess = creature1.Loot(world);
if (lootSuccess)
{
Logger.Info($"{creature1.Type} {creature1.Name} successfully looted an object.");
}
}

// alternate the turns
currentCreature = currentCreature == creature ? creature1 : creature;

// combat happens after each turn
Combat(creature, creature1);

if (creature.isDead)
{
world.RemoveCreature(creature);
Logger.Info($"{creature.Type} {creature.Name} has been removed from the world");
}

if (creature1.isDead)
{
world.RemoveCreature(creature1);
Logger.Info($"{creature1.Type} {creature1.Name} has been removed from the world");
}
}

}
Move method in creature class, Movement is default movement where the implementation is
public void Move(int x, int y, World world)
{
Movement.Move(x, y, world, this);
}
public void Move(int x, int y, World world)
{
Movement.Move(x, y, world, this);
}
The FlyMovement is not being triggered
Protagonist
ProtagonistOP2y ago
Protagonist
ProtagonistOP2y ago
it hits dragon but it doesnt seem to take the method for flymovement and uses the defaultmovement instaed
JakenVeina
JakenVeina2y ago
wat
Protagonist
ProtagonistOP2y ago
maybe this would be long to explain since it has many connected parts
JakenVeina
JakenVeina2y ago
little bit I dunno, if you wanna read me in, what's the simplest you can condense the problem?
Protagonist
ProtagonistOP2y ago
I set up a strategy pattern for the movement of a creature, each creature has a "certain movement"
JakenVeina
JakenVeina2y ago
okay like a pre-defined sequence of movements
Protagonist
ProtagonistOP2y ago
public virtual void Move(int x, int y, World world, Creature creature)
public virtual void Move(int x, int y, World world, Creature creature)
this is how the move method looks like in the deafult movement ^ theres code but its too long to put
JakenVeina
JakenVeina2y ago
that's "Move creature within world to position (x, y)"?
Protagonist
ProtagonistOP2y ago
yes
JakenVeina
JakenVeina2y ago
k
Protagonist
ProtagonistOP2y ago
the world has a position so does a creature
public override void Move(int x, int y, World world, Creature creature)
{
base.Move(x + 2, y + 2, world, creature);
Logger.Info("This Creature is flying");
}
public override void Move(int x, int y, World world, Creature creature)
{
base.Move(x + 2, y + 2, world, creature);
Logger.Info("This Creature is flying");
}
this is the flymovement so if the creature flys it will just move +2x and +2y and print the creature is flying
JakenVeina
JakenVeina2y ago
uhhh
Protagonist
ProtagonistOP2y ago
was that confusing?
JakenVeina
JakenVeina2y ago
so, x/y is actually the creature's CURRENT position? the position it's moving from? and the creature moves 2 units diagonally on each tick?
Protagonist
ProtagonistOP2y ago
x/y is a random movement from 0-5, and it gets added to the current creatures position
JakenVeina
JakenVeina2y ago
okay so
Protagonist
ProtagonistOP2y ago
so if i have creature with position 10,10 and x is 2 and y is 5, i should move to 12,15
JakenVeina
JakenVeina2y ago
what does base.Move() do
Protagonist
ProtagonistOP2y ago
^
JakenVeina
JakenVeina2y ago
well then what the fuck is the hard-coded +2s?
Protagonist
ProtagonistOP2y ago
So if u fly u basically have +2 movement does that make sense
JakenVeina
JakenVeina2y ago
nah what does base.Move() do
Protagonist
ProtagonistOP2y ago
public virtual void Move(int x, int y, World world, Creature creature)
{
int newX = creature.Position.X + x;
int newY = creature.Position.Y + y;

// Check if the new position is outside the world's boundaries
if (newX < 0 || newY < 0 || newX >= world.MaxX || newY >= world.MaxY)
{
Logger.Warning($"Cannot move {creature.Type} {creature.Name} to ({newX}, {newY}). Movement outside world boundaries.");
return;
}

// Check if there are any obstacles in the way
if (CheckObstacles(newX, newY, creature))
{
Logger.Warning($"Obstacle detected. Cannot move {creature.Type}{creature.Name}.");
return;
}

// Move the creature
creature.Position.X = newX;
creature.Position.Y = newY;
}

private bool CheckObstacles(int x, int y, Creature creature)
{
// Check if there are any attack or defense items in the way
foreach (AttackItem item in creature.AttackItems)
{
if (item.Position.X == x && item.Position.Y == y)
{
return true; // obstacle found
}
}

foreach (DefenceItem item in creature.DefenceItems)
{
if (item.Position.X == x && item.Position.Y == y)
{
return true; // obstacle found
}
}

return false; // no obstacles found
}
public virtual void Move(int x, int y, World world, Creature creature)
{
int newX = creature.Position.X + x;
int newY = creature.Position.Y + y;

// Check if the new position is outside the world's boundaries
if (newX < 0 || newY < 0 || newX >= world.MaxX || newY >= world.MaxY)
{
Logger.Warning($"Cannot move {creature.Type} {creature.Name} to ({newX}, {newY}). Movement outside world boundaries.");
return;
}

// Check if there are any obstacles in the way
if (CheckObstacles(newX, newY, creature))
{
Logger.Warning($"Obstacle detected. Cannot move {creature.Type}{creature.Name}.");
return;
}

// Move the creature
creature.Position.X = newX;
creature.Position.Y = newY;
}

private bool CheckObstacles(int x, int y, Creature creature)
{
// Check if there are any attack or defense items in the way
foreach (AttackItem item in creature.AttackItems)
{
if (item.Position.X == x && item.Position.Y == y)
{
return true; // obstacle found
}
}

foreach (DefenceItem item in creature.DefenceItems)
{
if (item.Position.X == x && item.Position.Y == y)
{
return true; // obstacle found
}
}

return false; // no obstacles found
}
JakenVeina
JakenVeina2y ago
okay, so x and y are the deltas
Protagonist
ProtagonistOP2y ago
deltas meaning?
JakenVeina
JakenVeina2y ago
they're not x/y coordinates they're a vector a delta vector an amount of change
Protagonist
ProtagonistOP2y ago
yes
JakenVeina
JakenVeina2y ago
and movement is always positive?
Protagonist
ProtagonistOP2y ago
it can be negative
JakenVeina
JakenVeina2y ago
then the +2s definitely don't make sense it sounds more like what you want is to increase the RNG range so, your RNG movement is +/-5 in any direction?
Protagonist
ProtagonistOP2y ago
yes the thing is it might not make sense, because moving - moves u down
JakenVeina
JakenVeina2y ago
with the +2s, you've turned it into +7/-3, with the bias on moving up-right it sounds like what you REALLY want is for flying characters to have random movement of +/-7
Protagonist
ProtagonistOP2y ago
i mean now it sounds off
JakenVeina
JakenVeina2y ago
that's what I'm saying 😉
Protagonist
ProtagonistOP2y ago
A creatures positon can never go beyond the worlds position, so if the world is 100,100, and the creatures position is 10,10 moving - just means moving down now i get that the +2 might not make sense
JakenVeina
JakenVeina2y ago
so
Protagonist
ProtagonistOP2y ago
but i could just add if statements
JakenVeina
JakenVeina2y ago
movement is not in any direction
Protagonist
ProtagonistOP2y ago
well in my head i didnt think about right and left but technically it is every movement
JakenVeina
JakenVeina2y ago
which means that x and y can be negative normally, anywhere form -5 to +5
Protagonist
ProtagonistOP2y ago
it can be negative yes exactly if i do +2 to -5,5 thats -3,7
JakenVeina
JakenVeina2y ago
correct but my point is if the +2 is intended to make flying creatures move faster
Protagonist
ProtagonistOP2y ago
that its pointless? 🤣
JakenVeina
JakenVeina2y ago
that's not what you wrote
Protagonist
ProtagonistOP2y ago
well in this case what does it look like?
JakenVeina
JakenVeina2y ago
it seems like your intention was to give flying creatures +/-7 movement you actually have given them +7/-3 movement which is kinda nonsense you're trying to bias your RNG generation at the wrong spot if your goal is to generate a +/-7 value, you need to specify it that way to the RNG you can't just adjust it after-the-fact to get the same result
Protagonist
ProtagonistOP2y ago
ah so i inputted the wtong numbers wrong
JakenVeina
JakenVeina2y ago
sort of wherever your RNG call is that generates those numbers you have to make the decision THERE
Protagonist
ProtagonistOP2y ago
i wanna leave the -5,5 for rng i can just change what the flymovement does
JakenVeina
JakenVeina2y ago
instead of
var x = rng.Next(-5, 5);
var y = rng.Next(-5, 5);
var x = rng.Next(-5, 5);
var y = rng.Next(-5, 5);
you'd want something like
var x = rng.Next(-creature.MovementSpeed, creature.MovementSpeed);
var y = rng.Next(-creature.MovementSpeed, creature.MovementSpeed);
var x = rng.Next(-creature.MovementSpeed, creature.MovementSpeed);
var y = rng.Next(-creature.MovementSpeed, creature.MovementSpeed);
or probably better yet, move this logic inside the Move method, so each create gets to define for itself how its movement works
Protagonist
ProtagonistOP2y ago
i should move that logic to move yes, but this approach doesnt make sense to me
JakenVeina
JakenVeina2y ago
which one?
Protagonist
ProtagonistOP2y ago
^
JakenVeina
JakenVeina2y ago
what doesn't make sense about it?
Protagonist
ProtagonistOP2y ago
the random numbers -creature.movementspeed
JakenVeina
JakenVeina2y ago
that's not random that's a value defined for each creature
Protagonist
ProtagonistOP2y ago
no no as in how would that work
JakenVeina
JakenVeina2y ago
for normal creatures, it'd be 5 for your flying creatures, you'd define it to be 7
Protagonist
ProtagonistOP2y ago
where is this defined?
JakenVeina
JakenVeina2y ago
maybe some creatures could use 3 where you define it
Protagonist
ProtagonistOP2y ago
wouldnt that just break the move
JakenVeina
JakenVeina2y ago
given that I wrote it as creature.MovementSpeed, my intention would be that you define it on the creature how so?
Protagonist
ProtagonistOP2y ago
x and y properties?
JakenVeina
JakenVeina2y ago
what about them? actually, better question what x and y properties?
Protagonist
ProtagonistOP2y ago
so instead of generating random numbers you want me to have const fields for x and y for each type of creature? or maybe im understanding wrong
JakenVeina
JakenVeina2y ago
no
Protagonist
ProtagonistOP2y ago
the way the method is set up i cant just call movement anyway
public IMovement Movement { get; set; } = new DefaultMovement();
public IMovement Movement { get; set; } = new DefaultMovement();
in creature class ^
JakenVeina
JakenVeina2y ago
I would want you to have a property MovementSpeed that is used to generate your random movement values
Protagonist
ProtagonistOP2y ago
so i wouldnt have to "hardcode" anything?
JakenVeina
JakenVeina2y ago
maybe? maybe not depends how you want to implement it
Protagonist
ProtagonistOP2y ago
shouldnt this be done as a part of refactoring?
JakenVeina
JakenVeina2y ago
uhh, sure, you could call it that
Protagonist
ProtagonistOP2y ago
after i finish all my code i can go into each and refactor to be better but before i can refactor im having an issue thats not calling the flymovement method in the dragons ctor its almost always using default movement
JakenVeina
JakenVeina2y ago
okay
Protagonist
ProtagonistOP2y ago
after i figure this issue ill apply the movement speed thank u but i need some help figuring it out
public class Dragon : Creature
{
public Dragon(string name, Position position, int hp) : base(name, position, hp + 50)
{
Type = "Dragon";
Movement = new FlyMovement();
}
}
public class Dragon : Creature
{
public Dragon(string name, Position position, int hp) : base(name, position, hp + 50)
{
Type = "Dragon";
Movement = new FlyMovement();
}
}
the mvoement is not being reached do u know why?
JakenVeina
JakenVeina2y ago
depends what's calling it
Protagonist
ProtagonistOP2y ago
//Creature class
public IMovement Movement { get; set; } = new DefaultMovement();
...
public void Move(int x, int y, World world)
{
Movement.Move(x, y, world, this);
}
//Creature class
public IMovement Movement { get; set; } = new DefaultMovement();
...
public void Move(int x, int y, World world)
{
Movement.Move(x, y, world, this);
}
when calling move its called on a creature
JakenVeina
JakenVeina2y ago
and what calls that?
Protagonist
ProtagonistOP2y ago
Creature currentCreature = creature;

while (!creature.isDead && !creature1.isDead)
{
if (currentCreature == creature)
{
int x = Random.Shared.Next(-5, 6);
int y = Random.Shared.Next(-5, 6);

creature.Move(x, y, world);
...
Creature currentCreature = creature;

while (!creature.isDead && !creature1.isDead)
{
if (currentCreature == creature)
{
int x = Random.Shared.Next(-5, 6);
int y = Random.Shared.Next(-5, 6);

creature.Move(x, y, world);
...
the method play
JakenVeina
JakenVeina2y ago
k and creature is a Dragon?
Protagonist
ProtagonistOP2y ago
yes
JakenVeina
JakenVeina2y ago
prove it
Protagonist
ProtagonistOP2y ago
well in the json file i have it has type dragon then i deseralize it
JakenVeina
JakenVeina2y ago
okay, but that means nothing it means you WANT it to be a Dragon you expect it to be a Dragon IS it?
Protagonist
ProtagonistOP2y ago
its a creature aha
JakenVeina
JakenVeina2y ago
but is it a Dragon?
Protagonist
ProtagonistOP2y ago
yes it should be
JakenVeina
JakenVeina2y ago
but IS it?
Protagonist
ProtagonistOP2y ago
ublic static Creature Create(string creatureType, string name, Position position, int hp)
{
return creatureType.ToLower() switch
{
"dragon" => new Dragon(name, position, hp) { Type = "Dragon" },
"basilisk" => new Basilisk(name, position, hp) { Type = "Basilisk" },
_ => throw new ArgumentException("Invalid creature type"),
};
}
ublic static Creature Create(string creatureType, string name, Position position, int hp)
{
return creatureType.ToLower() switch
{
"dragon" => new Dragon(name, position, hp) { Type = "Dragon" },
"basilisk" => new Basilisk(name, position, hp) { Type = "Basilisk" },
_ => throw new ArgumentException("Invalid creature type"),
};
}
JakenVeina
JakenVeina2y ago
okay that's great and all
Protagonist
ProtagonistOP2y ago
no it says its a creature
JakenVeina
JakenVeina2y ago
but is creature a Dragon how so?
Protagonist
ProtagonistOP2y ago
no dragon is a creature
JakenVeina
JakenVeina2y ago
correct but is creature a Dragon?
Protagonist
ProtagonistOP2y ago
no it is not
JakenVeina
JakenVeina2y ago
how so?
Protagonist
ProtagonistOP2y ago
creature is a creature
JakenVeina
JakenVeina2y ago
how so? it's rhetorical, show me
Protagonist
ProtagonistOP2y ago
because im calling creature instead of an instance of a dragon?
JakenVeina
JakenVeina2y ago
are you? I'm not even sure what that means
Protagonist
ProtagonistOP2y ago
well i am, but i thought in the method i showed im switching it to a dragon
JakenVeina
JakenVeina2y ago
again it's rhetorical I'm asking what creature is show me
Protagonist
ProtagonistOP2y ago
what am i showing u exactly
JakenVeina
JakenVeina2y ago
the value of creature within the debugger at the point where .Move() is being called
Protagonist
ProtagonistOP2y ago
well first thing i notice is the Type is null when it should be dragon but it should of got that from the json file is that why its not converting to a dragon instance
JakenVeina
JakenVeina2y ago
well, that just suggests more that there's some issue with your deserialization logic or with something in between now, you don't have just one creature, do you? I'm guessing this is inside a loop over many creatures?
Protagonist
ProtagonistOP2y ago
yes it is
JakenVeina
JakenVeina2y ago
well, make sure you're looking at ALL creatures in that loop to see if your expected dragon is in there also, you might consider swapping out your JSON file for one with only one creature, at least until this is debugged but yeah, if there's no dragon in there, then either your deserialization is messed up, or you're screwing something up post-deserialization or, your JSON is malformed which might fall under "deserialization is messed up"
Protagonist
ProtagonistOP2y ago
Protagonist
ProtagonistOP2y ago
okay so this line here works fine it gets the type
JakenVeina
JakenVeina2y ago
and the movement so, you were looking at the wrong creature
Protagonist
ProtagonistOP2y ago
before that, it goes back to null
JakenVeina
JakenVeina2y ago
or that creature is getting lost uhh yeah
Protagonist
ProtagonistOP2y ago
the Type how
JakenVeina
JakenVeina2y ago
cause you told it to you're replacing it you just took the creature object that you verified was correct, and replaced it with a different object you don't see where maybe the problem is?
Protagonist
ProtagonistOP2y ago
aha my mind totally went blank
JakenVeina
JakenVeina2y ago
😉
Protagonist
ProtagonistOP2y ago
that makes sense now
JakenVeina
JakenVeina2y ago
🎉 your decorator appears to be malfunctioning
Protagonist
ProtagonistOP2y ago
does this work?
new AttackBoostDecorator(baseCreature);
new AttackBoostDecorator(baseCreature);
JakenVeina
JakenVeina2y ago
define "work"
Protagonist
ProtagonistOP2y ago
well before i was putting it in the object will this still apply it to the basecreature?
JakenVeina
JakenVeina2y ago
apply what?
Protagonist
ProtagonistOP2y ago
the decorator it just adds +5 hitpoints to all attackitens
JakenVeina
JakenVeina2y ago
I mean it does what you've coded it to do the decorator pattern is perfectly valid not my personal taste, but it's well-established if you applying a decorator to this object makes it lose the properties you expect it to have like Type = "Dragon" and Movement = FlyMovement then yeah, I'd say it's not working dig in and figure out why
Protagonist
ProtagonistOP2y ago
before that i should check if the movement is working the fly that is
JakenVeina
JakenVeina2y ago
I thought we already established that it's not? I thought that was the whole point of this conversation?
Protagonist
ProtagonistOP2y ago
yh but now that the type is assigned to dragon it should well not the type
JakenVeina
JakenVeina2y ago
but you didn't change anything yet did you? we JUST established that the Type and Movement are wrong on account of the decorator so you're going to go back and check again if they're still wrong, before doing anything to the decorator?
Protagonist
ProtagonistOP2y ago
I just wanted to check if the creature was now pointing to Dragon
Protagonist
ProtagonistOP2y ago
Protagonist
ProtagonistOP2y ago
but i guess i should fix the decorator its nearly 5am so excuse the brain deadness
JakenVeina
JakenVeina2y ago
I officially have no idea what's going on
Protagonist
ProtagonistOP2y ago
Okay lets retrack We wanted the flyMovement to trigger, but our creature was still of type creature and wasnt correctly being assigned to dragon thats the most part
JakenVeina
JakenVeina2y ago
no it was of type AttackBoostDecorator
Protagonist
ProtagonistOP2y ago
yes sorry ^ you said there was something wrong with the decorator class
JakenVeina
JakenVeina2y ago
cause that's what you showed me you showed me that the Dragon object was getting deserialized correctly and then immediately after, was getting wrapped in an AttackBoostDecorator which you then showed was invalid
Protagonist
ProtagonistOP2y ago
Yes
JakenVeina
JakenVeina2y ago
so
Protagonist
ProtagonistOP2y ago
how would i call the decorator to the dragon now tho
JakenVeina
JakenVeina2y ago
what do you mean?
Protagonist
ProtagonistOP2y ago
as in i want the attackdecorator class to be assigned to dragon class im not sure of how i can apply the decorator now to it
public class Dragon : Creature
{
public Dragon(string name, Position position, int hp) : base(name, position, hp + 50)
{
Type = "Dragon";
Movement = new FlyMovement();
CreatureDecorator = new AttackBoostDecorator(this);
}
}
public class Dragon : Creature
{
public Dragon(string name, Position position, int hp) : base(name, position, hp + 50)
{
Type = "Dragon";
Movement = new FlyMovement();
CreatureDecorator = new AttackBoostDecorator(this);
}
}
i did it like this indtead instead there ive resolved my issues Thank you although now i need to fix flymovement doesnt seem to add +2 to x and y
JakenVeina
JakenVeina2y ago
that's no longer a decorator a decorator is supposed to wrap an existing object, invisibly, allowing it to affect the object's behavior AttachBoostDecorator presumably, wants to affect the attacking behavior of the creature it wraps around meaning the other properties and behaviors of the object should be unaffected meaning the decorator should be forwarding them from the wrapped object which it seems to not have been doing
Protagonist
ProtagonistOP2y ago
i see how would i apply it to my object then since im already applying something else to it
JakenVeina
JakenVeina2y ago
huh? you apply it to your object the way you were already doing that's the decorator pattern you wrap an existing object what other thing are you "applying" to it? and how does that stop you from applying a decorator?
Protagonist
ProtagonistOP2y ago
yes but then we had problems
case "Dragon":
baseCreature = CreatureFactory.Create(creature.Type, creature.Name, creature.Position, creature.Hp);
baseCreature = new AttackBoostDecorator(baseCreature);
break;
case "Dragon":
baseCreature = CreatureFactory.Create(creature.Type, creature.Name, creature.Position, creature.Hp);
baseCreature = new AttackBoostDecorator(baseCreature);
break;
JakenVeina
JakenVeina2y ago
right because of your decorator go fix your decorator
Protagonist
ProtagonistOP2y ago
make it static?
JakenVeina
JakenVeina2y ago
no? make it do what it's supposed to do decorate the object it's been given
MODiX
MODiX2y ago
JakenVeina#1758
a decorator is supposed to wrap an existing object, invisibly, allowing it to affect the object's behavior
Quoted by
<@!137791696325836800> from #Design Pattern (click here)
React with ❌ to remove this embed.
MODiX
MODiX2y ago
JakenVeina#1758
meaning the other properties and behaviors of the object should be unaffected
Quoted by
<@!137791696325836800> from #Design Pattern (click here)
React with ❌ to remove this embed.
Protagonist
ProtagonistOP2y ago
This first time ive done anything with design patterns so im not sure
case "Dragon":
baseCreature = CreatureFactory.Create(creature.Type, creature.Name, creature.Position, creature.Hp);
baseCreature = new AttackBoostDecorator(baseCreature);
break;
case "Dragon":
baseCreature = CreatureFactory.Create(creature.Type, creature.Name, creature.Position, creature.Hp);
baseCreature = new AttackBoostDecorator(baseCreature);
break;
so your saying with the correct implementation in the decorator, this code here should function as intended? i was just doing things based off searching design patterns
JakenVeina
JakenVeina2y ago
yes, absolutely both the Dragon creature and AttackBoostDecorator are Creatures they should be indistinguishable, if you compare them, except that the AttackBoostDecorator will exhibit a different behavior for attacking whatever that means when you call AttackBoostDecorator.Type it should be returning the .Type value of the Creature that it's decorating because that's not related to attacking same for .Movement the fact that it's not doing that means the decorator class itself is misbehaving
Protagonist
ProtagonistOP2y ago
ah okay i think i see now
public abstract class CreatureDecorator : Creature
{
protected Creature BaseCreature;

public CreatureDecorator(Creature baseCreature) : base(baseCreature.Name, baseCreature.Position, baseCreature.Hp)
{
BaseCreature = baseCreature;
Name = baseCreature.Name;
Position = baseCreature.Position;
Hp = baseCreature.Hp;
DefenceItems = baseCreature.DefenceItems;
Type = baseCreature.Type;
Movement = baseCreature.Movement;
AttackItems = baseCreature.AttackItems;
}
}
public abstract class CreatureDecorator : Creature
{
protected Creature BaseCreature;

public CreatureDecorator(Creature baseCreature) : base(baseCreature.Name, baseCreature.Position, baseCreature.Hp)
{
BaseCreature = baseCreature;
Name = baseCreature.Name;
Position = baseCreature.Position;
Hp = baseCreature.Hp;
DefenceItems = baseCreature.DefenceItems;
Type = baseCreature.Type;
Movement = baseCreature.Movement;
AttackItems = baseCreature.AttackItems;
}
}
JakenVeina
JakenVeina2y ago
that's about the least efficient way to do it, but yes
Protagonist
ProtagonistOP2y ago
would i have to override each property?
JakenVeina
JakenVeina2y ago
that would be a more-efficient way to do it at least, memory-wise
Protagonist
ProtagonistOP2y ago
so if i had a lot of properties i should always override or should i always almost override whats best practice
JakenVeina
JakenVeina2y ago
I mean, I'm biased, cause my answer is gonna be "don't use decorators" 90% of the time but IMO, overriding properties beats duplicating them I.E. don't double your memory footprint
Protagonist
ProtagonistOP2y ago
im just using for the sake of it being a requirement but it doesnt sound too shabby
JakenVeina
JakenVeina2y ago
fair enough
Protagonist
ProtagonistOP2y ago
also i do agree with overriding and saving memory
JakenVeina
JakenVeina2y ago
it's a decent exercise in how inheritance works
Protagonist
ProtagonistOP2y ago
but i didnt know doing it like this doubles the memory thats true
JakenVeina
JakenVeina2y ago
in a hand-wavy sort of way your orignal object takes up enough memory to store 10 fields (let's say), plus a little bit for metadata about the object itself, like its type if the decorator just duplicates all the fields, then, it also takes up enough memory to store 10 fields I.E. creating a decorator and an object to be decorated allocates twice as much memory as just allocating the object you can at least the extra memory needed to store the 10 fields can't eliminate the overhead of the decorator object itself cause
public string MyProperty { get; set; }
public string MyProperty { get; set; }
is equivalent to
public string MyProperty
{
get => _myProperty;
set => _myProperty = value;
}
private string _myProperty;
public string MyProperty
{
get => _myProperty;
set => _myProperty = value;
}
private string _myProperty;
I.E. it allocates a string field and if that's on the base class, then both Dragon and AttackBoostDecorator have their own unique field however if you setup the base class as
public abstract string MyProperty { get; set; }
public abstract string MyProperty { get; set; }
and Dragon as
public override string MyProperty { get; set; }
public override string MyProperty { get; set; }
and AttackBoostDecorator as
public override string MyProperty
=> _decoratedObject.MyProperty;

private Creature _decoratedObject;
public override string MyProperty
=> _decoratedObject.MyProperty;

private Creature _decoratedObject;
then AttackBoostDecorator doesn't allocate fields for each property only Dragon does and AttackBoostDecorator only allocates one field to store the whole decorated object this does come with the assumption that the original instance being decorated ISN'T being used by anything else but that is pretty much how the decorator pattern is accepted to work
Protagonist
ProtagonistOP2y ago
thats pretty nice it seems like getting into the technicalities of memorys and meta date seems like a long/difficult thing
JakenVeina
JakenVeina2y ago
welcome to C#
Protagonist
ProtagonistOP2y ago
ill prob pick up on them during internship or working or maybe assing myself self study on that
JakenVeina
JakenVeina2y ago
maybe, maybe not if you really want to take your knowledge to the next level, I recommend an actual technical book at some point, you'll absorb about all you can through osmosis, and you'll need to take a more active role in developing your skills, in order to progress
Protagonist
ProtagonistOP2y ago
thats true If i may ask, since youve seen some of my code and so on what would you say my level of C# is Still beginner?
JakenVeina
JakenVeina2y ago
on the upper end
Protagonist
ProtagonistOP2y ago
I see the flymethod doesnt seem to be adding +2 to the x and y at all it just keeps it the same but ill try figure it out tmrw thank u for ur Hmmm
JakenVeina
JakenVeina2y ago
o7
Florian Voß
Florian Voß2y ago
this is strategy pattern and having hardcoded values is quite common in the redefined methods. Say you wanna create a Strategy for WeaponBehaviour because different weapons deal different amount of dmg. so we create an IWeaponBehaviour interface with DealDamage method or Attack or whatever. Then we create SwortBehaviour that attacks for 4, AxeBehaviour that attacks for 6, and DaggerBehaviour to attack for 3. It may seem weird to create extra classes for this but it makes more sense as the strategy gets more complex than that.
JakenVeina
JakenVeina2y ago
that wasn't really the question
Florian Voß
Florian Voß2y ago
I understood it as complaining about hardcoded code
JakenVeina
JakenVeina2y ago
no
Florian Voß
Florian Voß2y ago
sorry then
JakenVeina
JakenVeina2y ago
np
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server