Press "Enter" to skip to content

Lesson 19.14: Moving the Engine classes to their new projects

Now, we can move the classes from the Engine class into their new classes.

We’ll cut-and-paste the files, update the classes’ namespaces, and update the “using” directives.

The video will show me going through the actual move – in case it’s difficult to determine exactly what to do in the written steps below.

NOTE: When following the steps, make sure you copy files, when the step says FILE or FILES, and folders, where the step says FOLDERS.

Also, when you move the files, you really do not need to update the namespaces. You could leave the namespace unchanged. However, if you add new classes to the new projects, those classes will be created (by default, from Visual Studio) to use the new project’s name. So, some classes in that project would have the old namespace and some would have the new one.


Link to video on YouTube

Step 1: Move ViewModels

Cut-and-paste the GameSession.cs FILE from Engine\ViewModels into SOSCSRPG.ViewModels

Step 2: Move Services

Cut-and-paste the FILES from Engine\Services into SOSCSRPG.Services

Cut-and-paste the FOLDER Engine\Factories into SOSCSRPG.Services

Step 3: Move Models

Cut-and-paste the FILES from Engine\Models into SOSCSRPG.Models

Cut-and-paste the FOLDER Engine\Shared into SOSCSRPG.Models

Cut-and-paste the FOLDER Engine\Actions into SOSCSRPG.Models

Step 4: Update namespaces and using directives

Ctrl-Shift-H

Look in: “Entire solution”

File types: !*\bin\*;!*\obj\*;!*\.*

“Engine.Factories” to “SOSCSRPG.Services.Factories”

“Engine.Actions” to “SOSCSRPG.Models.Actions”

“Engine.Shared” to “SOSCSRPG.Models.Shared”

“assembly=Engine” to “assembly=SOSCSRPG.ViewModels”

“Engine.” to “SOSCSRPG.”

Step 5: Update assembly namespace in Startup.xaml

In this XAML Window, we are not binding to a ViewModel. We’re directly binding to a Model – GameDetails.

This is something we probably need to change in the future, to be consistent. But, for now, that means we need to change the xmlns and DataContext lines to use the SOSCSRPG.Models namespace and assembly.

Startup.xaml

<Window x:Class="WPFUI.Startup"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPFUI"
        xmlns:models="clr-namespace:SOSCSRPG.Models;assembly=SOSCSRPG.Models"
        d:DataContext="{d:DesignInstance models:GameDetails}"
        mc:Ignorable="d"
        FontSize="11pt"
        Title="{Binding Title}" Height="400" Width="400">
 
    <Grid Margin="10,10,10,10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
 
        <Button Grid.Row="0" Grid.Column="0"
                Margin="0,5,0,5"
                HorizontalAlignment="Center"
                Width="125"
                Content="Start new game"
                Click="StartNewGame_OnClick"/>
 
        <Button Grid.Row="1" Grid.Column="0"
                Margin="0,5,0,5"
                HorizontalAlignment="Center"
                Width="125"
                Content="Load saved game"
                Click="LoadSavedGame_OnClick"/>
 
        <Button Grid.Row="2" Grid.Column="0"
                Margin="0,5,0,5"
                HorizontalAlignment="Center"
                Width="125"
                Content="Exit"
                Click="Exit_OnClick"/>
         
    </Grid>
 
</Window>

Step 5: Make classes/functions visible

Change SOSCSRPG.Models\World’s AddLocation() to public

Change SOSCSRPG.Services\Factories\WorldFactory’s CreateWorld() to public

Change SOSCSRPG.Services\Factories\WorldFactory class to public

World.cs

using System.Collections.Generic;

namespace SOSCSRPG.Models
{
    public class World
    {
        private readonly List<Location> _locations = new List<Location>();

        public void AddLocation(Location location)
        {
            _locations.Add(location);
        }

        public Location LocationAt(int xCoordinate, int yCoordinate)
        {
            foreach(Location loc in _locations)
            {
                if(loc.XCoordinate == xCoordinate && loc.YCoordinate == yCoordinate)
                {
                    return loc;
                }
            }

            return null;
        }
    }
}

WorldFactory.cs

using System.IO;
using System.Xml;
using SOSCSRPG.Models;
using SOSCSRPG.Models.Shared;

namespace SOSCSRPG.Services.Factories
{
    public static class WorldFactory
    {
        private const string GAME_DATA_FILENAME = ".\\GameData\\Locations.xml";

        public 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"));
        }
    }
}

Step 6: Delete project references to Engine project

Delete the Engine project

Double-click on the WPFUI and SOSCSRPG.ViewModels projects and remove the ProjectReference lines to the Engine project

SOSCSRPG.ViewModels.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Fody" Version="6.6.0">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="PropertyChanged.Fody" Version="3.4.0" PrivateAssets="All"/>
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\SOSCSRPG.Models\SOSCSRPG.Models.csproj" />
    <ProjectReference Include="..\SOSCSRPG.Services\SOSCSRPG.Services.csproj" />
  </ItemGroup>

</Project>

WPFUI.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net5.0-windows</TargetFramework>
    <UseWPF>true</UseWPF>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\SOSCSRPG.Core\SOSCSRPG.Core.csproj" />
    <ProjectReference Include="..\SOSCSRPG.Models\SOSCSRPG.Models.csproj" />
    <ProjectReference Include="..\SOSCSRPG.ViewModels\SOSCSRPG.ViewModels.csproj" />
  </ItemGroup>

  <Target Name="PostBuild" AfterTargets="PostBuildEvent">
    <Exec Command="xcopy $(SolutionDir)GameFiles\*.* $(ProjectDir)$(OutDir) /s /y" />
  </Target>

</Project>

Step 8: Test game

Leave a Reply

Your email address will not be published. Required fields are marked *