NS/main/source/util/Balance.h

213 lines
10 KiB
C
Raw Normal View History

//======== (C) Copyright 2002 Charles G. Cleveland All rights reserved. =========
//
// The copyright to the contents herein is the property of Charles G. Cleveland.
// The contents may be used and/or copied only with the written permission of
// Charles G. Cleveland, or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//===============================================================================
#ifndef BALANCE_H
#define BALANCE_H
#include <string>
#include <map>
#include <memory>
#include "Balance.txt" //default balancing source - this used to be ../Balance.txt
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// BalanceValueContainerFactory -- facade that creates, stores, and
// maintains BalanceValueContainer objects. Multiple calls with the
// same parameter will return the same object. The (void) function
// call is equivalent to calling for a filename with an empty string.
// Invalid filenames will still return an usable BalanceValueContainer,
// but that container will not be able to save later.
//
// The objects that this function creates should not be manually
// deleted; it is responsible for cleanup of the objects.
//
// TODO: Add another constructor for UPP::ProductInfo objects
// TODO: Make retrieval/creation of objects thread safe (it's not)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class BalanceValueContainer;
namespace BalanceValueContainerFactory
{
BalanceValueContainer* get(const std::string& filename);
BalanceValueContainer* get(void);
const std::string& getDefaultFilename(void);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// BalanceChangeListener -- abstract class that allows arbitrary
// items to listen for changes to the balancing system. Items can
// register for individual values or for the entire balance variable
// set. Listeners are notified in advance of each change, but don't
// have the authority to override.
//
// The shouldNotify function is a filter for items registered for
// entire sets, allowing them to select items they are actually
// interested in receiving. Items that are registered for specific
// variables skip the shouldNotify check.
//
// When a BalanceValueContainer is wiped, the balanceCleared function
// is called rather than iterating over all of the values for all of
// the attached listeners. It should be considered a signal that
// all items the listener is interested in have been removed.
//
// The BalanceStartCompoundChange and BalanceEndCompoundChange
// functions provide rough grain functionality for listeners that
// want to only operate once on a large change (such as a complete
// reset) instead of once per change. By combining these functions
// with an internal state variable, they can know when to ignore
// individual signals. The compound change functions will not be
// called for individual balance changes, so it's important to track
// these as well if you want a catch-all method of detecting changes.
//
// The compound change functions will only be called for universally
// registered listeners.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
enum BalanceValueType {
BALANCE_TYPE_FLOAT = 1,
BALANCE_TYPE_INT = 2,
BALANCE_TYPE_STRING = 3
};
class BalanceChangeListener
{
public:
unsigned int getBalanceChangeListenerID(void) const;
virtual ~BalanceChangeListener(void);
virtual bool shouldNotify(const std::string& name, const BalanceValueType type) const;
virtual void balanceCleared(void) const;
virtual void balanceValueInserted(const std::string& name, const float value) const;
virtual void balanceValueInserted(const std::string& name, const int value) const;
virtual void balanceValueInserted(const std::string& name, const std::string& value) const;
virtual void balanceValueChanged(const std::string& name, const float old_value, const float new_value) const;
virtual void balanceValueChanged(const std::string& name, const int old_value, const int new_value) const;
virtual void balanceValueChanged(const std::string& name, const std::string& old_value, const std::string& default_value) const;
virtual void balanceValueRemoved(const std::string& name, const float old_value) const;
virtual void balanceValueRemoved(const std::string& name, const int old_value) const;
virtual void balanceValueRemoved(const std::string& name, const std::string& old_value) const;
virtual void balanceStartCompoundChange(void) const;
virtual void balanceEndCompoundChange(void) const;
protected:
BalanceChangeListener(void);
private:
const unsigned int BCL_ID; //handle for tracking registrations; internal use only
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// BalanceValueContainer -- abstract parent class for balance variable
// storage and retrieval with change notification.
//
// It is possible to actually use the same name for multiple variable
// types at runtime, but the results are undefined if the conflict
// is saved or reloaded, so it's important to be careful when using
// value types.
//
// When calling addListener, multiple registrations for the same
// variable name or multiple global registrations have no added
// effect. If a listener is registered globally and for a specific
// variable, it will still only be called once per event.
//
// When calling removeListener without a name argument, only the
// universal listener location is checked for the matching pointer.
// It is safe to leave listeners registered with a container even
// after the listeners have been deconstructed, so it is not required
// to unregister a listener from many different items.
//
// The equality and inequality checks test the equality/inequality
// of the value maps. The assignment operator performs the minimum
// number of changes required for the value maps to become equal.
// This is much more complex than simple reassignment, but it allows
// proper notification of BalanceChangeListeners.
//
// TODO: Make addition/removal of listeners thread safe (it's not)
// TODO: Make assignment thread safe (it's not)
// TODO: Make insertion/retrieval/removal of values thread safe
// TODO: Make load a minimal change operation (like assignment)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef std::map<std::string,float> BalanceFloatCollection;
typedef std::map<std::string,int> BalanceIntCollection;
typedef std::map<std::string,std::string> BalanceStringCollection;
class BalanceValueContainer
{
public:
virtual ~BalanceValueContainer(void);
virtual BalanceValueContainer& operator=(const BalanceValueContainer& other) = 0;
virtual bool operator!=(const BalanceValueContainer& other) const = 0;
virtual bool operator==(const BalanceValueContainer& other) const = 0;
virtual bool load(void) = 0;
virtual bool save(void) = 0;
virtual const float get(const std::string& name, const float default_value) const = 0;
virtual const int get(const std::string& name, const int default_value) const = 0;
virtual const std::string get(const std::string& name, const std::string& default_value) const = 0;
virtual const BalanceFloatCollection* getFloatMap(void) const = 0;
virtual const BalanceIntCollection* getIntMap(void) const = 0;
virtual const BalanceStringCollection* getStringMap(void) const = 0;
virtual void insert(const std::string& name, const float value) = 0;
virtual void insert(const std::string& name, const int value) = 0;
virtual void insert(const std::string& name, const std::string& value) = 0;
virtual void remove(const std::string& name) = 0;
virtual void clear(void) = 0;
virtual void addListener(const BalanceChangeListener* listener) = 0;
virtual void addListener(const std::string& name, const BalanceChangeListener* listener) = 0;
virtual void removeListener(const BalanceChangeListener* listener) = 0;
virtual void removeListener(const std::string& name, const BalanceChangeListener* listener) = 0;
protected:
BalanceValueContainer(void);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// BALANCE_VAR(x) macro - the heart of the balance system, ties value
// to default balance source if PLAYTEST_BUILD is enabled, uses
// hardcoded value otherwise. Place the name of the varaible #define
// in Balance.txt as the value in the macro.
//
// BALANCE_LISTENER(x) macro - for registering global
// BalanceChangeListeners (see below), reverts to no operation
// if AVH_PLAYTEST_BUILD isn't enabled.
//
// BALANCE_FIELD_LISTENER(x,y) macro - for registering field-specific
// BalanceChangeListeners, reverts to no operation if
// BALANCE_ENABLED isn't defined
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#ifdef BALANCE_ENABLED //use Balance.txt values on server, no-source/explicitly set values for client
#ifdef SERVER
#define BALANCE_DEFNAME BalanceValueContainerFactory::getDefaultFilename()
#else
#define BALANCE_DEFNAME ""
#endif
inline void BALANCE_LISTENER(const BalanceChangeListener* object) { BalanceValueContainerFactory::get(BALANCE_DEFNAME)->addListener(object); }
inline void BALANCE_FIELD_LISTENER(const BalanceChangeListener* object, const char* field) { BalanceValueContainerFactory::get(BALANCE_DEFNAME)->addListener(field,object); }
#define BALANCE_VAR(name) GetBalanceVar(#name,name) //requires macro for string-izing of name
inline int GetBalanceVar(const char* name, const int value) { return BalanceValueContainerFactory::get(BALANCE_DEFNAME)->get(name,value); }
inline float GetBalanceVar(const char* name, const float value) { return BalanceValueContainerFactory::get(BALANCE_DEFNAME)->get(name,value); }
inline float GetBalanceVar(const char* name, const double value) { return BalanceValueContainerFactory::get(BALANCE_DEFNAME)->get(name,(float)value); }
inline std::string GetBalanceVar(const char* name, const char* value) { return BalanceValueContainerFactory::get(BALANCE_DEFNAME)->get(name,value); }
#else
#define BALANCE_VAR(name) name //hardcodes the value at compile time
#define BALANCE_LISTENER(object)
#define BALANCE_FIELD_LISTENER(object,name)
#endif //BALANCE_ENABLED
#endif //BALANCE_H