#StackBounty: #c# #rubberduck #autocomplete Enhancing autocompletion for VBA code

Bounty: 200

Context

The Visual Basic Editor (VBE) does a good job at completing member scopes, for example when you type this and hit ENTER

Private Sub DoSomething

You get this for free:

Private Sub DoSomething()

End Sub

The problem is that VBA is a very, uhm, blocky language, and the VBE doesn’t automatically complete any of the blocks. For example when you type this and hit ENTER

With Something

All you get is this:

With Something

And what you’d like is this:

With Something

End With

The next release of Rubberduck will fix this, and more. Here’s how.


Interface & Wiring

I started with an IAutoComplete interface that looks like this:

namespace Rubberduck.AutoComplete
{
    public interface IAutoComplete
    {
        string InputToken { get; }
        string OutputToken { get; }
        bool Execute(AutoCompleteEventArgs e, AutoCompleteSettings settings);
        bool IsInlineCharCompletion { get; }
        bool IsEnabled { get; set; }
    }
}

This interface is flexible enough to allow toggling each individual implementation on/off using Rubberduck settings, and the InputToken / OutputToken properties are flexible enough to support both inline and block autocompletion.

The AutoCompleteEventArgs class is defined in the Rubberduck.VBEditor project, which is responsible for the lower-level VBE messenging hooks and COM wrappers:

namespace Rubberduck.VBEditor.Events
{
    public class AutoCompleteEventArgs : EventArgs
    {
        public AutoCompleteEventArgs(ICodeModule module, WindowsApi.KeyPressEventArgs e)
        {
            if (e.Key == Keys.Delete ||
                e.Key == Keys.Back ||
                e.Key == Keys.Enter ||
                e.Key == Keys.Tab)
            {
                Keys = e.Key;
            }
            else
            {
                Character = e.Character;
            }
            CodeModule = module;
            CurrentSelection = module.GetQualifiedSelection().Value.Selection;
            CurrentLine = module.GetLines(CurrentSelection);
        }

        /// <summary>
        /// <c>true</c> if the character has been handled, i.e. written to the code pane.
        /// Set to <c>true</c> to swallow the character and prevent the WM message from reaching the code pane.
        /// </summary>
        public bool Handled { get; set; }

        /// <summary>
        /// The CodeModule wrapper for the module being edited.
        /// </summary>
        public ICodeModule CodeModule { get; }

        /// <summary>
        /// <c>true</c> if the event is originating from a <c>WM_CHAR</c> message.
        /// <c>false</c> if the event is originating from a <c>WM_KEYDOWN</c> message.
        /// </summary>
        /// <remarks>
        /// Inline completion is handled on WM_CHAR; deletions and block completion on WM_KEYDOWN.
        /// </remarks>
        public bool IsCharacter => Keys == default;
        /// <summary>
        /// The character whose key was pressed. Undefined value if <see cref="Keys"/> isn't `<see cref="Keys.None"/>.
        /// </summary>
        public char Character { get; }
        /// <summary>
        /// The actionnable key that was pressed. Value is <see cref="Keys.None"/> when <see cref="IsCharacter"/> is <c>true</c>.
        /// </summary>
        public Keys Keys { get; }

        /// <summary>
        /// The current location of the caret.
        /// </summary>
        public Selection CurrentSelection { get; }
        /// <summary>
        /// The contents of the current line of code.
        /// </summary>
        public string CurrentLine { get; }
    }
}

The EventArgs object is created by VBENativeServices in a static handler (which needs to be static for various reasons) that is invoked when a key is pressed in the editor’s code pane:

public static event EventHandler<AutoCompleteEventArgs> KeyDown; 
private static void OnKeyDown(KeyPressEventArgs e)
{
    using (var pane = GetCodePaneFromHwnd(e.Hwnd))
    {
        using (var module = pane.CodeModule)
        {
            var args = new AutoCompleteEventArgs(module, e);
            KeyDown?.Invoke(_vbe, args);
            e.Handled = args.Handled;
        }
    }
}

The value of the Handled property is carried to the invoking native handler, which then uses this value to determine whether to “swallow” the keypress or let it through to the code pane – this all happens in the rather low-level CodePaneSubClass class:

namespace Rubberduck.VBEditor.WindowsApi
{
    public class KeyPressEventArgs
    {
        public KeyPressEventArgs(IntPtr hwnd, IntPtr wParam, IntPtr lParam, char character = default)
        {
            Hwnd = hwnd;
            WParam = wParam;
            LParam = lParam;
            Character = character;
            if (character == default(char))
            {
                Key = (Keys)wParam;
            }
            else
            {
                IsCharacter = true;
            }
        }

        public bool IsCharacter { get; }
        public IntPtr Hwnd { get; }
        public IntPtr WParam { get; }
        public IntPtr LParam { get; }

        public bool Handled { get; set; }

        public char Character { get; }
        public Keys Key { get; }
    }

    //Stub for code pane replacement.  :-)
    internal class CodePaneSubclass : FocusSource
    {
        public ICodePane CodePane { get; }

        internal CodePaneSubclass(IntPtr hwnd, ICodePane pane) : base(hwnd)
        {
            CodePane = pane;
        }

        public override int SubClassProc(IntPtr hWnd, IntPtr msg, IntPtr wParam, IntPtr lParam, IntPtr uIdSubclass, IntPtr dwRefData)
        {
            KeyPressEventArgs args;
            switch ((WM)msg)
            {
                case WM.CHAR:
                    args = new KeyPressEventArgs(hWnd, wParam, lParam, (char)wParam);
                    OnKeyDown(args);
                    if (args.Handled) { return 0; }
                    break;
                case WM.KEYDOWN:
                    args = new KeyPressEventArgs(hWnd, wParam, lParam);
                    OnKeyDown(args);
                    if (args.Handled) { return 0; }
                    break;
            }
            return base.SubClassProc(hWnd, msg, wParam, lParam, uIdSubclass, dwRefData);
        }

        protected override void DispatchFocusEvent(FocusType type)
        {
            var window = VBENativeServices.GetWindowInfoFromHwnd(Hwnd);
            if (!window.HasValue)
            {
                return;
            }
            OnFocusChange(new WindowChangedEventArgs(window.Value.Hwnd, window.Value.Window, CodePane, type));
        }
    }
}

One concern is that a decision was taken to handle both WM_CHAR and WM_KEYDOWN, because CHAR conveniently gives us the exact char to use, but only KEYDOWN can tell us whether the DELETE or <kbd>BACKSPACE</kbd> key was pressed – so the KeyPressEventArgs contain information that tells us whether we need to look at the Character or the Keys enum value when we handle the keypress… and this makes the name KeyPress rather all-encompassing.


AutoCompleteService

The component responsible for handling the low-level VBENativeServices.KeyDown event gets the settings service and the IAutoComplete provider constructor-injected – the class is needs to handle changes in configuration settings, which could conceivably be toggling one or more autocompletes’ IsEnabled state at any point in time.. but we don’t want to re-load the settings file at every keypress either:

namespace Rubberduck.AutoComplete
{
    public class AutoCompleteService : SubclassingWindow, IDisposable
    {
        private readonly IGeneralConfigService _configService;
        private readonly List<IAutoComplete> _autoCompletes;

        private AutoCompleteSettings _settings;

        public AutoCompleteService(IGeneralConfigService configService, IAutoCompleteProvider provider)
        {
            _configService = configService;
            _autoCompletes = provider.AutoCompletes.ToList();
            ApplyAutoCompleteSettings(configService.LoadConfiguration());

            _configService.SettingsChanged += ConfigServiceSettingsChanged;
            VBENativeServices.KeyDown += HandleKeyDown;
        }

        private void ConfigServiceSettingsChanged(object sender, ConfigurationChangedEventArgs e)
        {
            var config = _configService.LoadConfiguration();
            ApplyAutoCompleteSettings(config);
        }

        private void ApplyAutoCompleteSettings(Configuration config)
        {
            _settings = config.UserSettings.AutoCompleteSettings;
            foreach (var autoComplete in _autoCompletes)
            {
                var setting = config.UserSettings.AutoCompleteSettings.AutoCompletes.FirstOrDefault(s => s.Key == autoComplete.GetType().Name);
                if (setting != null && autoComplete.IsEnabled != setting.IsEnabled)
                {
                    autoComplete.IsEnabled = setting.IsEnabled;
                    continue;
                }
            }
        }

        private void HandleKeyDown(object sender, AutoCompleteEventArgs e)
        {
            var module = e.CodeModule;
            var qualifiedSelection = module.GetQualifiedSelection();
            var selection = qualifiedSelection.Value.Selection;

            if (e.Keys != Keys.None && selection.LineCount > 1 || selection.StartColumn != selection.EndColumn)
            {
                return;
            }

            var currentContent = module.GetLines(selection);

            var handleDelete = e.Keys == Keys.Delete && selection.EndColumn <= currentContent.Length;
            var handleBackspace = e.Keys == Keys.Back && selection.StartColumn > 1;
            foreach (var autoComplete in _autoCompletes.Where(auto => auto.IsEnabled))
            {
                if (handleDelete || handleBackspace)
                {
                    if (DeleteAroundCaret(e, autoComplete))
                    {
                        break;
                    }
                }
                else
                {
                    if (autoComplete.Execute(e, _settings))
                    {
                        break;
                    }
                }
            }
        }

        private bool DeleteAroundCaret(AutoCompleteEventArgs e, IAutoComplete autoComplete)
        {
            if (autoComplete.IsInlineCharCompletion)
            {
                var code = e.CurrentLine;
                // If caret LHS is the AC input token and RHS is the AC output token, we can remove both.
                // Substring index is 0-based. Selection from code pane is 1-based.
                // LHS should be at StartColumn - 2, RHS at StartColumn - 1.
                var caretLHS = code.Substring(Math.Max(0, e.CurrentSelection.StartColumn - 2), 1);
                var caretRHS = code.Length >= e.CurrentSelection.StartColumn
                    ? code.Substring(e.CurrentSelection.StartColumn - 1, 1)
                    : string.Empty;

                if (caretLHS == autoComplete.InputToken && caretRHS == autoComplete.OutputToken)
                {
                    var left = code.Substring(0, e.CurrentSelection.StartColumn - 2);
                    var right = code.Substring(e.CurrentSelection.StartColumn);
                    using (var pane = e.CodeModule.CodePane)
                    {
                        e.CodeModule.ReplaceLine(e.CurrentSelection.StartLine, left + right);
                        pane.Selection = new Selection(e.CurrentSelection.StartLine, e.CurrentSelection.StartColumn - 1);
                        e.Handled = true;
                    }
                    return true;
                }
            }
            return false;
        }

        public void Dispose()
        {
            VBENativeServices.KeyDown -= HandleKeyDown;
            if (_configService != null)
            {
                _configService.SettingsChanged -= ConfigServiceSettingsChanged;
            }

            _autoCompletes.Clear();
        }
    }
}

So the service handles deleting & backspacing. Two classes handle inline and block completion, respectively.


Inline Autocompletion

The simplest form of autocompletion is the “inline” kind. Since all inline autocompletes work the same way, the execution logic is implemented in a base class:

namespace Rubberduck.AutoComplete
{
    public abstract class AutoCompleteBase : IAutoComplete
    {
        protected AutoCompleteBase(string inputToken, string outputToken)
        {
            InputToken = inputToken;
            OutputToken = outputToken;
        }

        public bool IsInlineCharCompletion => InputToken.Length == 1 && OutputToken.Length == 1;
        public bool IsEnabled { get; set; }
        public string InputToken { get; }
        public string OutputToken { get; }

        public virtual bool Execute(AutoCompleteEventArgs e, AutoCompleteSettings settings)
        {
            if (!e.IsCharacter || !IsInlineCharCompletion)
            {
                return false;
            }

            var module = e.CodeModule;
            using (var pane = module.CodePane)
            {
                var selection = pane.Selection;
                if (e.Character.ToString() == InputToken)
                {
                    var code = module.GetLines(selection).Insert(Math.Max(0, selection.StartColumn - 1), InputToken + OutputToken);
                    module.ReplaceLine(selection.StartLine, code);
                    pane.Selection = new Selection(selection.StartLine, selection.StartColumn + 1);
                    e.Handled = true;
                    return true;
                }
                return false;
            }
        }
    }
}

Classes derived from the above base class include:

public class AutoCompleteClosingBrace : AutoCompleteBase
{
    public AutoCompleteClosingBrace() 
        : base("{", "}") { }
}

And:

public class AutoCompleteClosingParenthese : AutoCompleteBase
{
    public AutoCompleteClosingParenthese()
        :base("(", ")") { }
}

And also:

public class AutoCompleteClosingString : AutoCompleteBase
{
    public AutoCompleteClosingString() 
        : base(""", """) { }
}

IMO it does smell that each class has exactly nothing but constructor arguments. OTOH it does make it very easy to use reflection to automagically have the AutoCompleteProvider know about all supported autocompletions. Any better ideas?


Block Autocompletion

Auto-completing code blocks is a tad more complicated: since Rubberduck has a Smart Indenter with a bunch of settings, not honoring the indenter settings wouldn’t feel right, so we want the derived types to be able to override some predicate that determines whether the block body should be indented. But we also want to avoid completing a block that’s actually a comment, and then If and #If tokens need to be treated differently (i.e. precompiler directives). The result is a little bit hairy, but the derived classes are just as neat (/smelly?) as the inline autocompletes:

namespace Rubberduck.AutoComplete
{
    public abstract class AutoCompleteBlockBase : AutoCompleteBase
    {
        /// <param name="indenterSettings">Used for auto-indenting blocks as per indenter settings.</param>
        /// <param name="inputToken">The token that starts the block, i.e. what to detect.</param>
        /// <param name="outputToken">The token that closes the block, i.e. what to insert.</param>
        protected AutoCompleteBlockBase(IConfigProvider<IndenterSettings> indenterSettings, string inputToken, string outputToken)
            :base(inputToken, outputToken)
        {
            IndenterSettings = indenterSettings;
        }

        protected virtual bool FindInputTokenAtBeginningOfCurrentLine => false;
        protected virtual bool SkipPreCompilerDirective => true;

        protected readonly IConfigProvider<IndenterSettings> IndenterSettings;

        protected virtual bool ExecuteOnCommittedInputOnly => true;
        protected virtual bool MatchInputTokenAtEndOfLineOnly => false;

        protected virtual bool IndentBody => true;

        public override bool Execute(AutoCompleteEventArgs e, AutoCompleteSettings settings)
        {
            var ignoreTab = e.Keys == Keys.Tab && !settings.CompleteBlockOnTab;
            if (IsInlineCharCompletion || e.Keys == Keys.None || ignoreTab)
            {
                return false;
            }

            var module = e.CodeModule;
            using (var pane = module.CodePane)
            {
                var selection = pane.Selection;
                var code = module.GetLines(selection);

                if (SkipPreCompilerDirective && code.Trim().StartsWith("#"))
                {
                    return false;
                }

                var pattern = SkipPreCompilerDirective
                                ? $"\b{InputToken}\b"
                                : $"{InputToken}\b"; // word boundary marker (b) would prevent matching the # character

                var isMatch = MatchInputTokenAtEndOfLineOnly
                                ? code.EndsWith(InputToken, System.StringComparison.OrdinalIgnoreCase)
                                : Regex.IsMatch(code.Trim(), pattern, RegexOptions.IgnoreCase);

                if (isMatch && !code.HasComment(out _) && !IsBlockCompleted(module, selection))
                {
                    var indent = code.TakeWhile(c => char.IsWhiteSpace(c)).Count();
                    var newCode = OutputToken.PadLeft(OutputToken.Length + indent, ' ');

                    var stdIndent = IndentBody ? IndenterSettings.Create().IndentSpaces : 0;

                    module.InsertLines(selection.NextLine.StartLine, "n" + newCode);

                    module.ReplaceLine(selection.NextLine.StartLine, new string(' ', indent + stdIndent));
                    pane.Selection = new Selection(selection.NextLine.StartLine, indent + stdIndent + 1);

                    e.Handled = true;
                    return true;
                }
                return false;
            }
        }

        private bool IsBlockCompleted(ICodeModule module, Selection selection)
        {
            string content;
            var proc = module.GetProcOfLine(selection.StartLine);
            if (proc == null)
            {
                content = module.GetLines(1, module.CountOfDeclarationLines);
            }
            else
            {
                var procKind = module.GetProcKindOfLine(selection.StartLine);
                var startLine = module.GetProcStartLine(proc, procKind);
                var lineCount = module.GetProcCountLines(proc, procKind);
                content = module.GetLines(startLine, lineCount);
            }

            var options = RegexOptions.IgnoreCase;
            var inputPattern = $"(?<!{OutputToken.Replace(InputToken, string.Empty)})\b{InputToken}\b";
            var inputMatches = Regex.Matches(content, inputPattern, options).Count;
            var outputMatches = Regex.Matches(content, $"\b{OutputToken}\b", options).Count;

            return inputMatches > 0 && inputMatches == outputMatches;
        }
    }
}

The matching logic allows this single AutoCompleteDoBlock class to work with Do...Loop, Do Until...Loop, and Do While...Loop constructs:

public class AutoCompleteDoBlock : AutoCompleteBlockBase
{
    public AutoCompleteDoBlock(IIndenterSettings indenterSettings)
        : base(indenterSettings, $"{Tokens.Do}", Tokens.Loop) { }
}

And Enum blocks may or may not be indented, depending on indenter settings:

public class AutoCompleteEnumBlock : AutoCompleteBlockBase
{
    public AutoCompleteEnumBlock(IIndenterSettings indenterSettings)
        : base(indenterSettings, $"{Tokens.Enum}", $"{Tokens.End} {Tokens.Enum}") { }

    protected override bool IndentBody => IndenterSettings.IndentEnumTypeAsProcedure;
}

Everything works pretty well (see it in action on YouTube), with one known edge case I’m not sure I want to address: rule of thumb, in order for it to break your VBA code, you pretty much need to be actively trying to break the feature.

Does anything look off?

These two implementations in particular, kind of smell funny:

public class AutoCompleteIfBlock : AutoCompleteBlockBase
{
    public AutoCompleteIfBlock(IIndenterSettings indenterSettings) 
        : base(indenterSettings, $"{Tokens.Then}", $"{Tokens.End} {Tokens.If}") { }

    protected override bool MatchInputTokenAtEndOfLineOnly => true;
}
public class AutoCompleteOnErrorResumeNextBlock : AutoCompleteBlockBase
{
    public AutoCompleteOnErrorResumeNextBlock(IIndenterSettings indenterSettings)
        : base(indenterSettings, $"{Tokens.On} {Tokens.Error} {Tokens.Resume} {Tokens.Next}", $"{Tokens.On} {Tokens.Error} {Tokens.GoTo} 0") { }

    protected override bool ExecuteOnCommittedInputOnly => false;
}

Feels like the base class is going to be growing with members as per some specific derived type’s needs – like the If...End If autocomplete that needs to account for VBA’s totally legal single-line If {condition} Then {statement} syntax, which Rubberduck shouldn’t try to complete… On the other hand most implementations do have extremely similar mechanisms, so the base implementation makes a rather sensible default.


Get this bounty!!!

#StackBounty: #c# #unity3d #interpolation #catmull-rom-curve Acceleration in Unity

Bounty: 150

I am trying to emulate acceleration and deceleration in Unity.

I have written to code to generate a track in Unity and place an object at a specific location on the track based on time. The result looks a little like this.

Cube mid way through Catmull-Rom Spline

The issue I currently have is that each section of the spline is a different length and the cube moves across each section at a different, but uniform, speed. This causes there to be sudden jumps in the change of the speed of the cube when transitioning between sections.

In order to try and fix this issue, I attempted to use Robert Penner’s easing equations on the GetTime(Vector3 p0, Vector3 p1, float alpha) method. However, whilst this did help somewhat, it was not sufficient. There were still jumps in speed in between transitions.

Does anyone have any ideas on how I could dynamically ease the position of the cube to make it look like it was accelerating and decelerating, without large jumps in speed between segments of the track?


I have written a script that shows a simple implementation of my code. It can be attached to any game object. To make it easy to see what is happening when the code runs, attach to something like a cube or sphere.

using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

public class InterpolationExample : MonoBehaviour {
    [Header("Time")]
    [SerializeField]
    private float currentTime;
    private float lastTime = 0;
    [SerializeField]
    private float timeModifier = 1;
    [SerializeField]
    private bool running = true;
    private bool runningBuffer = true;

    [Header("Track Settings")]
    [SerializeField]
    [Range(0, 1)]
    private float catmullRomAlpha = 0.5f;
    [SerializeField]
    private List<SimpleWayPoint> wayPoints = new List<SimpleWayPoint>
    {
        new SimpleWayPoint() {pos = new Vector3(-4.07f, 0, 6.5f), time = 0},
        new SimpleWayPoint() {pos = new Vector3(-2.13f, 3.18f, 6.39f), time = 1},
        new SimpleWayPoint() {pos = new Vector3(-1.14f, 0, 4.55f), time = 6},
        new SimpleWayPoint() {pos = new Vector3(0.07f, -1.45f, 6.5f), time = 7},
        new SimpleWayPoint() {pos = new Vector3(1.55f, 0, 3.86f), time = 7.2f},
        new SimpleWayPoint() {pos = new Vector3(4.94f, 2.03f, 6.5f), time = 10}
    };

    [Header("Debug")]
    [Header("WayPoints")]
    [SerializeField]
    private bool debugWayPoints = true;
    [SerializeField]
    private WayPointDebugType debugWayPointType = WayPointDebugType.SOLID;
    [SerializeField]
    private float debugWayPointSize = 0.2f;
    [SerializeField]
    private Color debugWayPointColour = Color.green;
    [Header("Track")]
    [SerializeField]
    private bool debugTrack = true;
    [SerializeField]
    [Range(0, 1)]
    private float debugTrackResolution = 0.04f;
    [SerializeField]
    private Color debugTrackColour = Color.red;

    [System.Serializable]
    private class SimpleWayPoint
    {
        public Vector3 pos;
        public float time;
    }

    [System.Serializable]
    private enum WayPointDebugType
    {
        SOLID,
        WIRE
    }

    private void Start()
    {
        wayPoints.Sort((x, y) => x.time.CompareTo(y.time));
        wayPoints.Insert(0, wayPoints[0]);
        wayPoints.Add(wayPoints[wayPoints.Count - 1]);
    }

    private void LateUpdate()
    {
        //This means that if currentTime is paused, then resumed, there is not a big jump in time
        if(runningBuffer != running)
        {
            runningBuffer = running;
            lastTime = Time.time;
        }

        if(running)
        {
            currentTime += (Time.time - lastTime) * timeModifier;
            lastTime = Time.time;
            if(currentTime > wayPoints[wayPoints.Count - 1].time)
            {
                currentTime = 0;
            }
        }
        transform.position = GetPosition(currentTime);
    }

    #region Catmull-Rom Math
    public Vector3 GetPosition(float time)
    {
        //Check if before first waypoint
        if(time <= wayPoints[0].time)
        {
            return wayPoints[0].pos;
        }
        //Check if after last waypoint
        else if(time >= wayPoints[wayPoints.Count - 1].time)
        {
            return wayPoints[wayPoints.Count - 1].pos;
        }

        //Check time boundaries - Find the nearest WayPoint your object has passed
        float minTime = -1;
        float maxTime = -1;
        int minIndex = -1;
        for(int i = 1; i < wayPoints.Count; i++)
        {
            if(time > wayPoints[i - 1].time && time <= wayPoints[i].time)
            {
                maxTime = wayPoints[i].time;
                int index = i - 1;
                minTime = wayPoints[index].time;
                minIndex = index;
            }
        }

        float timeDiff = maxTime - minTime;
        float percentageThroughSegment = 1 - ((maxTime - time) / timeDiff);

        //Define the 4 points required to make a Catmull-Rom spline
        Vector3 p0 = wayPoints[ClampListPos(minIndex - 1)].pos;
        Vector3 p1 = wayPoints[minIndex].pos;
        Vector3 p2 = wayPoints[ClampListPos(minIndex + 1)].pos;
        Vector3 p3 = wayPoints[ClampListPos(minIndex + 2)].pos;

        return GetCatmullRomPosition(percentageThroughSegment, p0, p1, p2, p3, catmullRomAlpha);
    }

    //Prevent Index Out of Array Bounds
    private int ClampListPos(int pos)
    {
        if(pos < 0)
        {
            pos = wayPoints.Count - 1;
        }

        if(pos > wayPoints.Count)
        {
            pos = 1;
        }
        else if(pos > wayPoints.Count - 1)
        {
            pos = 0;
        }

        return pos;
    }

    //Math behind the Catmull-Rom curve. See here for a good explanation of how it works. https://stackoverflow.com/a/23980479/4601149
    private Vector3 GetCatmullRomPosition(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float alpha)
    {
        float dt0 = GetTime(p0, p1, alpha);
        float dt1 = GetTime(p1, p2, alpha);
        float dt2 = GetTime(p2, p3, alpha);

        Vector3 t1 = ((p1 - p0) / dt0) - ((p2 - p0) / (dt0 + dt1)) + ((p2 - p1) / dt1);
        Vector3 t2 = ((p2 - p1) / dt1) - ((p3 - p1) / (dt1 + dt2)) + ((p3 - p2) / dt2);

        t1 *= dt1;
        t2 *= dt1;

        Vector3 c0 = p1;
        Vector3 c1 = t1;
        Vector3 c2 = (3 * p2) - (3 * p1) - (2 * t1) - t2;
        Vector3 c3 = (2 * p1) - (2 * p2) + t1 + t2;
        Vector3 pos = CalculatePosition(t, c0, c1, c2, c3);

        return pos;
    }

    private float GetTime(Vector3 p0, Vector3 p1, float alpha)
    {
        if(p0 == p1)
            return 1;
        return Mathf.Pow((p1 - p0).sqrMagnitude, 0.5f * alpha);
    }

    private Vector3 CalculatePosition(float t, Vector3 c0, Vector3 c1, Vector3 c2, Vector3 c3)
    {
        float t2 = t * t;
        float t3 = t2 * t;
        return c0 + c1 * t + c2 * t2 + c3 * t3;
    }

    //Utility method for drawing the track
    private void DisplayCatmullRomSpline(int pos, float resolution)
    {
        Vector3 p0 = wayPoints[ClampListPos(pos - 1)].pos;
        Vector3 p1 = wayPoints[pos].pos;
        Vector3 p2 = wayPoints[ClampListPos(pos + 1)].pos;
        Vector3 p3 = wayPoints[ClampListPos(pos + 2)].pos;

        Vector3 lastPos = p1;
        int maxLoopCount = Mathf.FloorToInt(1f / resolution);

        for(int i = 1; i <= maxLoopCount; i++)
        {
            float t = i * resolution;
            Vector3 newPos = GetCatmullRomPosition(t, p0, p1, p2, p3, catmullRomAlpha);
            Gizmos.DrawLine(lastPos, newPos);
            lastPos = newPos;
        }
    }
    #endregion

    private void OnDrawGizmos()
    {
        #if UNITY_EDITOR
        if(EditorApplication.isPlaying)
        {
            if(debugWayPoints)
            {
                Gizmos.color = debugWayPointColour;
                foreach(SimpleWayPoint s in wayPoints)
                {
                    if(debugWayPointType == WayPointDebugType.SOLID)
                    {
                        Gizmos.DrawSphere(s.pos, debugWayPointSize);
                    }
                    else if(debugWayPointType == WayPointDebugType.WIRE)
                    {
                        Gizmos.DrawWireSphere(s.pos, debugWayPointSize);
                    }
                }
            }

            if(debugTrack)
            {
                Gizmos.color = debugTrackColour;
                if(wayPoints.Count >= 2)
                {
                    for(int i = 0; i < wayPoints.Count; i++)
                    {
                        if(i == 0 || i == wayPoints.Count - 2 || i == wayPoints.Count - 1)
                        {
                            continue;
                        }

                        DisplayCatmullRomSpline(i, debugTrackResolution);
                    }
                }
            }
        }
        #endif
    }
}


Get this bounty!!!

#StackBounty: #c# #asp.net Returning anything but ok in HttpResponseMessage results in serverside webservice call delays

Bounty: 200

I’m calling 2 webservices from a .Net 3.5 Framework Client (Server is a more modern .NET Framework Server: 4.6).

Separated I run into no Problems, but if I call the methods in the order shown below I get the Problem that the VerifyFile method on the Server is never entered, and I instead immediately get a The server has committed a protocol Violation Section=ResponseStatusLine error on the Client.
To be more exact: The Server Registers in the Events the VerifyFile request but doesn’t enter the actual code until up to 6 minutes later (and immediately Returns something instead that causes the above error).

After much testing I could reduce it to the first method “DownloadFile” being the cause of the Problem. And that always when I return anything else than the statuscode ok from it (Content or not Content doesn’t matter).

I’m at a complete loss with this phenomenon (I would have expected the Client to have Troubles, but the Server not entering that one code part until MINUTES later Looks like the Server is getting into Troubles itself, which is unexpected, also unexpected is that the SECOND method and not the original one is running into Problems there).

So my question is why is returning anything but HttpStatusCode.OK causing These Problems and what can I do to correct this?

Client:

WebClient webClient = new WebClient();
webClient.QueryString.Add("downloadId", id);
webClient.DownloadFile("localhost/Download/DownloadFile", @"c:templocal.txt");
webClient = new WebClient();
webClient.QueryString.Add("downloadId", id);
webClient.QueryString.Add("fileLength", GetFileLength(@"c:templocal.txt"));
var i = webClient.DownloadString("localhost/Download/VerifyFile");

Testwise I replaced the DownloadFile with: webClient.DownloadString("localhost/Download/DownloadFile");

Originally I also had only one new WebClient, but added the second one after the first failures.

Server:

[RoutePrefix("Download")]
public class DownloadController : ApiController
{
    [HttpGet]
    [Route("DownloadFile")]
    public IHttpActionResult DownloadFile(int downloadId){
        return ResponseMessage(GetFile(downloadId));
    }

    private HttpResponseMessage GetFile(int downloadId){
        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);

        string filePath = GetFilePathFromDB(downloadid);

        if (filePath == String.Empty){
            var stream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite);
            result.Content = new StreamContent(stream);
            result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            result.Content.Headers.ContentDisposition.FileName = Path.GetFileName(filePath);
            result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            result.Content.Headers.ContentLength = stream.Length;   
        }
        else{
            result = new HttpResponseMessage(HttpStatusCode.InternalServerError);
        }       
        return result;
    }

    [HttpGet]
    [Route("VerifyFile")]
    public IHttpActionResult VerifyFile(int downloadId, int fileLength)
    {
        return Content(HttpStatusCode.OK, "OK");
    }


    private string GetFilePathFromDB(int downloadId)
    {
         return @"C:tempmytest.txt"; // testcode
    }
}


Get this bounty!!!

#StackBounty: #python #c #shellcode #segmentation #cross-platform Python – ctypes.cast function call outputs Segmentation Fault error m…

Bounty: 50

Background:

Writing a proof of concept of a twitter C&C inspired by Prof Viviek of SPSE similiar to twittor and the project includes a functionality of injecting shellcode and executing it within the python’s program. However I wanted to make the functionality cross platforms, but it only worked in a windows system.

Problem: When executing the python script in ubuntu server 12.04.5 LTS, the output says

Segmentation fault (core dumped)

Which means I am getting denied for accessing memory that I don’t have permission for. This is strange b/c in the source code I also set cytpes.mprotect(allocated_space, space_size, 7) <== 4 + 2 + 1 is for wrx permissions

Shellcode generated using command:

msfvenom --payload linux/x86/shell/bind_tcp  --format py --arch x86 --bad-char "x00x20x0d"

Python Script:

 #!/usr/bin/env python

import ctypes
import os

# please comment out the appropriate payload for the other platforms
# this below is for windows shell bind tcp listening at 4444
#buf  = ""
#buf += "shellcode..."

# below is for linux
buf = ""
buf += "shellcode..."


def main(shellcode):
    if os.name == 'posix':                                                 
        try:                              
            libc = ctypes.CDLL('libc.so.6')                                
            sc_ptr = ctypes.c_char_p(shellcode)                               

            size = len(shellcode)                                          
            addr_freespace = ctypes.c_void_p(libc.valloc(size))                 
            ctypes.memmove(addr_freespace, sc_ptr, size)                            
            libc.mprotect(addr_free_space, size, 1 | 2 | 4)   # changed to 7 for all three access                    
            run = ctypes.cast(free_space, ctypes.CFUNCTYPE(ctypes.c_void_p))
            run()                                                           
            sys.exit()                                                                    
        except Exception as e:
            print "Error: " e

    else:                                                                   
        try:  # windows implementation



if __name__ == '__main__':
    main(buf)

Question: Can someone explain why does the segmentation fault message appear and how do we fix such problem?

Credits: this script is inspired by sickle.py @ Line743-753

The only difference is the reference script is using python 3, while I am using python 2.7.

UPDATE:

After many trials and errors, including running the program in pdb. The segmentation fault error happened after the line of:

run()

Can someone please explain why this is happening?


Get this bounty!!!

#StackBounty: #c# #itext #itext7 iText set conformance level

Bounty: 50

Currently I am trying to create a PDF file with the conformance level A-1a with iText for C#. This is what I have so far:

var exportFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var exportFile = System.IO.Path.Combine(exportFolder, "Test.pdf");

var writer = new PdfWriter(exportFile);
var pdf = new PdfDocument(writer);
var document = new Document(pdf);
document.Add(new Paragraph("Hello World! Tom"));
document.Close();

How am I able to set the conformance level for this?

EDIT

I found this in their documentation:
https://developers.itextpdf.com/content/itext-7-jump-start-tutorial-net/chapter-7-creating-pdfua-and-pdfa-documents

But I don’t get what I have to replace INTENT with in the third line of code.
Is someone able to give me a full example with only a single line of Hello World. It doesn’t necessarily has to be iText. I am open for other tools.


Get this bounty!!!

#StackBounty: #c# #.net #sqlite #dependency-injection #xamarin.forms Cannot create commands from unopened database

Bounty: 100

I’ve searched around quite a lot and I cannot find any answers to this.

I am writing a Xamarin Forms Mobile application, it seems when I minimise the application and then reopen it or one of my activities get launched the following exception gets thrown:

SQLiteConnection.CreateCommand (System.String cmdText, System.Object[] ps)
SQLite.SQLiteException: Cannot create commands from unopened database
SQLiteConnection.CreateCommand (System.String cmdText, System.Object[] ps)
TableQuery`1[T].GenerateCommand (System.String selectionList)
TableQuery`1[T].GetEnumerator ()
System.Collections.Generic.List`1[T]..ctor (System.Collections.Generic.IEnumerable`1[T] collection) [0x00062] in :0
Enumerable.ToList[TSource] (System.Collections.Generic.IEnumerable`1[T] source)
AsyncTableQuery`1[T].<ToListAsync>b__9_0 ()
Task`1[TResult].InnerInvoke ()
Task.Execute ()

Here is my code:

Generic Repository (Where the Sqlite instance gets created)

public class Repository<T> : IRepository<T> where T : Entity, new()
{
     private readonly SQLiteAsyncConnection _db;

    public Repository(string dbPath)
    {
        _db = new SQLiteAsyncConnection(dbPath);
        _db.CreateTableAsync<T>().Wait();
    }
}

The IOC registration

FreshIOC.Container.Register<IRepository<Settings>>(new Repository<Settings>(dbPath)); // FreshIOC is a wrapper around TinyIOC

In my App.xaml.cs OnResume

protected override void OnResume()
{
    SQLiteAsyncConnection.ResetPool();
}

The above with ResetPool I put that in to see if it would make a difference but it did not.

URL Activity

protected override void OnCreate(Bundle bundle)
{
    base.OnCreate(bundle);

    var url = Intent.Data.ToString();
    var split = url.Split(new[] { "ombi://", "_" }, StringSplitOptions.RemoveEmptyEntries);
    if (split.Length > 1)
    {
        var dbLocation = new FileHelper().GetLocalFilePath("ombi.db3");
        var repo = new Repository<OmbiMobile.Models.Entities.Settings>(dbLocation);
        var settings = repo.Get().Result;
        foreach (var s in settings)
        {
            var i = repo.Delete(s).Result;
        }
        repo.Save(new Settings
        {
            AccessToken = split[1],
            OmbiUrl = split[0]
        });
    }

    Intent startup = new Intent(this, typeof(MainActivity));
    StartActivity(startup);
    Finish();
}

I am not sure what else to do or look for, I can’t seem to find any information about this sort of error.


Get this bounty!!!

#StackBounty: #c++ #c++11 #templates #builder Factoring out repeated constructor calls in template-builder pattern

Bounty: 100

Consider the following builder-like class, which allows one to update member variables, as well as change template type parameters associated with the builder (only shown with a couple of template type parameters and members, but in practice there would be more):

template <typename T1 = DefaultT1, typename T2 = DefaultT2>
class Builder {
  int param1, param2;
  Builder(int param1, int param2) : param1{param1}, param2{param2} {}
public:
  Builder() : Builder(default1, default2) {}

  // methods to change param1 and param2 not shown

  /* return a new Builder with T1 changed to the given T1_NEW */
  template <typename T1_NEW>
  Builder<T1_NEW, T2   > withT1() { return {param1, param2}; }

  template <typename T2_NEW>
  Builder<T1   , T2_NEW> withT2() { return {param1, param2}; }

  Foo make() {
    // uses T1 and T2 to populate members of foo
    return Foo{ typename T1::member, typename T2::another };
  }
};

Note the withT1<> and withT2<> methods which allow you to return a new builder with a different type for T1 or T2 respectively. The bodies for these methods are identical: return {param1, param2};, and in practice much more complicated than shown here (e.g., if there are many parameters).

I’d like to factor the body out into some method which does the construction, like:

template <typename T1_, typename T2_>
Builder<T1_, T2_> copy() { return {param1, param2}; }

and then each withT* method could just call copy.

However, it isn’t clear to me how to avoid including the fully qualified type of Builder in the call:

template <typename T1_NEW>
Builder<T1_NEW, T2   > withT1() { return copy<T1_NEW, T2>(); }

Here the cure is worse than the original poison, since I need qualify each copy call with <T1_NEW, T2> (and this is different for each withT* method). Is there some way I can refer to the return type or other type of deduction which I can use to call copy() in the same way in each function?

I’m writing in C++11, but discussion of how a C++11 solution could be improved in later standards is also welcome.


Get this bounty!!!

#StackBounty: #c++ #solaris C++ ostream_withassign with << operator compile error

Bounty: 50

I’m working on some legacy code with an old Solaris compiler on Solaris 10 (no new fangled C++0x here 😉

-bash-3.2$ CC -V

CC: Sun C++ 5.12 SunOS_sparc 2011/11/16

I’ve got a 3rd party dictionary class with an iterator

template<K, V>
class DictIterator
{
    public:
        DictIterator(TheDictClass<K, V>& collection);
        K key() const;
        V value() const;
        // advance the iterator. return true if iterator points to a valid item
        bool operator()();
    ...
};

My code is supposed to go through each item in the dictionary but has a compile error that I can’t explain:

DictIterator iterator(theDictionary);
while(iterator())
{
    cout << iterator.key(); 
}

Fails with "filename.cc", line 42: Error: The operation "ostream_withassign<<Key" is illegal.

But this version works:

DictIterator iterator(theDictionary);
while(iterator())
{
    Key key(iterator.key());
    cout << key; 
}

Obviously I’ve got a workaround but I thought that since DictIterator.key() returns a K (not a reference), the two snippets were pretty similar. Can anyone let me know what weird corner of C++ I’ve just bumped into?

edit: To answer comments, << is overridden ostream& operator(ostream &, Key&);


Get this bounty!!!

#StackBounty: #c++ #game #c++17 C++ Inventory System

Bounty: 50

I have recently been working a lot on a project for a system that represents an inventory and item usage in a game, with one of the important features is that it should be reusable in multiple projects. I think I managed to do this quite well, keeping the required interface as minimum as possible. I have come to a point where I think the project is finished, but I would like to get feedback on where I can still improve the code. It’s really long, so I’m not sure if I should post everything here. I will just post the main Inventory header here, and the rest of the code can be found on github. If I do need to copy all code here, let me know.

Inventory.h

#pragma once

#include "IItem.h"
#include "ItemDispatcher.h"
#include <memory>
#include <functional>
#include <string>
#include <unordered_map>
#include <string_view>
#include <type_traits>
#include <utility>



template<unsigned int MAX_SIZE, typename GameObjTy = temp::GameObject, typename ItemTy = IItem>
class Inventory
{
private:

    class Traits //class to simulate namespace inside class
    {
    public:

        /*HasUseMethod type trait*/

        template<typename _Ty, typename = std::void_t<>>
        struct HasUseMethodHelper : std::false_type 
        {
        };

        template<typename _Ty>
        struct HasUseMethodHelper<_Ty, std::void_t<decltype(std::declval<_Ty>().use(std::declval<ItemDispatcher<GameObjTy>&>()))>> : std::true_type
        {
        };

        template<typename _Ty>
        struct HasUseMethodT : HasUseMethodHelper<_Ty>::type
        {
        };

        template<typename _Ty> using HasUseMethod = typename HasUseMethodT<_Ty>::type;
        template<typename _Ty> static constexpr bool HasUseMethodV = HasUseMethod<_Ty>::value;

        /*HasEquippabmeMethod type trait*/

        template<typename _Ty, typename = std::void_t<>>
        struct HasEquippableMethodHelper : std::false_type
        {
        };

        template<typename _Ty>
        struct HasEquippableMethodHelper<_Ty, 
            std::void_t<decltype(std::is_same_v<decltype(std::declval<_Ty>().equippable()), bool >)>> : std::true_type
        {
        };

        template<typename _Ty>
        struct HasEquippableMethodT : HasEquippableMethodHelper<_Ty>::type
        {
        };

        template<typename _Ty> using HasEquippableMethod = typename HasEquippableMethodT<_Ty>::type;
        template<typename _Ty> static constexpr bool HasEquippableMethodV = HasEquippableMethod<_Ty>::value;

        /*HasIsEquipped type trait*/

        template<typename _Ty, typename = std::void_t<>>
        struct HasIsEquippedMethodHelper : std::false_type
        {
        };

        template<typename _Ty>
        struct HasIsEquippedMethodHelper<_Ty, 
            std::void_t<decltype(std::is_same_v<decltype(std::declval<_Ty>().is_equipped()), bool >)>> : std::true_type
        {
        };

        template<typename _Ty>
        struct HasIsEquippedMethodT : HasIsEquippedMethodHelper<_Ty>::type
        {
        };

        template<typename _Ty> using HasIsEquippedMethod = typename HasIsEquippedMethodT<_Ty>::type;
        template<typename _Ty> static constexpr bool HasIsEquippedMethodV = HasIsEquippedMethod<_Ty>::value;

        /*HasSetEquip type trait*/

        template<typename _Ty, typename = std::void_t<>>
        struct HasSetEquipMethodHelper : std::false_type
        {
        };

        template<typename _Ty>
        struct HasSetEquipMethodHelper<_Ty, 
            std::void_t<decltype(std::is_same_v<decltype(std::declval<_Ty>().set_equip(std::declval<bool>())), void >)>> 
                : std::true_type
        {
        };

        template<typename _Ty>
        struct HasSetEquipMethodT : HasSetEquipMethodHelper<_Ty>::type
        {
        };

        template<typename _Ty> using HasSetEquipMethod = typename HasSetEquipMethodT<_Ty>::type;
        template<typename _Ty> static constexpr bool HasSetEquipMethodV = HasSetEquipMethod<_Ty>::value;

        /*HasUnequipMethod type trait*/

        template<typename _Ty, typename = std::void_t<>>
        struct HasUnequipMethodHelper : std::false_type
        {
        };

        template<typename _Ty>
        struct HasUnequipMethodHelper<_Ty, 
            std::void_t<decltype(std::is_same_v<decltype(std::declval<_Ty>().unequip(std::declval<GameObjTy*>())), void >)>> 
                : std::true_type
        {
        };

        template<typename _Ty>
        struct HasUnequipMethodT : HasUnequipMethodHelper<_Ty>::type
        {
        };

        template<typename _Ty> using HasUnequipMethod = typename HasUnequipMethodT<_Ty>::type;
        template<typename _Ty> static constexpr bool HasUnequipMethodV = HasUnequipMethod<_Ty>::value;

        /*HasReusableMethod type trait*/

        template<typename _Ty, typename = std::void_t<>>
        struct HasReusableMethodHelper : std::false_type
        {
        };

        template<typename _Ty>
        struct HasReusableMethodHelper<_Ty, 
            std::void_t<decltype(std::is_same_v<decltype(std::declval<_Ty>().reusable()), bool >)>> 
                : std::true_type
        {
        };

        template<typename _Ty>
        struct HasReusableMethodT : HasReusableMethodHelper<_Ty>::type
        {
        };

        template<typename _Ty> using HasReusableMethod = typename HasReusableMethodT<_Ty>::type;
        template<typename _Ty> static constexpr bool HasReusableMethodV = HasReusableMethod<_Ty>::value;

        template<typename _Ty, typename = std::void_t<>>
        struct HasStackableMethodHelper : std::false_type
        {
        };

        template<typename _Ty>
        struct HasStackableMethodHelper<_Ty, 
            std::void_t<decltype(std::is_same_v<decltype(std::declval<_Ty>().stackable()), bool>)>>
                : std::true_type
        {
        };

        template<typename _Ty>
        struct HasStackableMethodT : HasStackableMethodHelper<_Ty>::type
        {
        };

        template<typename _Ty> using HasStackableMethod = typename HasStackableMethodT<_Ty>::type;
        template<typename _Ty> static constexpr bool HasStackableMethodV = HasStackableMethod<_Ty>::value;

        template<typename _Ty>
        struct IsValidItemT
        {
            static constexpr bool value =
                HasEquippableMethodV<_Ty>
                && HasUseMethodV<_Ty>
                && HasIsEquippedMethodV<_Ty>
                && HasSetEquipMethodV<_Ty>
                && HasEquippableMethodV<_Ty>
                && HasReusableMethodV<_Ty>
                && HasStackableMethodV<_Ty>;
        };

        template<typename _Ty> using IsValidItem = typename IsValidItemT<_Ty>::type;
        template<typename _Ty> static constexpr bool IsValidItemV = IsValidItemT<_Ty>::value;
    };

public:
    static_assert(Traits::IsValidItemV<ItemTy>, "Item type is invalid. It should provide methods listed in documentation");

    class Exception
    {
    private:
        std::string msg;
    public:
        explicit inline Exception(std::string_view error) : msg {error} {}
        inline std::string_view what() { return msg; }
    };

    using game_object_type = GameObjTy; 
    using item_type = ItemTy; 
    using item_pointer = std::unique_ptr<item_type>;

    using game_object_pointer = game_object_type*;
    using inventory_type = std::unordered_map<std::string, std::pair<item_pointer, unsigned int>>;
    using iterator = typename inventory_type::iterator;
    using const_iterator = typename inventory_type::const_iterator;
    using size_type = typename inventory_type::size_type;

    explicit Inventory(game_object_pointer owner);
    Inventory(Inventory const& other) = delete;
    Inventory(Inventory&& other);

    Inventory& operator=(Inventory const& other) = delete;
    Inventory& operator=(Inventory&& other);

    inventory_type const& contents() const;
    inventory_type& contents();

    /*Adds a new item, stacked on top of an item with the same ID. The id parameter will be used to access the item*/
    template<typename ItemT>
    void addItem(std::string_view id);

    /*constructs a new item and adds it to the inventory. The id parameter will be used to access the item*/
    template<typename ItemT, typename... Args>
    void emplaceItem(std::string_view id, Args... args);

    void useItem(std::string_view name, game_object_pointer target = nullptr);

    /*The iterators invalidate when a new Item is added to the inventory*/
    iterator getItem(std::string_view name);
    /*The iterators invalidate when a new Item is added to the inventory*/
    const_iterator getItem(std::string_view name) const;

    void removeItem(std::string_view name);

    iterator begin();
    iterator end();

    const_iterator cbegin() const;
    const_iterator cend() const;

    size_type max_size() const;
    size_type size() const;

    /*Merges inventory A with this inventory. Leaves other empty, unless this inventory is full, in which case the leftover
      elements will be deleted*/ //#TODO: leftover elements are left in old inventory?
    template<unsigned int N>
    void merge(Inventory<N, GameObjTy, ItemTy>& other);

    template<unsigned int N>
    bool merge_fits(Inventory<N, GameObjTy, ItemTy> const& other);

    /*Transfers item with name parameter into the inventory specified in destination, unless destination does not have enough
     *space left*/
    template<unsigned int N>
    void transfer(Inventory<N, GameObjTy, ItemTy>& destination, std::string_view name);

    bool empty() const;
    bool full() const;

    void setOwner(game_object_pointer owner);
    game_object_pointer getOwner() const;

    void clear();
    unsigned int getItemCount(std::string_view id) const;

private:
    size_type m_size = 0;

    inventory_type m_items { MAX_SIZE };
    game_object_pointer m_owner { nullptr };

    //these functions are private so you cannot accidentally pass an invalid iterator to one of these, causing undefined behavior

    void useItem(iterator pos, game_object_pointer target = nullptr); 
    void removeItem(iterator pos);

    inline Exception InventoryFullException() const { return Exception {"Inventory is full"}; }
    inline Exception InvalidItemTypeException() const { return Exception {"Item type must be derived from Inventory::ItemTy, which defaults to IItem"}; }
    inline Exception InvalidItemException() const { return Exception { "Invalid item name" }; }
    inline Exception InvalidStackException() const { return Exception {"Tried to stack a non-stackable item"}; }
    inline Exception InvalidIDException() const { return Exception {"ID not found in inventory"}; }
};

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
Inventory<MAX_SIZE, GameObjTy, ItemTy>::Inventory(game_object_pointer owner) : m_owner(owner)
{

}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
Inventory<MAX_SIZE, GameObjTy, ItemTy>::Inventory(Inventory&& other) : m_owner(std::move(other.m_owner)), m_items(std::move(other.m_items)), m_size(other.m_size)
{
    other.m_owner = nullptr;
    other.m_items = inventory_type {};
    other.m_size = 0;
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
Inventory<MAX_SIZE, GameObjTy, ItemTy>& Inventory<MAX_SIZE, GameObjTy, ItemTy>::operator=(Inventory<MAX_SIZE, GameObjTy, ItemTy>&& other)
{
    // #WARNING: Self assignment check is missing
    m_owner = other.m_owner;
    m_items = std::move(other.m_items);
    m_size = other.m_size;

    other.m_owner = nullptr;
    other.m_items = inventory_type {};
    other.m_size = 0;

    return *this;
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
typename Inventory<MAX_SIZE, GameObjTy, ItemTy>::inventory_type const& Inventory<MAX_SIZE, GameObjTy, ItemTy>::contents() const
{
    return m_items;
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
typename Inventory<MAX_SIZE, GameObjTy, ItemTy>::inventory_type& Inventory<MAX_SIZE, GameObjTy, ItemTy>::contents()
{
    return m_items;
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
typename Inventory<MAX_SIZE, GameObjTy, ItemTy>::iterator Inventory<MAX_SIZE, GameObjTy, ItemTy>::begin() 
{ 
    return m_items.begin(); 
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
typename Inventory<MAX_SIZE, GameObjTy, ItemTy>::iterator Inventory<MAX_SIZE, GameObjTy, ItemTy>::end()
{
    return m_items.end();
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
typename Inventory<MAX_SIZE, GameObjTy, ItemTy>::const_iterator Inventory<MAX_SIZE, GameObjTy, ItemTy>::cbegin() const 
{ 
    return m_items.cbegin(); 
}
template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
typename Inventory<MAX_SIZE, GameObjTy, ItemTy>::const_iterator Inventory<MAX_SIZE, GameObjTy, ItemTy>::cend() const 
{ 
    return m_items.cend(); 
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
typename Inventory<MAX_SIZE, GameObjTy, ItemTy>::iterator Inventory<MAX_SIZE, GameObjTy, ItemTy>::getItem(std::string_view name)
{
    return m_items.find(name.data());
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
typename Inventory<MAX_SIZE, GameObjTy, ItemTy>::const_iterator Inventory<MAX_SIZE, GameObjTy, ItemTy>::getItem(std::string_view name) const
{
    return m_items.find(name.data());
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
void Inventory<MAX_SIZE, GameObjTy, ItemTy>::useItem(std::string_view name, game_object_pointer target)
{
    useItem(getItem(name), target);
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
template<typename ItemT>
void Inventory<MAX_SIZE, GameObjTy, ItemTy>::addItem(std::string_view id)
{
    if constexpr (!std::is_base_of_v<item_type, ItemT>)
        throw InvalidItemTypeException();

    if (size() >= MAX_SIZE)
    {
        throw InventoryFullException();
    }

    if (m_items.find(id.data()) != m_items.end()) //if we already own this item, increment the count
    {
        if (!m_items[id.data()].first->stackable())
            throw InvalidStackException();
        m_items[id.data()].second += 1; //increment count
        m_size += 1;
    }
    else
    {
        throw InvalidIDException();
    }
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
template<typename ItemT, typename... Args>
void Inventory<MAX_SIZE, GameObjTy, ItemTy>::emplaceItem(std::string_view id, Args... args)
{
    if constexpr (!std::is_base_of_v<item_type, ItemT>)
        throw InvalidItemTypeException();

    if (size() >= MAX_SIZE)
    {
        throw InventoryFullException();
    }

    m_items[id.data()] = std::make_pair(std::make_unique<ItemT>(std::forward<Args>(args)...), 1);
    m_size += 1;
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
void Inventory<MAX_SIZE, GameObjTy, ItemTy>::useItem(iterator pos, game_object_pointer target)
{
    if (pos == m_items.end()) throw InvalidItemException();

    //use the item

    ItemDispatcher<GameObjTy> dispatcher { target };

    auto& it = *pos;
    auto& itemPair = it.second;
    auto& item = itemPair.first;

    if (item->equippable())
    {
        dispatcher.setTarget(m_owner);
        if (!item->is_equipped())
        {
            item->set_equip(true);
            item->use(dispatcher);
        }
        else
        {
            item->set_equip(false);
            item->use(dispatcher);
        }
        return;
    }
    else
    {
        dispatcher.setTarget(target);
        item->use(dispatcher); //dispatcher.target == target, see construction above
    }

    if (!item->reusable())
    {
        if (!item->stackable())
            removeItem(pos);
        else
        {
            if (itemPair.second > 1) itemPair.second -= 1; //decrement count if we have more than 1
            else removeItem(pos);
        }
        m_size -= 1;
    }
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
void Inventory<MAX_SIZE, GameObjTy, ItemTy>::removeItem(iterator pos)
{
    m_items.erase(pos);
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
void Inventory<MAX_SIZE, GameObjTy, ItemTy>::removeItem(std::string_view name)
{
    removeItem(getItem(name));
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
void Inventory<MAX_SIZE, GameObjTy, ItemTy>::setOwner(game_object_pointer owner)
{
    m_owner = owner;
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
typename Inventory<MAX_SIZE, GameObjTy, ItemTy>::game_object_pointer Inventory<MAX_SIZE, GameObjTy, ItemTy>::getOwner() const
{
    return m_owner;
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
typename Inventory<MAX_SIZE, GameObjTy, ItemTy>::size_type Inventory<MAX_SIZE, GameObjTy, ItemTy>::max_size() const
{
    return MAX_SIZE;
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
typename Inventory<MAX_SIZE, GameObjTy, ItemTy>::size_type Inventory<MAX_SIZE, GameObjTy, ItemTy>::size() const
{
    return m_size;
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
template<unsigned int N>
void Inventory<MAX_SIZE, GameObjTy, ItemTy>::merge(Inventory<N, GameObjTy, ItemTy>& other)
{
    if (!merge_fits(other))
        throw InventoryFullException();

    for (auto& it = other.begin(); it != other.end(); std::advance(it, 1))
    {

        this->m_items[it->first] = std::move(it->second);
    }
    other.clear();
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
void Inventory<MAX_SIZE, GameObjTy, ItemTy>::clear()
{
    m_size = 0;
    m_items.clear();
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
template<unsigned int N>
bool Inventory<MAX_SIZE, GameObjTy, ItemTy>::merge_fits(Inventory<N, GameObjTy, ItemTy> const& other)
{
    return !(full() || other.size() + this->size() >= max_size());
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
template<unsigned int N>
void Inventory<MAX_SIZE, GameObjTy, ItemTy>::transfer(Inventory<N, GameObjTy, ItemTy>& destination, std::string_view name)
{   
    if (destination.full())
        return;

    auto& it = getItem(name);
    auto& item = (*it).second;

    destination.contents()[name.data()] = std::move(item);

    m_items.erase(it);
    m_size -= 1;
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
bool Inventory<MAX_SIZE, GameObjTy, ItemTy>::empty() const
{
    return size() <= 0;
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
bool Inventory<MAX_SIZE, GameObjTy, ItemTy>::full() const
{
    return max_size() <= size();
}

template<unsigned int MAX_SIZE, typename GameObjTy, typename ItemTy>
unsigned int Inventory<MAX_SIZE, GameObjTy, ItemTy>::getItemCount(std::string_view id) const
{
    if (m_items.find(id.data()) == m_items.end()) throw InvalidItemException();
    return m_items.at(id.data()).second;
}

I will also add a main.cpp test file just to demonstrate how this can be used

main.cpp

#include "DamagePotion.h"
#include "Inventory.h"
#include "HealPotion.h"
#include "Sword.h"
#include "ItemUtil.h"

std::ostream& operator<<(std::ostream& out, ItemID const& id)
{
    if (id == ItemID::DAMAGE_POTION)
    {
        out << "ID_DAMAGE_POTION";
    }
    else if (id == ItemID::DEFAULT_ITEM) out << "ID_DEFAULT_ITEM";
    else if (id == ItemID::HEAL_POTION) out << "ID_HEAL_POTION";
    else if (id == ItemID::SWORD) out << "ID_SWORD";
    return out;
}

//Replace temp::GameObject class with the GameObject class used by your game

class Player : public temp::GameObject
{
public:
    Player() : temp::GameObject(200)
    {
        try
        {
            m_inventory.emplaceItem<DamagePotion>("Damage Potion I", 50);
            m_inventory.emplaceItem<HealPotion>("Heal Potion I", 70);
            m_inventory.emplaceItem<Sword>("Sword I", 20);

            std::cout << "Inventory contents after adding base items:n";
            for (auto const& it : m_inventory.contents()) std::cout << it.second.first->id() << "n";
            std::cout << "n";

            m_inventory.useItem("Damage Potion I", this);
            m_inventory.useItem("Heal Potion I", this);
            m_inventory.useItem("Sword I");

            std::cout << "Inventory contents after using base items:n";
            for (auto const& it : m_inventory.contents()) std::cout << it.second.first->id() << "n";
            std::cout << "n";

            m_inventory.useItem("Sword I"); // will unequip Sword I

            std::cout << "Inventory contents after unequipping Sword I:n";
            for (auto const& it : m_inventory.contents()) std::cout << it.second.first->id() << "n";
            std::cout << "n";

            chest.emplaceItem<DamagePotion>("CDmgPot", 100);
            chest.emplaceItem<HealPotion>("CHealPot", 200);

            std::cout << "Chest contents after adding base items:n";
            for (auto const& it : chest.contents()) std::cout << it.second.first->id() << "n";
            std::cout << "n";

            m_inventory.merge(chest);

            std::cout << "Chest contents after merging with inventory:n";
            for (auto const& it : chest.contents()) std::cout << it.second.first->id() << "n";
            std::cout << "n";
            std::cout << "Inventory contents after merging with chest:n";
            for (auto const& it : m_inventory.contents()) std::cout << it.second.first->id() << "n";
            std::cout << "n";

            chest.emplaceItem<Sword>("CSword", 50);

            std::cout << "Chest contents after adding CSword:n";
            for (auto const& it : chest.contents()) std::cout << it.second.first ->id() << "n";
            std::cout << "n";

            chest.transfer(m_inventory, "CSword");

            std::cout << "Inventory contents after transferring CSword from chest:n";
            for (auto const& it : m_inventory.contents()) std::cout << it.second.first->id() << "n";
            std::cout << "n";

            chest.emplaceItem<Sword>("CSword", 20);

            std::cout << "Chest contents after adding a CSword:n";
            for (auto const& it : chest.contents()) std::cout << it.second.first->id() << "n";
            std::cout << "n";

            chest.removeItem("CSword");

            std::cout << "Chest contents after removing a CSword:n";
            for (auto const& it :chest.contents()) std::cout << it.second.first->id() << "n";
            std::cout << "n";
        }
        catch (std::runtime_error e)
        {
            std::cerr << e.what();
        }
    }

private:
    Inventory<200> m_inventory { this };

    Inventory<5> chest { this };
};


struct InvalidItem
{

};

struct InvalidEquippable
{
    void equippable()
    {

    }
};

class TestClass : public temp::GameObject
{
public:
    TestClass() : temp::GameObject(50)
    {
        try
        {

            Inventory<100> inv { this };

            inv.emplaceItem<ItemType<ItemID::DAMAGE_POTION>::type>("P", 20);
            inv.addItem<DamagePotion>("P");

            std::cout << ItemName(ItemID::HEAL_POTION) << ' ' << ItemId<Sword>() << 'n';

            std::cout << inv.getItemCount("P") << 'n';

            inv.useItem("P", this);
            inv.useItem("P", this);

            std::cout << getHealth() << 'n';

            std::cout << inv.getItemCount("P") << 'n';
        }
        catch (Inventory<100>::Exception e)
        {
            std::cout << e.what() << "n";
        }
    }
};



int main()
{

    Player p;


//  IItem* base_ptr;

//  Inventory<200> {nullptr};

    //Fails to compile due to traits
//  Inventory<100, temp::GameObject, InvalidItem> {nullptr};
//  Inventory<100, temp::GameObject, InvalidEquippable> {nullptr};

//  base_ptr = new DamagePotion(20);

//  temp::GameObject target { 100 };
/*
    std::cout << "Using Item: n";
    std::cout << "Name:t" << base_ptr->name() << "n";
    std::cout << "ID:t" << base_ptr->id() << "n";
    base_ptr->use(&target);
*/


    std::cin.get();
}

Note: I have just read a meta post that says that it is not allowed to post GitHub links. I am not sure what I should do in this case, as I mostly want the Inventory header reviewed. The files in the github repo are only for when there really is more information required.

EDIT: as per request in the comments, here are some further explanations:

Architecture

As I created this project with portability across other projects in mind, so as a kind of library, the architecture is designed to be as simple to use as possible. All Items will be inherited from a base IItem class, or any other class that supports the functions in the Inventory::Traits class. The inventory is responsible for managing the resources of every item, and for creating them. So when adding an item you call

inventory.emplaceItem<SomePotion>("Potion", 50); //the 50 is passed to SomePotion's constructor

MAX_SIZE

MAX_SIZE is a template parameter due to an unlucky design choice at the very beginning. Since I did not want to do lots of allocations for items, I wanted to have the size fixed. This is probably completely unneccesary, but annoying to remove now.

Item usage

Since the Inventory is responsible for using the items (by calling useItem("name", target_ptr);), I needed some way of doing that. I chose for the Visitor Pattern, which I implemented with the ItemDispatcher class.

Data Structure

The items are stored in a std::unordered_map<std::string, std::pair<std::unique_ptr<Item>, unsigned>>; I will break down why I chose for this. First of all, I wanted the items to be accessible in some way. Iterators were clumsy, because they would invalidate when an item is added to the inventory. I still kept the begin() and end() functions for if you would want to iterate through an inventory in a loop. So I chose for an undoredered map, with string indices so you can give every item its own string ID. The items are stored as a pair of [Item, Count], since I wanted to be able to stack items where possible (Item.stackable() == true).

Reusability

About the reusable in multiple projects. With that I mean that if I, at some point decide to make an RPG game, and the character needs an inventory, that I can just use this exact Inventory class without any modifications. If I then later want to make another, completely different game that also features an Inventory, or some other way of storing items, I can reuse this again.

Techniques

The Traits class is used as a wrapper for the SFINAE type traits that I use to detect if an eventual custom Item type supports all required functions, set for example like:

Inventory<200, MyCoolGameObject, MyCoolItem> inventory;

Traits is a class because I can’t do

class X
{
    namespace Y
    {

    };
};


Get this bounty!!!