Skip to content

Releases: openrpg/OpenRpg

Large structural changes and addition of `IEntity`

18 Sep 14:59
Compare
Choose a tag to compare

Summary

Over the years of working on this library the goal was to try and have an additive and non-breaking way to easily add new responsibilities to core objects, be it via the internal functionality or 3rd party components.

Originally we took the approach of having interfaces that could be extended and composed however needed, which would let the end consumer decide which interfaces to use when composing things, and that has some benefits but it also has some down sides, such as not easily being able to add new responsibilities without inheriting or changing underlying type in some way.

The IStats object originally showed a way to handle this in a nice way, where its just a dictionary under the hood and lets you add keyed information in, so Health could be key 1 and we can add extension methods to the related objects which let us add responsibilities and logic in a more indirect way without needing to alter hierarchies or inheritance models etc.

Now felt like the right time to start solidifying on this idea by bringing a lot of the responsibilities in the OpenRpg.Genres layer into the core, such as ICharacter, which is now what IEntity has become.

IEntity

This is the notion of something that has both Stats, State and Variables under the hood, with the Variables basically becoming out extension point. This lets us expose dynamic ways to extend any entity to contain responsibilities for having an Inventory, or having a Class applied, this in a way is similar to how the ECS pattern works where everything is just a component added to the entity at runtime.

One downside here though is because we allow ANYTHING to be stored against the entities variables it has to be of type object which means ValueTypes will get boxed and everything needs casting on the way out, however this is taken care of in the extension methods that extend the underlying objects, and casting a type is fairly quick to do.

Other Changes

There are some other changes around making IDataTemplate a more official notion and having templates derive from that so we can keep them streamlined, as well as having certain interfaces having generics to support different types of IStatVariables or IStateVariables etc.

Updated Item related functionality & mappers

25 Oct 14:12
Compare
Choose a tag to compare

Summary

Items were always seen as a base class to extend with an identification mechanism by the consuming app, but as time went on it became apparent that its probably easier to just have it have a Guid by default, but without messing up the existing interface we have added a new IIsUnique interface which allows anything to be given a Guid UniqueId {get;}.

Also as part of this Equipment has been changed slightly so slots are no longer tied to a specific item type but are now more open so you can implement a predicate indicating if an item type can be equipped.

We have also added IMapper<Tin, Tout> at the core layer to support higher level changes to streamline common persistence scenarios, which historically were left to the consumer to implement, but there is a large amount of overlap so the higher level libs are implementing that.

Added Tagging Utility Library

14 Apr 15:23
Compare
Choose a tag to compare

Summary

This libraries usefulness may not be directly apparent, and it may also seem a bit odd that it uses int for tags rather than string, however there is some purpose to it all I assure you.

So its only int as its FAAAAR quicker to compare ints and pass them around than it is to use strings, so much like our other Types style objects in the real world to use tags you would probably have something like:

public class TagTypes
{
   public static int Armour = 1;
   public static int Weapon = 2;
   public static int Metal= 3;
   public static int Wood= 4;
   public static int Hot = 5;
   public static int Armour = 6;
   // ... etc
}

So then you may be asking...

So why is this useful?

As of right now its not massively useful, you can add tags to anything via the ITagged interface if you wanted to logically group certain items/quests etc so you could search for all Quests with the tags { easy, gathering } or all weapons with { armour, heavy } to find any heavy armours etc.

Those are fairly simple use cases but in the future when we start to look at procedurally based content these tags can be extremely useful as an approach for managing procedural relationships by expressing related tags and the weightings with them, i.e hot could be related to cold with a weighting of -1.0f meaning it HATES the cold tag, but could have a positive relation with sand of 0.4f meaning things can be related and have some form of strength/importance of relationship.

A quick example

So for example lets say you procedurally generate an area from tags { hot, illegal, sparse } well that would conjure pictures Mos Eisley or some desert area of some sort, but then if we were to assume we had relations setup, you may find that hot areas are more likely to have sand textures, have little water and hills, you could then also find that the illegal tag is linked to bandits and cheap goods, however as its sparse there wouldn't be many NPCs or towns there.

So from just a couple of tags you can start to form a view of a place, and same sort of thing with crafting, if you were to have a blueprint for a weapon that contains { metal, sword } so you could provide that silver, iron, gold etc and it could find that silver is related to lower durability but improved damage to werewolves etc.

A lot of this is a long way away, and even though this may sound cool it may not be applicable for all scenarios, so it is left as a utility for people to use how they see fit, like the curves etc.

Rewritten Data Layer

29 Mar 08:37
Compare
Choose a tag to compare

Summary

While the data layer was fine for what it was doing it always felt slightly noisy in terms of the amount of classes/interfaces there for abstraction etc, also it made it difficult to really do anything productive due to the reliance on just an object data source so you always had to know what was being passed in.

IRepository

So to try and make things a bit more stable and easier to extend we have removed the generics and moved to just a singular IRepository which has extension methods to do all CRUD based operations the old one had as well as streamlining data source interactions via a new IDataSource interface.

You can read more about some of these decisions and changes in my chapter here

IDataSource

This basically wraps the notion of an underlying data source, be it a database, an in memory data store (Dictionary) or anything else, this makes it a bit easier to interact with now as the IDataSource exposes methods to access data which the old one didn't.

Locales

Due to the repository change the LocaleRepository does not align 100% with the new pattern but has been altered to seem like it is the same, and is less noisy too.

Extensions

This also has some more extension methods around curves and random numbers, these also warranted unit tests so we now have a test project to go with everything, and thats the last of the major changes in this version!

Improved Equipment and IVariable usages

28 Jan 15:55
Compare
Choose a tag to compare

To try and make the IVariable interface more usable elsewhere we have made a few underlying convention interfaces, this should not really effect the higher level interfaces much but it gives us greater flexibility to re-use a lot of the existing infrastructure on other areas like AI etc.

Also worth noting the equipment interface has been moved over to use the variables interface under the hood so now rather than it being a bespoke object with each slot being a property, it now uses the same extension method approach to add your own flavour of equipment on top of it, making it more reusable for everyone.

Making IVariables more defensive

07 Jun 14:02
Compare
Choose a tag to compare

Summary

Currently when interacting with IVariables it is expected that you will be using the indexer and it will throw if the variable doesn't exist. While this is fine for the most part, it can catch devs unaware, especially with the pattern for extensions on the variables allowing you to access the data like properties i.e myItemTemplate.Variables.QualityType().

So as currently this could blow up on you if:

  • The QualityType variable is not set when you are getting it
  • The QualityType is not an int when you try to get it

It felt like this could be a bit problematic for people who are just trying to get on and be productive, so we are changing the way these default helper extensions work by using Convert.ToXXX rather than manual casts, and also using GetVariable on the variables vs Variables[VariableType].

This comes at a minor performance cost, but it will not be noticeable unless you are calling these methods hundreds of thousands of times per frame/update, and if performance is an issue you are still able to write your own optimised conventions/extensions that directly access the variables.

Adding Cards and simplifying some classes

22 May 14:23
Compare
Choose a tag to compare

Summary

As I am doing some work on another project which is like a simple card game auto battled some of that functionality has been rolled into OpenRpg, there are also some changes around variables which allow more flexibility in usage as well as improving use cases.

Cards

So cards are basically wrappers of data, be it items, abilities, effects etc.

All the underlying objects are the same, so you can take the same items you already have and same classes/races etc and just express them as cards by providing card implementations for each bit. Then in your game layer you just need to display the cards and apply them to characters/whatever.

IHasAssetCode

This notion has been removed as it was mainly there to provide users a way to tie an asset code to a given object, i.e lets say an item has a sprite and a model, you could use the asset code as a way to satisfy that dependency without knowing about the view.

However not everyone needs this, and those who do may need more than just a single string field, so as part of this its recommended that if you need that functionality you use the Variables provided on most objects and have a type specific for your view related data. This also allows you to provide as much view related data as you want, be it unique view ids, view asset codes or even 3rd party id codes etc.