forked from mirror/openmw-tes3mp
Merge branch 'master' of https://github.com/zinnschlag/openmw into terrain_next
Conflicts: CMakeLists.txt
This commit is contained in:
commit
8be661c802
51 changed files with 1620 additions and 2599 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -7,6 +7,9 @@ Docs/mainpage.hpp
|
|||
CMakeFiles
|
||||
*/CMakeFiles
|
||||
CMakeCache.txt
|
||||
moc_*.cxx
|
||||
cmake_install.cmake
|
||||
*.[ao]
|
||||
Makefile
|
||||
makefile
|
||||
data
|
||||
|
|
|
@ -18,8 +18,8 @@ include (OpenMWMacros)
|
|||
# Version
|
||||
|
||||
set (OPENMW_VERSION_MAJOR 0)
|
||||
set (OPENMW_VERSION_MINOR 11)
|
||||
set (OPENMW_VERSION_RELEASE 1)
|
||||
set (OPENMW_VERSION_MINOR 12)
|
||||
set (OPENMW_VERSION_RELEASE 0)
|
||||
|
||||
set (OPENMW_VERSION "${OPENMW_VERSION_MAJOR}.${OPENMW_VERSION_MINOR}.${OPENMW_VERSION_RELEASE}")
|
||||
|
||||
|
@ -192,7 +192,7 @@ find_package(Bullet REQUIRED)
|
|||
include_directories("."
|
||||
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE
|
||||
${OGRE_Terrain_INCLUDE_DIR}
|
||||
${OIS_INCLUDE_DIR} ${Boost_INCLUDE_DIR}
|
||||
${OIS_INCLUDE_DIRS} ${Boost_INCLUDE_DIR}
|
||||
${PLATFORM_INCLUDE_DIR}
|
||||
${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/MyGUIEngine/include
|
||||
${CMAKE_HOME_DIRECTORY}/extern/mygui_3.0.1/OgrePlatform/include
|
||||
|
@ -297,7 +297,7 @@ if(DPKG_PROGRAM)
|
|||
|
||||
SET(CPACK_GENERATOR "DEB")
|
||||
SET(CPACK_PACKAGE_NAME "openmw")
|
||||
SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://openmw.com")
|
||||
SET(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://openmw.org")
|
||||
SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
|
||||
SET(CPACK_DEBIAN_PACKAGE_MAINTAINER "${PACKAGE_MAINTAINER}")
|
||||
SET(CPACK_DEBIAN_PACKAGE_DESCRIPTION "A reimplementation of The Elder Scrolls III: Morrowind
|
||||
|
@ -326,7 +326,6 @@ if(WIN32)
|
|||
FILE(GLOB files "${OpenMW_BINARY_DIR}/Release/*.*")
|
||||
INSTALL(FILES ${files} DESTINATION ".")
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
|
||||
INSTALL(FILES "${OpenMW_BINARY_DIR}/launcher.cfg" "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION ".")
|
||||
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
|
||||
|
||||
SET(CPACK_GENERATOR "NSIS")
|
||||
|
@ -345,11 +344,17 @@ if(WIN32)
|
|||
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
|
||||
SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe")
|
||||
|
||||
SET(VCREDIST "${OpenMW_BINARY_DIR}/vcredist_x86.exe")
|
||||
if(EXISTS ${VCREDIST})
|
||||
INSTALL(FILES ${VCREDIST} DESTINATION "redist")
|
||||
SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe")
|
||||
if(EXISTS ${VCREDIST32})
|
||||
INSTALL(FILES ${VCREDIST32} DESTINATION "redist")
|
||||
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x86.exe\\\" /q'" )
|
||||
endif(EXISTS ${VCREDIST})
|
||||
endif(EXISTS ${VCREDIST32})
|
||||
|
||||
SET(VCREDIST64 "${OpenMW_BINARY_DIR}/vcredist_x64.exe")
|
||||
if(EXISTS ${VCREDIST64})
|
||||
INSTALL(FILES ${VCREDIST64} DESTINATION "redist")
|
||||
SET(CPACK_NSIS_EXTRA_INSTALL_COMMANDS "ExecWait '\\\"$INSTDIR\\\\redist\\\\vcredist_x64.exe\\\" /q'" )
|
||||
endif(EXISTS ${VCREDIST64})
|
||||
|
||||
SET(OALREDIST "${OpenMW_BINARY_DIR}/oalinst.exe")
|
||||
if(EXISTS ${OALREDIST})
|
||||
|
@ -358,6 +363,10 @@ if(WIN32)
|
|||
ExecWait '\\\"$INSTDIR\\\\redist\\\\oalinst.exe\\\" /s'" )
|
||||
endif(EXISTS ${OALREDIST})
|
||||
|
||||
if(CMAKE_CL_64)
|
||||
SET(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64")
|
||||
endif()
|
||||
|
||||
include(CPack)
|
||||
endif(WIN32)
|
||||
|
||||
|
@ -420,19 +429,13 @@ endif()
|
|||
if (APPLE)
|
||||
set(INSTALL_SUBDIR OpenMW)
|
||||
|
||||
#install(FILES ${MISC_FILES} DESTINATION ../MacOS)
|
||||
#install(DIRECTORY "${APP_BUNDLE_DIR}/Contents/Plugins" DESTINATION ..)
|
||||
#install(DIRECTORY "${APP_BUNDLE_DIR}/Contents/Resources/resources" DESTINATION ../Resources)
|
||||
install(DIRECTORY "${APP_BUNDLE_DIR}" USE_SOURCE_PERMISSIONS DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
install(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
|
||||
install(FILES "${OpenMW_BINARY_DIR}/plugins.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
install(FILES "${OpenMW_BINARY_DIR}/launcher.qss" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
|
||||
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
# set(CPACK_BUNDLE_PLIST "${CMAKE_SOURCE_DIR}/files/mac/Info.plist")
|
||||
# set(CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/files/mac/openmw.icns")
|
||||
# set(CPACK_BUNDLE_NAME "OpenMW")
|
||||
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${OPENMW_VERSION_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${OPENMW_VERSION_MINO})
|
||||
|
@ -442,11 +445,13 @@ if (APPLE)
|
|||
set(PLUGINS "")
|
||||
|
||||
# Scan Plugins dir for *.dylibs
|
||||
file(GLOB ALL_PLUGINS "${APP_BUNDLE_DIR}/Contents/Plugins/*.dylib")
|
||||
set(PLUGIN_SEARCH_ROOT "${APP_BUNDLE_DIR}/Contents/Plugins")
|
||||
file(GLOB_RECURSE ALL_PLUGINS "${PLUGIN_SEARCH_ROOT}/*.dylib")
|
||||
|
||||
set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins")
|
||||
foreach(PLUGIN ${ALL_PLUGINS})
|
||||
get_filename_component(PLUGIN_FILENAME ${PLUGIN} NAME)
|
||||
set(PLUGINS ${PLUGINS} "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}/Contents/Plugins/${PLUGIN_FILENAME}")
|
||||
string(REPLACE "${PLUGIN_SEARCH_ROOT}/" "" PLUGIN_RELATIVE "${PLUGIN}")
|
||||
set(PLUGINS ${PLUGINS} "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}")
|
||||
endforeach()
|
||||
|
||||
#For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail
|
||||
|
@ -456,7 +461,7 @@ if (APPLE)
|
|||
# some library already has be "fixed up", i.e. its id name contains @executable_path,
|
||||
# but library is not embedded in bundle. For example, it's Ogre.framework from Ogre SDK.
|
||||
# Current implementation of GetPrerequsities/BundleUtilities doesn't handle that case.
|
||||
#
|
||||
#
|
||||
# Current limitations:
|
||||
# 1. Handles only frameworks, not simple libs
|
||||
INSTALL(CODE "
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
set(ESMTOOL
|
||||
esmtool_cmd.c
|
||||
esmtool_cmd.h
|
||||
esmtool.cpp
|
||||
)
|
||||
source_group(apps\\esmtool FILES ${ESMTOOL})
|
||||
|
|
|
@ -1,35 +1,138 @@
|
|||
#include <iostream>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <components/esm/esm_reader.hpp>
|
||||
#include <components/esm/records.hpp>
|
||||
|
||||
#include "esmtool_cmd.h"
|
||||
|
||||
#include <iostream>
|
||||
#define ESMTOOL_VERSION 1.1
|
||||
|
||||
using namespace std;
|
||||
using namespace ESM;
|
||||
|
||||
// Create a local alias for brevity
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
void printRaw(ESMReader &esm);
|
||||
void loadCell(Cell &cell, ESMReader &esm, bool quiet);
|
||||
|
||||
int main(int argc, char**argv)
|
||||
// Based on the legacy struct
|
||||
struct Arguments
|
||||
{
|
||||
gengetopt_args_info info;
|
||||
unsigned int raw_given;
|
||||
unsigned int quiet_given;
|
||||
unsigned int loadcells_given;
|
||||
std::string encoding;
|
||||
std::string filename;
|
||||
};
|
||||
|
||||
if(cmdline_parser(argc, argv, &info) != 0)
|
||||
return 1;
|
||||
bool parseOptions (int argc, char** argv, Arguments &info)
|
||||
{
|
||||
bpo::options_description desc("Inspect and extract from Morrowind ES files (ESM, ESP, ESS)\nSyntax: esmtool [options] file \nAllowed options");
|
||||
|
||||
if(info.inputs_num != 1)
|
||||
desc.add_options()
|
||||
("help,h", "print help message.")
|
||||
("version,v", "print version information and quit.")
|
||||
("raw,r", "Show an unformattet list of all records and subrecords.")
|
||||
("quiet,q", "Supress all record information. Useful for speed tests.")
|
||||
("loadcells,C", "Browse through contents of all cells.")
|
||||
|
||||
( "encoding,e", bpo::value<std::string>(&(info.encoding))->
|
||||
default_value("win1252"),
|
||||
"Character encoding used in ESMTool:\n"
|
||||
"\n\twin1250 - Central and Eastern European such as Polish, Czech, Slovak, Hungarian, Slovene, Bosnian, Croatian, Serbian (Latin script), Romanian and Albanian languages\n"
|
||||
"\n\twin1251 - Cyrillic alphabet such as Russian, Bulgarian, Serbian Cyrillic and other languages\n"
|
||||
"\n\twin1252 - Western European (Latin) alphabet, used by default")
|
||||
;
|
||||
|
||||
std::string finalText = "\nIf no option is given, the default action is to parse all records in the archive\nand display diagnostic information.";
|
||||
|
||||
// input-file is hidden and used as a positional argument
|
||||
bpo::options_description hidden("Hidden Options");
|
||||
|
||||
hidden.add_options()
|
||||
( "input-file,i", bpo::value< vector<std::string> >(), "input file")
|
||||
;
|
||||
|
||||
bpo::positional_options_description p;
|
||||
p.add("input-file", -1);
|
||||
|
||||
// there might be a better way to do this
|
||||
bpo::options_description all;
|
||||
all.add(desc).add(hidden);
|
||||
bpo::parsed_options valid_opts = bpo::command_line_parser(argc, argv)
|
||||
.options(all).positional(p).run();
|
||||
|
||||
bpo::variables_map variables;
|
||||
bpo::store(valid_opts, variables);
|
||||
bpo::notify(variables);
|
||||
|
||||
if (variables.count ("help"))
|
||||
{
|
||||
if(info.inputs_num == 0)
|
||||
cout << "ERROR: missing ES file\n\n";
|
||||
else
|
||||
cout << "ERROR: more than one ES file specified\n\n";
|
||||
cmdline_parser_print_help();
|
||||
return 1;
|
||||
std::cout << desc << finalText << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (variables.count ("version"))
|
||||
{
|
||||
std::cout << "ESMTool version " << ESMTOOL_VERSION << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( !variables.count("input-file") )
|
||||
{
|
||||
std::cout << "\nERROR: missing ES file\n\n";
|
||||
std::cout << desc << finalText << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// handling gracefully the user adding multiple files
|
||||
if (variables["input-file"].as< vector<std::string> >().size() > 1)
|
||||
{
|
||||
std::cout << "\nERROR: more than one ES file specified\n\n";
|
||||
std::cout << desc << finalText << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
info.filename = variables["input-file"].as< vector<std::string> >()[0];
|
||||
|
||||
info.raw_given = variables.count ("raw");
|
||||
info.quiet_given = variables.count ("quiet");
|
||||
info.loadcells_given = variables.count ("loadcells");
|
||||
|
||||
// Font encoding settings
|
||||
info.encoding = variables["encoding"].as<std::string>();
|
||||
if (info.encoding == "win1250")
|
||||
{
|
||||
std::cout << "Using Central and Eastern European font encoding." << std::endl;
|
||||
}
|
||||
else if (info.encoding == "win1251")
|
||||
{
|
||||
std::cout << "Using Cyrillic font encoding." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(info.encoding != "win1252")
|
||||
{
|
||||
std::cout << info.encoding << " is not a valid encoding option." << std::endl;
|
||||
info.encoding = "win1252";
|
||||
}
|
||||
std::cout << "Using default (English) font encoding." << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char**argv)
|
||||
{
|
||||
Arguments info;
|
||||
if(!parseOptions (argc, argv, info))
|
||||
return 1;
|
||||
|
||||
ESMReader esm;
|
||||
const char* filename = info.inputs[0];
|
||||
esm.setEncoding(info.encoding);
|
||||
|
||||
string filename = info.filename;
|
||||
cout << "\nFile: " << filename << endl;
|
||||
|
||||
try {
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
package "esmtool"
|
||||
version "1.0"
|
||||
purpose "Inspect and extract from Morrowind ES files (ESM, ESP, ESS)"
|
||||
args "--unamed-opts=ES-FILE -F esmtool_cmd -G"
|
||||
|
||||
option "raw" r "Show an unformattet list of all records and subrecords" optional
|
||||
option "quiet" q "Supress all record information. Useful for speed tests." optional
|
||||
option "loadcells" C "Browse through contents of all cells." optional
|
||||
|
||||
text "\nIf no option is given, the default action is to parse all records in the archive and display diagnostic information."
|
File diff suppressed because it is too large
Load diff
|
@ -1,179 +0,0 @@
|
|||
/** @file esmtool_cmd.h
|
||||
* @brief The header file for the command line option parser
|
||||
* generated by GNU Gengetopt version 2.22.2
|
||||
* http://www.gnu.org/software/gengetopt.
|
||||
* DO NOT modify this file, since it can be overwritten
|
||||
* @author GNU Gengetopt by Lorenzo Bettini */
|
||||
|
||||
#ifndef ESMTOOL_CMD_H
|
||||
#define ESMTOOL_CMD_H
|
||||
|
||||
/* If we use autoconf. */
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h> /* for FILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifndef CMDLINE_PARSER_PACKAGE
|
||||
/** @brief the program name (used for printing errors) */
|
||||
#define CMDLINE_PARSER_PACKAGE "esmtool"
|
||||
#endif
|
||||
|
||||
#ifndef CMDLINE_PARSER_PACKAGE_NAME
|
||||
/** @brief the complete program name (used for help and version) */
|
||||
#define CMDLINE_PARSER_PACKAGE_NAME "esmtool"
|
||||
#endif
|
||||
|
||||
#ifndef CMDLINE_PARSER_VERSION
|
||||
/** @brief the program version */
|
||||
#define CMDLINE_PARSER_VERSION "1.0"
|
||||
#endif
|
||||
|
||||
/** @brief Where the command line options are stored */
|
||||
struct gengetopt_args_info
|
||||
{
|
||||
const char *help_help; /**< @brief Print help and exit help description. */
|
||||
const char *version_help; /**< @brief Print version and exit help description. */
|
||||
const char *raw_help; /**< @brief Show an unformattet list of all records and subrecords help description. */
|
||||
const char *quiet_help; /**< @brief Supress all record information. Useful for speed tests. help description. */
|
||||
const char *loadcells_help; /**< @brief Browse through contents of all cells. help description. */
|
||||
|
||||
unsigned int help_given ; /**< @brief Whether help was given. */
|
||||
unsigned int version_given ; /**< @brief Whether version was given. */
|
||||
unsigned int raw_given ; /**< @brief Whether raw was given. */
|
||||
unsigned int quiet_given ; /**< @brief Whether quiet was given. */
|
||||
unsigned int loadcells_given ; /**< @brief Whether loadcells was given. */
|
||||
|
||||
char **inputs ; /**< @brief unamed options (options without names) */
|
||||
unsigned inputs_num ; /**< @brief unamed options number */
|
||||
} ;
|
||||
|
||||
/** @brief The additional parameters to pass to parser functions */
|
||||
struct cmdline_parser_params
|
||||
{
|
||||
int override; /**< @brief whether to override possibly already present options (default 0) */
|
||||
int initialize; /**< @brief whether to initialize the option structure gengetopt_args_info (default 1) */
|
||||
int check_required; /**< @brief whether to check that all required options were provided (default 1) */
|
||||
int check_ambiguity; /**< @brief whether to check for options already specified in the option structure gengetopt_args_info (default 0) */
|
||||
int print_errors; /**< @brief whether getopt_long should print an error message for a bad option (default 1) */
|
||||
} ;
|
||||
|
||||
/** @brief the purpose string of the program */
|
||||
extern const char *gengetopt_args_info_purpose;
|
||||
/** @brief the usage string of the program */
|
||||
extern const char *gengetopt_args_info_usage;
|
||||
/** @brief all the lines making the help output */
|
||||
extern const char *gengetopt_args_info_help[];
|
||||
|
||||
/**
|
||||
* The command line parser
|
||||
* @param argc the number of command line options
|
||||
* @param argv the command line options
|
||||
* @param args_info the structure where option information will be stored
|
||||
* @return 0 if everything went fine, NON 0 if an error took place
|
||||
*/
|
||||
int cmdline_parser (int argc, char * const *argv,
|
||||
struct gengetopt_args_info *args_info);
|
||||
|
||||
/**
|
||||
* The command line parser (version with additional parameters - deprecated)
|
||||
* @param argc the number of command line options
|
||||
* @param argv the command line options
|
||||
* @param args_info the structure where option information will be stored
|
||||
* @param override whether to override possibly already present options
|
||||
* @param initialize whether to initialize the option structure my_args_info
|
||||
* @param check_required whether to check that all required options were provided
|
||||
* @return 0 if everything went fine, NON 0 if an error took place
|
||||
* @deprecated use cmdline_parser_ext() instead
|
||||
*/
|
||||
int cmdline_parser2 (int argc, char * const *argv,
|
||||
struct gengetopt_args_info *args_info,
|
||||
int override, int initialize, int check_required);
|
||||
|
||||
/**
|
||||
* The command line parser (version with additional parameters)
|
||||
* @param argc the number of command line options
|
||||
* @param argv the command line options
|
||||
* @param args_info the structure where option information will be stored
|
||||
* @param params additional parameters for the parser
|
||||
* @return 0 if everything went fine, NON 0 if an error took place
|
||||
*/
|
||||
int cmdline_parser_ext (int argc, char * const *argv,
|
||||
struct gengetopt_args_info *args_info,
|
||||
struct cmdline_parser_params *params);
|
||||
|
||||
/**
|
||||
* Save the contents of the option struct into an already open FILE stream.
|
||||
* @param outfile the stream where to dump options
|
||||
* @param args_info the option struct to dump
|
||||
* @return 0 if everything went fine, NON 0 if an error took place
|
||||
*/
|
||||
int cmdline_parser_dump(FILE *outfile,
|
||||
struct gengetopt_args_info *args_info);
|
||||
|
||||
/**
|
||||
* Save the contents of the option struct into a (text) file.
|
||||
* This file can be read by the config file parser (if generated by gengetopt)
|
||||
* @param filename the file where to save
|
||||
* @param args_info the option struct to save
|
||||
* @return 0 if everything went fine, NON 0 if an error took place
|
||||
*/
|
||||
int cmdline_parser_file_save(const char *filename,
|
||||
struct gengetopt_args_info *args_info);
|
||||
|
||||
/**
|
||||
* Print the help
|
||||
*/
|
||||
void cmdline_parser_print_help(void);
|
||||
/**
|
||||
* Print the version
|
||||
*/
|
||||
void cmdline_parser_print_version(void);
|
||||
|
||||
/**
|
||||
* Initializes all the fields a cmdline_parser_params structure
|
||||
* to their default values
|
||||
* @param params the structure to initialize
|
||||
*/
|
||||
void cmdline_parser_params_init(struct cmdline_parser_params *params);
|
||||
|
||||
/**
|
||||
* Allocates dynamically a cmdline_parser_params structure and initializes
|
||||
* all its fields to their default values
|
||||
* @return the created and initialized cmdline_parser_params structure
|
||||
*/
|
||||
struct cmdline_parser_params *cmdline_parser_params_create(void);
|
||||
|
||||
/**
|
||||
* Initializes the passed gengetopt_args_info structure's fields
|
||||
* (also set default values for options that have a default)
|
||||
* @param args_info the structure to initialize
|
||||
*/
|
||||
void cmdline_parser_init (struct gengetopt_args_info *args_info);
|
||||
/**
|
||||
* Deallocates the string fields of the gengetopt_args_info structure
|
||||
* (but does not deallocate the structure itself)
|
||||
* @param args_info the structure to deallocate
|
||||
*/
|
||||
void cmdline_parser_free (struct gengetopt_args_info *args_info);
|
||||
|
||||
/**
|
||||
* Checks that all the required options were specified
|
||||
* @param args_info the structure to check
|
||||
* @param prog_name the name of the program that will be used to print
|
||||
* possible errors
|
||||
* @return
|
||||
*/
|
||||
int cmdline_parser_required (struct gengetopt_args_info *args_info,
|
||||
const char *prog_name);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* ESMTOOL_CMD_H */
|
|
@ -41,25 +41,16 @@ source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER} ${LAUNCHER_HEADER_MOC
|
|||
find_package(Qt4 REQUIRED)
|
||||
set(QT_USE_QTGUI 1)
|
||||
|
||||
#find_package(PNG REQUIRED)
|
||||
#include_directories(${PNG_INCLUDE_DIR})
|
||||
if (NOT APPLE) # this dependency can be completely removed, but now it only tested on OS X
|
||||
find_package(PNG REQUIRED)
|
||||
include_directories(${PNG_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
QT4_ADD_RESOURCES(RCC_SRCS resources.qrc)
|
||||
QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC})
|
||||
|
||||
include(${QT_USE_FILE})
|
||||
|
||||
# list here plugins that can't be detected statically, but loaded in runtime
|
||||
# it needed for packaging automatisation
|
||||
#set(USED_QT_PLUGINS imageformats/libqgif
|
||||
# imageformats/libqico
|
||||
# imageformats/libqjpeg
|
||||
# imageformats/libqmng
|
||||
# imageformats/libqsvg
|
||||
# imageformats/libqtga
|
||||
# imageformats/libqtiff)
|
||||
# It seems that launcher works without this plugins, but it loads them into memory if they exists
|
||||
|
||||
# Main executable
|
||||
add_executable(omwlauncher
|
||||
${LAUNCHER}
|
||||
|
@ -71,7 +62,7 @@ target_link_libraries(omwlauncher
|
|||
${Boost_LIBRARIES}
|
||||
${OGRE_LIBRARIES}
|
||||
${QT_LIBRARIES}
|
||||
# ${PNG_LIBRARY}
|
||||
${PNG_LIBRARY}
|
||||
components
|
||||
)
|
||||
|
||||
|
@ -82,19 +73,16 @@ endif()
|
|||
if (APPLE)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
|
||||
"${APP_BUNDLE_DIR}/../launcher.qss")
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg
|
||||
"${APP_BUNDLE_DIR}/../launcher.cfg")
|
||||
|
||||
# copy used QT plugins into ${APP_BUNDLE_DIR}/Contents/Plugins
|
||||
#foreach(PLUGIN ${USED_QT_PLUGINS})
|
||||
# get_filename_component(PLUGIN_FILENAME ${PLUGIN} NAME)
|
||||
# configure_file("${QT_PLUGINS_DIR}/${PLUGIN}.dylib" "${APP_BUNDLE_DIR}/Contents/Plugins/${PLUGIN_FILENAME}.dylib" COPYONLY)
|
||||
#endforeach()
|
||||
|
||||
else()
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/resources/launcher.qss")
|
||||
|
||||
# Fallback in case getGlobalDataPath does not point to resources
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.qss
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.qss")
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/files/launcher.cfg
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/launcher.cfg")
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}launcher.cfg")
|
||||
endif()
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
#include <QtGui>
|
||||
|
||||
#include <components/esm/esm_reader.hpp>
|
||||
#include <components/files/collections.hpp>
|
||||
#include <components/files/multidircollection.hpp>
|
||||
#include <components/cfg/configurationmanager.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
#include "datafilespage.hpp"
|
||||
#include "lineedit.hpp"
|
||||
|
@ -26,7 +24,9 @@ bool rowSmallerThan(const QModelIndex &index1, const QModelIndex &index2)
|
|||
return index1.row() <= index2.row();
|
||||
}
|
||||
|
||||
DataFilesPage::DataFilesPage(QWidget *parent) : QWidget(parent)
|
||||
DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, mCfgMgr(cfg)
|
||||
{
|
||||
mDataFilesModel = new QStandardItemModel(); // Contains all plugins with masters
|
||||
mPluginsModel = new PluginsModel(); // Contains selectable plugins
|
||||
|
@ -118,37 +118,139 @@ DataFilesPage::DataFilesPage(QWidget *parent) : QWidget(parent)
|
|||
connect(mPluginsTable, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(setCheckState(QModelIndex)));
|
||||
connect(mPluginsTable, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(showContextMenu(const QPoint&)));
|
||||
|
||||
connect(mProfilesComboBox, SIGNAL(textChanged(const QString&, const QString&)), this, SLOT(profileChanged(const QString&, const QString&)));
|
||||
|
||||
|
||||
setupConfig();
|
||||
createActions();
|
||||
setupConfig();
|
||||
setupDataFiles();
|
||||
|
||||
}
|
||||
|
||||
void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict)
|
||||
void DataFilesPage::setupConfig()
|
||||
{
|
||||
// Put the paths in a boost::filesystem vector to use with Files::Collections
|
||||
Files::PathContainer dataDirs;
|
||||
QString config = QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.cfg").string());
|
||||
QFile file(config);
|
||||
|
||||
foreach (const QString ¤tPath, paths) {
|
||||
dataDirs.push_back(boost::filesystem::path(currentPath.toStdString()));
|
||||
if (!file.exists()) {
|
||||
config = QString::fromStdString((mCfgMgr.getUserPath() / "launcher.cfg").string());
|
||||
}
|
||||
|
||||
// Open our config file
|
||||
mLauncherConfig = new QSettings(config, QSettings::IniFormat);
|
||||
file.close();
|
||||
|
||||
// Make sure we have no groups open
|
||||
while (!mLauncherConfig->group().isEmpty()) {
|
||||
mLauncherConfig->endGroup();
|
||||
}
|
||||
|
||||
mLauncherConfig->beginGroup("Profiles");
|
||||
QStringList profiles = mLauncherConfig->childGroups();
|
||||
|
||||
if (profiles.isEmpty()) {
|
||||
// Add a default profile
|
||||
profiles.append("Default");
|
||||
}
|
||||
|
||||
mProfilesComboBox->addItems(profiles);
|
||||
|
||||
QString currentProfile = mLauncherConfig->value("CurrentProfile").toString();
|
||||
|
||||
if (currentProfile.isEmpty()) {
|
||||
// No current profile selected
|
||||
currentProfile = "Default";
|
||||
}
|
||||
|
||||
const int currentIndex = mProfilesComboBox->findText(currentProfile);
|
||||
if (currentIndex != -1) {
|
||||
// Profile is found
|
||||
mProfilesComboBox->setCurrentIndex(currentIndex);
|
||||
}
|
||||
|
||||
mLauncherConfig->endGroup();
|
||||
}
|
||||
|
||||
|
||||
void DataFilesPage::setupDataFiles()
|
||||
{
|
||||
// We use the Configuration Manager to retrieve the configuration values
|
||||
boost::program_options::variables_map variables;
|
||||
boost::program_options::options_description desc;
|
||||
|
||||
desc.add_options()
|
||||
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
|
||||
// ("data-local", boost::program_options::value<std::string>()->default_value(""))
|
||||
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
|
||||
("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
|
||||
|
||||
mCfgMgr.readConfiguration(variables, desc);
|
||||
|
||||
// Put the paths in a boost::filesystem vector to use with Files::Collections
|
||||
Files::PathContainer dataDirs(variables["data"].as<Files::PathContainer>());
|
||||
mDataDirs = dataDirs;
|
||||
|
||||
// std::string local = variables["data-local"].as<std::string>();
|
||||
// if (!local.empty()) {
|
||||
// mDataLocal.push_back(Files::PathContainer::value_type(local));
|
||||
// dataDirs.push_back(Files::PathContainer::value_type(local));
|
||||
// }
|
||||
|
||||
if (dataDirs.size()>1)
|
||||
dataDirs.resize (1);
|
||||
|
||||
mCfgMgr.processPaths(dataDirs);
|
||||
|
||||
while (dataDirs.empty()) {
|
||||
// No valid data files directory found
|
||||
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error detecting Morrowind installation");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Cancel);
|
||||
msgBox.setText(tr("<br><b>Could not find the Data Files location</b><br><br> \
|
||||
The directory containing the Data Files was not found.<br><br> \
|
||||
Press \"Browse...\" to specify the location manually.<br>"));
|
||||
|
||||
QAbstractButton *dirSelectButton =
|
||||
msgBox.addButton(tr("B&rowse..."), QMessageBox::ActionRole);
|
||||
|
||||
msgBox.exec();
|
||||
|
||||
if (msgBox.clickedButton() == dirSelectButton) {
|
||||
|
||||
QString dataDir = QFileDialog::getExistingDirectory(
|
||||
this, tr("Select Data Files Directory"),
|
||||
"/home",
|
||||
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
|
||||
|
||||
dataDirs.push_back(Files::PathContainer::value_type(dataDir.toStdString()));
|
||||
mDataDirs.push_back(Files::PathContainer::value_type(dataDir.toStdString()));
|
||||
} else {
|
||||
// Cancel
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if cancel was clicked because we can't exit from while loop
|
||||
if (dataDirs.empty()) {
|
||||
QApplication::exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a file collection for the dataDirs
|
||||
Files::Collections mFileCollections(dataDirs, strict);
|
||||
Files::Collections fileCollections(dataDirs, !variables["fs-strict"].as<bool>());
|
||||
|
||||
// First we add all the master files
|
||||
const Files::MultiDirCollection &esm = mFileCollections.getCollection(".esm");
|
||||
const Files::MultiDirCollection &esm = fileCollections.getCollection(".esm");
|
||||
unsigned int i = 0; // Row number
|
||||
|
||||
for (Files::MultiDirCollection::TIter iter(esm.begin()); iter!=esm.end(); ++iter)
|
||||
{
|
||||
for (Files::MultiDirCollection::TIter iter(esm.begin()); iter!=esm.end(); ++iter) {
|
||||
QString currentMaster = QString::fromStdString(
|
||||
boost::filesystem::path (iter->second.filename()).string());
|
||||
|
||||
const QList<QTableWidgetItem*> itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly);
|
||||
|
||||
if (itemList.isEmpty()) // Master is not yet in the widget
|
||||
{
|
||||
if (itemList.isEmpty()) { // Master is not yet in the widget
|
||||
mMastersWidget->insertRow(i);
|
||||
QTableWidgetItem *item = new QTableWidgetItem(currentMaster);
|
||||
mMastersWidget->setItem(i, 0, item);
|
||||
|
@ -157,14 +259,13 @@ void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict)
|
|||
}
|
||||
|
||||
// Now on to the plugins
|
||||
const Files::MultiDirCollection &esp = mFileCollections.getCollection(".esp");
|
||||
const Files::MultiDirCollection &esp = fileCollections.getCollection(".esp");
|
||||
|
||||
for (Files::MultiDirCollection::TIter iter(esp.begin()); iter!=esp.end(); ++iter)
|
||||
{
|
||||
for (Files::MultiDirCollection::TIter iter(esp.begin()); iter!=esp.end(); ++iter) {
|
||||
ESMReader fileReader;
|
||||
QStringList availableMasters; // Will contain all found masters
|
||||
|
||||
fileReader.setEncoding("win1252"); // FIXME: This should be configurable!
|
||||
fileReader.setEncoding(variables["encoding"].as<std::string>());
|
||||
fileReader.open(iter->second.string());
|
||||
|
||||
// First we fill the availableMasters and the mMastersWidget
|
||||
|
@ -176,8 +277,7 @@ void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict)
|
|||
|
||||
const QList<QTableWidgetItem*> itemList = mMastersWidget->findItems(currentMaster, Qt::MatchExactly);
|
||||
|
||||
if (itemList.isEmpty()) // Master is not yet in the widget
|
||||
{
|
||||
if (itemList.isEmpty()) { // Master is not yet in the widget
|
||||
mMastersWidget->insertRow(i);
|
||||
|
||||
QTableWidgetItem *item = new QTableWidgetItem(currentMaster);
|
||||
|
@ -234,54 +334,6 @@ void DataFilesPage::setupDataFiles(const QStringList &paths, bool strict)
|
|||
readConfig();
|
||||
}
|
||||
|
||||
void DataFilesPage::setupConfig()
|
||||
{
|
||||
Cfg::ConfigurationManager cfg;
|
||||
|
||||
QString config = (cfg.getRuntimeConfigPath() / "launcher.cfg").string().c_str();
|
||||
QFile file(config);
|
||||
|
||||
if (!file.exists()) {
|
||||
config = QString::fromStdString((cfg.getLocalConfigPath() / "launcher.cfg").string());
|
||||
}
|
||||
|
||||
file.setFileName(config); // Just for displaying information
|
||||
|
||||
// Open our config file
|
||||
mLauncherConfig = new QSettings(config, QSettings::IniFormat);
|
||||
mLauncherConfig->sync();
|
||||
|
||||
|
||||
// Make sure we have no groups open
|
||||
while (!mLauncherConfig->group().isEmpty()) {
|
||||
mLauncherConfig->endGroup();
|
||||
}
|
||||
|
||||
mLauncherConfig->beginGroup("Profiles");
|
||||
QStringList profiles = mLauncherConfig->childGroups();
|
||||
|
||||
if (profiles.isEmpty()) {
|
||||
// Add a default profile
|
||||
profiles.append("Default");
|
||||
}
|
||||
|
||||
mProfilesComboBox->addItems(profiles);
|
||||
|
||||
QString currentProfile = mLauncherConfig->value("CurrentProfile").toString();
|
||||
|
||||
if (currentProfile.isEmpty()) {
|
||||
// No current profile selected
|
||||
currentProfile = "Default";
|
||||
}
|
||||
mProfilesComboBox->setCurrentIndex(mProfilesComboBox->findText(currentProfile));
|
||||
|
||||
mLauncherConfig->endGroup();
|
||||
|
||||
// Now we connect the combobox to do something if the profile changes
|
||||
// This prevents strange behaviour while reading and appending the profiles
|
||||
connect(mProfilesComboBox, SIGNAL(textChanged(const QString&, const QString&)), this, SLOT(profileChanged(const QString&, const QString&)));
|
||||
}
|
||||
|
||||
void DataFilesPage::createActions()
|
||||
{
|
||||
// Refresh the plugins
|
||||
|
@ -414,18 +466,18 @@ void DataFilesPage::deleteProfile()
|
|||
return;
|
||||
}
|
||||
|
||||
QMessageBox deleteMessageBox(this);
|
||||
deleteMessageBox.setWindowTitle(tr("Delete Profile"));
|
||||
deleteMessageBox.setText(tr("Are you sure you want to delete <b>%0</b>?").arg(profile));
|
||||
deleteMessageBox.setIcon(QMessageBox::Warning);
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setWindowTitle(tr("Delete Profile"));
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.setStandardButtons(QMessageBox::Cancel);
|
||||
msgBox.setText(tr("Are you sure you want to delete <b>%0</b>?").arg(profile));
|
||||
|
||||
QAbstractButton *deleteButton =
|
||||
deleteMessageBox.addButton(tr("Delete"), QMessageBox::ActionRole);
|
||||
msgBox.addButton(tr("Delete"), QMessageBox::ActionRole);
|
||||
|
||||
deleteMessageBox.addButton(QMessageBox::Cancel);
|
||||
msgBox.exec();
|
||||
|
||||
deleteMessageBox.exec();
|
||||
|
||||
if (deleteMessageBox.clickedButton() == deleteButton) {
|
||||
if (msgBox.clickedButton() == deleteButton) {
|
||||
// Make sure we have no groups open
|
||||
while (!mLauncherConfig->group().isEmpty()) {
|
||||
mLauncherConfig->endGroup();
|
||||
|
@ -482,7 +534,6 @@ void DataFilesPage::moveUp()
|
|||
void DataFilesPage::moveDown()
|
||||
{
|
||||
// Shift the selected plugins down one row
|
||||
|
||||
if (!mPluginsTable->selectionModel()->hasSelection()) {
|
||||
return;
|
||||
}
|
||||
|
@ -898,9 +949,18 @@ void DataFilesPage::filterChanged(const QString filter)
|
|||
|
||||
void DataFilesPage::profileChanged(const QString &previous, const QString ¤t)
|
||||
{
|
||||
// Prevent the deletion of the default profile
|
||||
if (current == "Default") {
|
||||
mDeleteProfileAction->setEnabled(false);
|
||||
} else {
|
||||
mDeleteProfileAction->setEnabled(true);
|
||||
}
|
||||
|
||||
if (!previous.isEmpty()) {
|
||||
writeConfig(previous);
|
||||
mLauncherConfig->sync();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
uncheckPlugins();
|
||||
|
@ -968,11 +1028,105 @@ void DataFilesPage::readConfig()
|
|||
|
||||
void DataFilesPage::writeConfig(QString profile)
|
||||
{
|
||||
// Don't overwrite the config if no plugins are found
|
||||
if (mPluginsModel->rowCount() < 1) {
|
||||
// Don't overwrite the config if no masters are found
|
||||
if (mMastersWidget->rowCount() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare the OpenMW config
|
||||
QString config = QString::fromStdString((mCfgMgr.getLocalPath() / "openmw.cfg").string());
|
||||
QFile file(config);
|
||||
|
||||
if (!file.exists()) {
|
||||
config = QString::fromStdString((mCfgMgr.getUserPath() / "openmw.cfg").string());
|
||||
}
|
||||
|
||||
// Open the config as a QFile
|
||||
file.setFileName(config);
|
||||
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
||||
// File cannot be opened or created
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error writing OpenMW configuration file");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>Could not open or create %0</b><br><br> \
|
||||
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream in(&file);
|
||||
QByteArray buffer;
|
||||
|
||||
// Remove all previous entries from config
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
if (!line.startsWith("master") &&
|
||||
!line.startsWith("plugin") &&
|
||||
!line.startsWith("data") &&
|
||||
!line.startsWith("data-local"))
|
||||
{
|
||||
buffer += line += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
// Now we write back the other config entries
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error writing OpenMW configuration file");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>Could not write to %0</b><br><br> \
|
||||
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!buffer.isEmpty()) {
|
||||
file.write(buffer);
|
||||
}
|
||||
|
||||
QTextStream gameConfig(&file);
|
||||
|
||||
// First write the list of data dirs
|
||||
mCfgMgr.processPaths(mDataDirs);
|
||||
mCfgMgr.processPaths(mDataLocal);
|
||||
|
||||
QString path;
|
||||
|
||||
// data= directories
|
||||
for (Files::PathContainer::iterator it = mDataDirs.begin(); it != mDataDirs.end(); ++it) {
|
||||
path = QString::fromStdString(it->string());
|
||||
path.remove(QChar('\"'));
|
||||
|
||||
// Make sure the string is quoted when it contains spaces
|
||||
if (path.contains(" ")) {
|
||||
gameConfig << "data=\"" << path << "\"" << endl;
|
||||
} else {
|
||||
gameConfig << "data=" << path << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// data-local directory
|
||||
if (!mDataLocal.empty()) {
|
||||
path = QString::fromStdString(mDataLocal.front().string());
|
||||
path.remove(QChar('\"'));
|
||||
|
||||
if (path.contains(" ")) {
|
||||
gameConfig << "data-local=\"" << path << "\"" << endl;
|
||||
} else {
|
||||
gameConfig << "data-local=" << path << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (profile.isEmpty()) {
|
||||
profile = mProfilesComboBox->currentText();
|
||||
}
|
||||
|
@ -993,24 +1147,29 @@ void DataFilesPage::writeConfig(QString profile)
|
|||
mLauncherConfig->beginGroup(profile);
|
||||
mLauncherConfig->remove(""); // Clear the subgroup
|
||||
|
||||
// First write the masters to the config
|
||||
const QStringList masterList = selectedMasters();
|
||||
// Now write the masters to the configs
|
||||
const QStringList masters = selectedMasters();
|
||||
|
||||
// We don't use foreach because we need i
|
||||
for (int i = 0; i < masterList.size(); ++i) {
|
||||
const QString master = masterList.at(i);
|
||||
mLauncherConfig->setValue(QString("Master%0").arg(i), master);
|
||||
for (int i = 0; i < masters.size(); ++i) {
|
||||
const QString currentMaster = masters.at(i);
|
||||
|
||||
mLauncherConfig->setValue(QString("Master%0").arg(i), currentMaster);
|
||||
gameConfig << "master=" << currentMaster << endl;
|
||||
|
||||
}
|
||||
|
||||
// Now write all checked plugins
|
||||
// And finally write all checked plugins
|
||||
const QStringList plugins = checkedPlugins();
|
||||
|
||||
for (int i = 0; i < plugins.size(); ++i)
|
||||
{
|
||||
mLauncherConfig->setValue(QString("Plugin%1").arg(i), plugins.at(i));
|
||||
for (int i = 0; i < plugins.size(); ++i) {
|
||||
const QString currentPlugin = plugins.at(i);
|
||||
mLauncherConfig->setValue(QString("Plugin%1").arg(i), currentPlugin);
|
||||
gameConfig << "plugin=" << currentPlugin << endl;
|
||||
}
|
||||
|
||||
file.close();
|
||||
mLauncherConfig->endGroup();
|
||||
mLauncherConfig->endGroup();
|
||||
|
||||
mLauncherConfig->sync();
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
|
||||
#include <QWidget>
|
||||
#include <QModelIndex>
|
||||
|
||||
#include <components/files/collections.hpp>
|
||||
|
||||
#include "combobox.hpp"
|
||||
|
||||
class QTableWidget;
|
||||
|
@ -19,24 +22,19 @@ class PluginsModel;
|
|||
class PluginsView;
|
||||
class ComboBox;
|
||||
|
||||
namespace Files { struct ConfigurationManager; }
|
||||
|
||||
class DataFilesPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DataFilesPage(QWidget *parent = 0);
|
||||
DataFilesPage(Files::ConfigurationManager& cfg, QWidget *parent = 0);
|
||||
|
||||
ComboBox *mProfilesComboBox;
|
||||
QSettings *mLauncherConfig;
|
||||
|
||||
const QStringList checkedPlugins();
|
||||
const QStringList selectedMasters();
|
||||
void setupConfig();
|
||||
void readConfig();
|
||||
void writeConfig(QString profile = QString());
|
||||
|
||||
void setupDataFiles(const QStringList &paths, bool strict);
|
||||
|
||||
public slots:
|
||||
void masterSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
|
||||
void setCheckState(QModelIndex index);
|
||||
|
@ -81,11 +79,22 @@ private:
|
|||
QAction *mCheckAction;
|
||||
QAction *mUncheckAction;
|
||||
|
||||
Files::ConfigurationManager &mCfgMgr;
|
||||
Files::PathContainer mDataDirs;
|
||||
Files::PathContainer mDataLocal;
|
||||
|
||||
QSettings *mLauncherConfig;
|
||||
|
||||
const QStringList checkedPlugins();
|
||||
const QStringList selectedMasters();
|
||||
|
||||
void addPlugins(const QModelIndex &index);
|
||||
void removePlugins(const QModelIndex &index);
|
||||
void uncheckPlugins();
|
||||
void createActions();
|
||||
|
||||
void setupDataFiles();
|
||||
void setupConfig();
|
||||
void readConfig();
|
||||
void scrollToSelection();
|
||||
|
||||
};
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#include <QtGui>
|
||||
|
||||
#include "graphicspage.hpp"
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
GraphicsPage::GraphicsPage(QWidget *parent) : QWidget(parent)
|
||||
GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, mCfgMgr(cfg)
|
||||
{
|
||||
QGroupBox *rendererGroup = new QGroupBox(tr("Renderer"), this);
|
||||
|
||||
|
@ -147,21 +150,21 @@ void GraphicsPage::createPages()
|
|||
|
||||
void GraphicsPage::setupConfig()
|
||||
{
|
||||
QString ogreCfg = mCfg.getOgreConfigPath().string().c_str();
|
||||
QString ogreCfg = mCfgMgr.getOgreConfigPath().string().c_str();
|
||||
QFile file(ogreCfg);
|
||||
mOgreConfig = new QSettings(ogreCfg, QSettings::IniFormat);
|
||||
}
|
||||
|
||||
void GraphicsPage::setupOgre()
|
||||
{
|
||||
QString pluginCfg = mCfg.getPluginsConfigPath().string().c_str();
|
||||
QString pluginCfg = mCfgMgr.getPluginsConfigPath().string().c_str();
|
||||
QFile file(pluginCfg);
|
||||
|
||||
// Create a log manager so we can surpress debug text to stdout/stderr
|
||||
Ogre::LogManager* logMgr = OGRE_NEW Ogre::LogManager;
|
||||
logMgr->createLog((mCfg.getLogPath().string() + "/launcherOgre.log"), true, false, false);
|
||||
logMgr->createLog((mCfgMgr.getLogPath().string() + "/launcherOgre.log"), true, false, false);
|
||||
|
||||
QString ogreCfg = QString::fromStdString(mCfg.getOgreConfigPath().string());
|
||||
QString ogreCfg = QString::fromStdString(mCfgMgr.getOgreConfigPath().string());
|
||||
file.setFileName(ogreCfg);
|
||||
|
||||
//we need to check that the path to the configuration file exists before we
|
||||
|
@ -177,7 +180,7 @@ void GraphicsPage::setupOgre()
|
|||
Make sure you have write access to<br>%1<br><br>")).arg(configDir.path()));
|
||||
msgBox.exec();
|
||||
|
||||
QApplication::exit(1);
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -200,7 +203,7 @@ void GraphicsPage::setupOgre()
|
|||
|
||||
qCritical("Error creating Ogre::Root, the error reported was:\n %s", qPrintable(ogreError));
|
||||
|
||||
QApplication::exit(1);
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -234,7 +237,7 @@ void GraphicsPage::setupOgre()
|
|||
Please make sure the plugins.cfg file exists and contains a valid rendering plugin.<br>"));
|
||||
msgBox.exec();
|
||||
|
||||
QApplication::exit(1);
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -243,13 +246,7 @@ void GraphicsPage::setupOgre()
|
|||
if (mOpenGLRenderSystem) {
|
||||
mOGLRTTComboBox->addItems(getAvailableOptions(QString("RTT Preferred Mode"), mOpenGLRenderSystem));
|
||||
mOGLAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mOpenGLRenderSystem));
|
||||
|
||||
QStringList videoModes = getAvailableOptions(QString("Video Mode"), mOpenGLRenderSystem);
|
||||
// Remove extraneous spaces
|
||||
videoModes.replaceInStrings(QRegExp("\\s{2,}"), QString(" "));
|
||||
videoModes.replaceInStrings(QRegExp("^\\s"), QString());
|
||||
|
||||
mOGLResolutionComboBox->addItems(videoModes);
|
||||
mOGLResolutionComboBox->addItems(getAvailableOptions(QString("Video Mode"), mOpenGLRenderSystem));
|
||||
mOGLFrequencyComboBox->addItems(getAvailableOptions(QString("Display Frequency"), mOpenGLRenderSystem));
|
||||
}
|
||||
|
||||
|
@ -258,12 +255,7 @@ void GraphicsPage::setupOgre()
|
|||
mD3DRenderDeviceComboBox->addItems(getAvailableOptions(QString("Rendering Device"), mDirect3DRenderSystem));
|
||||
mD3DAntiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mDirect3DRenderSystem));
|
||||
mD3DFloatingPointComboBox->addItems(getAvailableOptions(QString("Floating-point mode"), mDirect3DRenderSystem));
|
||||
|
||||
QStringList videoModes = getAvailableOptions(QString("Video Mode"), mDirect3DRenderSystem);
|
||||
// Remove extraneous spaces
|
||||
videoModes.replaceInStrings(QRegExp("\\s{2,}"), QString(" "));
|
||||
videoModes.replaceInStrings(QRegExp("^\\s"), QString());
|
||||
mD3DResolutionComboBox->addItems(videoModes);
|
||||
mD3DResolutionComboBox->addItems(getAvailableOptions(QString("Video Mode"), mDirect3DRenderSystem));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,7 +412,7 @@ void GraphicsPage::writeConfig()
|
|||
|
||||
qCritical("Error validating configuration");
|
||||
|
||||
QApplication::exit(1);
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -446,7 +438,8 @@ void GraphicsPage::writeConfig()
|
|||
|
||||
qCritical("Error saving Ogre configuration, the error reported was:\n %s", qPrintable(ogreError));
|
||||
|
||||
QApplication::exit(1);
|
||||
qApp->exit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -478,7 +471,7 @@ QStringList GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSy
|
|||
{
|
||||
|
||||
if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0)
|
||||
result << (*opt_it).c_str();
|
||||
result << QString::fromStdString((*opt_it).c_str()).simplified();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,21 +7,20 @@
|
|||
#include <OgreRenderSystem.h>
|
||||
#include <OgreConfigFile.h>
|
||||
#include <OgreConfigDialog.h>
|
||||
#include <components/cfg/configurationmanager.hpp>
|
||||
|
||||
class QComboBox;
|
||||
class QCheckBox;
|
||||
class QStackedWidget;
|
||||
class QSettings;
|
||||
|
||||
namespace Files { struct ConfigurationManager; }
|
||||
|
||||
class GraphicsPage : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GraphicsPage(QWidget *parent = 0);
|
||||
|
||||
QSettings *mOgreConfig;
|
||||
GraphicsPage(Files::ConfigurationManager &cfg, QWidget *parent = 0);
|
||||
|
||||
void writeConfig();
|
||||
|
||||
|
@ -29,7 +28,6 @@ public slots:
|
|||
void rendererChanged(const QString &renderer);
|
||||
|
||||
private:
|
||||
Cfg::ConfigurationManager mCfg;
|
||||
Ogre::Root *mOgre;
|
||||
Ogre::RenderSystem *mSelectedRenderSystem;
|
||||
Ogre::RenderSystem *mOpenGLRenderSystem;
|
||||
|
@ -59,6 +57,10 @@ private:
|
|||
QCheckBox *mD3DVSyncCheckBox;
|
||||
QCheckBox *mD3DFullScreenCheckBox;
|
||||
|
||||
QSettings *mOgreConfig;
|
||||
|
||||
Files::ConfigurationManager &mCfgMgr;
|
||||
|
||||
QString getConfigValue(const QString &key, Ogre::RenderSystem *renderer);
|
||||
QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer);
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QtDebug>
|
||||
|
||||
#include "maindialog.hpp"
|
||||
|
||||
|
@ -17,17 +18,19 @@ int main(int argc, char *argv[])
|
|||
dir.cdUp();
|
||||
dir.cdUp();
|
||||
}
|
||||
|
||||
// force Qt to load only LOCAL plugins, don't touch system Qt installation
|
||||
QDir pluginsPath(QCoreApplication::applicationDirPath());
|
||||
pluginsPath.cdUp();
|
||||
pluginsPath.cd("Plugins");
|
||||
|
||||
QStringList libraryPaths;
|
||||
libraryPaths << pluginsPath.path() << QCoreApplication::applicationDirPath();
|
||||
app.setLibraryPaths(libraryPaths);
|
||||
#endif
|
||||
|
||||
QDir::setCurrent(dir.absolutePath());
|
||||
|
||||
// Load the stylesheet
|
||||
QFile file("./launcher.qss");
|
||||
|
||||
file.open(QFile::ReadOnly);
|
||||
QString styleSheet = QLatin1String(file.readAll());
|
||||
app.setStyleSheet(styleSheet);
|
||||
|
||||
MainDialog dialog;
|
||||
return dialog.exec();
|
||||
|
||||
|
|
|
@ -45,6 +45,20 @@ MainDialog::MainDialog()
|
|||
setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setMinimumSize(QSize(575, 575));
|
||||
|
||||
// Load the stylesheet
|
||||
QString config = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/launcher.qss").string());
|
||||
QFile file(config);
|
||||
|
||||
if (!file.exists()) {
|
||||
file.setFileName(QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.qss").string()));
|
||||
}
|
||||
|
||||
file.open(QFile::ReadOnly);
|
||||
QString styleSheet = QLatin1String(file.readAll());
|
||||
qApp->setStyleSheet(styleSheet);
|
||||
file.close();
|
||||
|
||||
|
||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
|
||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(play()));
|
||||
|
||||
|
@ -85,116 +99,13 @@ void MainDialog::createIcons()
|
|||
|
||||
}
|
||||
|
||||
QStringList MainDialog::readConfig(const QString &fileName)
|
||||
{
|
||||
// We can't use QSettings directly because it
|
||||
// does not support multiple keys with the same name
|
||||
QFile file(fileName);
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error opening OpenMW configuration file");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>Could not open %0</b><br><br> \
|
||||
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
|
||||
QApplication::exit(); // File cannot be opened or created
|
||||
}
|
||||
|
||||
QTextStream in(&file);
|
||||
QStringList dataDirs;
|
||||
QString dataLocal;
|
||||
|
||||
// Read the config line by line
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
|
||||
if (line.startsWith("data=")) {
|
||||
dataDirs.append(line.remove("data="));
|
||||
}
|
||||
|
||||
// Read the data-local key, if more than one are found only the last is used
|
||||
if (line.startsWith("data-local=")) {
|
||||
dataLocal = line.remove("data-local=");
|
||||
}
|
||||
|
||||
// Read fs-strict key
|
||||
if (line.startsWith("fs-strict=")) {
|
||||
QString value = line.remove("fs-strict=");
|
||||
|
||||
(value.toLower() == QLatin1String("true"))
|
||||
? mStrict = true
|
||||
: mStrict = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Add the data-local= key to the end of the dataDirs for priority reasons
|
||||
if (!dataLocal.isEmpty()) {
|
||||
dataDirs.append(dataLocal);
|
||||
}
|
||||
|
||||
if (!dataDirs.isEmpty())
|
||||
{
|
||||
// Reset the global datadirs to the newly read entries
|
||||
// Else return the previous dataDirs because nothing was found in this file;
|
||||
mDataDirs = dataDirs;
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
return mDataDirs;
|
||||
}
|
||||
|
||||
void MainDialog::createPages()
|
||||
{
|
||||
mPlayPage = new PlayPage(this);
|
||||
mGraphicsPage = new GraphicsPage(this);
|
||||
mDataFilesPage = new DataFilesPage(this);
|
||||
mGraphicsPage = new GraphicsPage(mCfgMgr, this);
|
||||
mDataFilesPage = new DataFilesPage(mCfgMgr, this);
|
||||
|
||||
// Retrieve all data entries from the configs
|
||||
QStringList dataDirs;
|
||||
|
||||
// Global location
|
||||
QFile file(QString::fromStdString((mCfg.getGlobalConfigPath()/"openmw.cfg").string()));
|
||||
if (file.exists()) {
|
||||
dataDirs = readConfig(file.fileName());
|
||||
}
|
||||
|
||||
// User location
|
||||
file.setFileName(QString::fromStdString((mCfg.getLocalConfigPath()/"openmw.cfg").string()));
|
||||
if (file.exists()) {
|
||||
dataDirs = readConfig(file.fileName());
|
||||
}
|
||||
|
||||
// Local location
|
||||
file.setFileName("./openmw.cfg");
|
||||
|
||||
if (file.exists()) {
|
||||
dataDirs = readConfig(file.fileName());
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
if (!dataDirs.isEmpty()) {
|
||||
// Now pass the datadirs on to the DataFilesPage
|
||||
mDataFilesPage->setupDataFiles(dataDirs, mStrict);
|
||||
} else {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error reading OpenMW configuration file");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>Could not read the location of the data files</b><br><br> \
|
||||
Please make sure OpenMW is correctly configured and try again.<br>"));
|
||||
msgBox.exec();
|
||||
|
||||
QApplication::exit(); // No data or data-local entries in openmw.cfg
|
||||
}
|
||||
|
||||
// Set the combobox of the play page to imitate the comobox on the datafilespage
|
||||
// Set the combobox of the play page to imitate the combobox on the datafilespage
|
||||
mPlayPage->mProfilesComboBox->setModel(mDataFilesPage->mProfilesComboBox->model());
|
||||
mPlayPage->mProfilesComboBox->setCurrentIndex(mDataFilesPage->mProfilesComboBox->currentIndex());
|
||||
|
||||
|
@ -246,14 +157,16 @@ void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
|
|||
void MainDialog::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
// Now write all config files
|
||||
writeConfig();
|
||||
mDataFilesPage->writeConfig();
|
||||
mGraphicsPage->writeConfig();
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void MainDialog::play()
|
||||
{
|
||||
// First do a write of all the configs, just to be sure
|
||||
writeConfig();
|
||||
mDataFilesPage->writeConfig();
|
||||
mGraphicsPage->writeConfig();
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
QString game = "./openmw.exe";
|
||||
|
@ -313,75 +226,3 @@ void MainDialog::play()
|
|||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void MainDialog::writeConfig()
|
||||
{
|
||||
// Write the profiles
|
||||
mDataFilesPage->writeConfig();
|
||||
mDataFilesPage->mLauncherConfig->sync();
|
||||
|
||||
// Write the graphics settings
|
||||
mGraphicsPage->writeConfig();
|
||||
mGraphicsPage->mOgreConfig->sync();
|
||||
|
||||
QStringList dataFiles = mDataFilesPage->selectedMasters();
|
||||
dataFiles.append(mDataFilesPage->checkedPlugins());
|
||||
|
||||
// Open the config as a QFile
|
||||
QFile file(QString::fromStdString((mCfg.getLocalConfigPath()/"openmw.cfg").string()));
|
||||
|
||||
if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
|
||||
// File cannot be opened or created
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error writing OpenMW configuration file");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>Could not open or create %0</b><br><br> \
|
||||
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
|
||||
QApplication::exit(1);
|
||||
}
|
||||
|
||||
QTextStream in(&file);
|
||||
QByteArray buffer;
|
||||
|
||||
// Remove all previous master/plugin entries from config
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
if (!line.contains("master") && !line.contains("plugin")) {
|
||||
buffer += line += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
// Now we write back the other config entries
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
QMessageBox msgBox;
|
||||
msgBox.setWindowTitle("Error writing OpenMW configuration file");
|
||||
msgBox.setIcon(QMessageBox::Critical);
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
msgBox.setText(tr("<br><b>Could not write to %0</b><br><br> \
|
||||
Please make sure you have the right permissions and try again.<br>").arg(file.fileName()));
|
||||
msgBox.exec();
|
||||
|
||||
QApplication::exit(1);
|
||||
}
|
||||
|
||||
file.write(buffer);
|
||||
|
||||
QTextStream out(&file);
|
||||
|
||||
// Write the list of game files to the config
|
||||
foreach (const QString ¤tFile, dataFiles) {
|
||||
|
||||
if (currentFile.endsWith(QString(".esm"), Qt::CaseInsensitive)) {
|
||||
out << "master=" << currentFile << endl;
|
||||
} else if (currentFile.endsWith(QString(".esp"), Qt::CaseInsensitive)) {
|
||||
out << "plugin=" << currentFile << endl;
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include <QDialog>
|
||||
|
||||
#include <components/cfg/configurationmanager.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
class QListWidget;
|
||||
class QListWidgetItem;
|
||||
|
@ -28,15 +28,11 @@ public slots:
|
|||
void play();
|
||||
void profileChanged(int index);
|
||||
|
||||
|
||||
private:
|
||||
void createIcons();
|
||||
void createPages();
|
||||
void writeConfig();
|
||||
void closeEvent(QCloseEvent *event);
|
||||
|
||||
QStringList readConfig(const QString &fileName);
|
||||
|
||||
QListWidget *mIconWidget;
|
||||
QStackedWidget *mPagesWidget;
|
||||
|
||||
|
@ -44,10 +40,7 @@ private:
|
|||
GraphicsPage *mGraphicsPage;
|
||||
DataFilesPage *mDataFilesPage;
|
||||
|
||||
QStringList mDataDirs;
|
||||
bool mStrict;
|
||||
|
||||
Cfg::ConfigurationManager mCfg;
|
||||
Files::ConfigurationManager mCfgMgr;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
#include <components/esm_store/cell_store.hpp>
|
||||
#include <components/bsa/bsa_archive.hpp>
|
||||
#include <components/esm/esm_reader.hpp>
|
||||
#include <components/files/path.hpp>
|
||||
#include <components/files/fixedpath.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
#include <components/nifbullet/bullet_nif_loader.hpp>
|
||||
#include <components/nifogre/ogre_nif_loader.hpp>
|
||||
|
||||
|
@ -171,7 +173,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
|
|||
return true;
|
||||
}
|
||||
|
||||
OMW::Engine::Engine(Cfg::ConfigurationManager& configurationManager)
|
||||
OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
|
||||
: mOgre (0)
|
||||
, mFpsLevel(0)
|
||||
, mDebug (false)
|
||||
|
@ -208,15 +210,16 @@ OMW::Engine::~Engine()
|
|||
void OMW::Engine::loadBSA()
|
||||
{
|
||||
const Files::MultiDirCollection& bsa = mFileCollections.getCollection (".bsa");
|
||||
|
||||
for (Files::MultiDirCollection::TIter iter (bsa.begin()); iter!=bsa.end(); ++iter)
|
||||
std::string dataDirectory;
|
||||
for (Files::MultiDirCollection::TIter iter(bsa.begin()); iter!=bsa.end(); ++iter)
|
||||
{
|
||||
std::cout << "Adding " << iter->second.string() << std::endl;
|
||||
Bsa::addBSA (iter->second.string());
|
||||
}
|
||||
std::cout << "Adding " << iter->second.string() << std::endl;
|
||||
Bsa::addBSA(iter->second.string());
|
||||
|
||||
std::cout << "Data dir " << mDataDir.string() << std::endl;
|
||||
Bsa::addDir(mDataDir.string(), mFSStrict);
|
||||
dataDirectory = iter->second.parent_path().string();
|
||||
std::cout << "Data dir " << dataDirectory << std::endl;
|
||||
Bsa::addDir(dataDirectory, mFSStrict);
|
||||
}
|
||||
}
|
||||
|
||||
// add resources directory
|
||||
|
@ -237,9 +240,7 @@ void OMW::Engine::enableFSStrict(bool fsStrict)
|
|||
|
||||
void OMW::Engine::setDataDirs (const Files::PathContainer& dataDirs)
|
||||
{
|
||||
/// \todo remove mDataDir, once resources system can handle multiple directories
|
||||
assert (!dataDirs.empty());
|
||||
mDataDir = dataDirs.back();
|
||||
mDataDirs = dataDirs;
|
||||
mFileCollections = Files::Collections (dataDirs, !mFSStrict);
|
||||
}
|
||||
|
||||
|
@ -315,7 +316,7 @@ void OMW::Engine::go()
|
|||
}
|
||||
mOgre->configure(!boost::filesystem::is_regular_file(mCfgMgr.getOgreConfigPath()),
|
||||
mCfgMgr.getOgreConfigPath().string(),
|
||||
mCfgMgr.getLogPath().string() + std::string("/"),
|
||||
mCfgMgr.getLogPath().string(),
|
||||
mCfgMgr.getPluginsConfigPath().string(), false);
|
||||
|
||||
// This has to be added BEFORE MyGUI is initialized, as it needs
|
||||
|
@ -341,7 +342,7 @@ void OMW::Engine::go()
|
|||
mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(),
|
||||
mOgre->getCamera(),
|
||||
mEnvironment.mWorld->getStore(),
|
||||
(mDataDir),
|
||||
mDataDirs,
|
||||
mUseSound, mFSStrict, mEnvironment);
|
||||
|
||||
// Create script system
|
||||
|
@ -450,7 +451,7 @@ void OMW::Engine::screenshot()
|
|||
// Count screenshots.
|
||||
int shotCount = 0;
|
||||
|
||||
const std::string screenshotPath = mCfgMgr.getLocalConfigPath().string();
|
||||
const std::string screenshotPath = mCfgMgr.getUserPath().string();
|
||||
|
||||
// Find the first unused filename with a do-while
|
||||
std::ostringstream stream;
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include <components/compiler/extensions.hpp>
|
||||
#include <components/files/collections.hpp>
|
||||
#include <components/cfg/configurationmanager.hpp>
|
||||
|
||||
#include "mwworld/environment.hpp"
|
||||
#include "mwworld/ptr.hpp"
|
||||
|
@ -52,13 +51,18 @@ namespace OEngine
|
|||
}
|
||||
}
|
||||
|
||||
namespace Files
|
||||
{
|
||||
struct ConfigurationManager;
|
||||
}
|
||||
|
||||
namespace OMW
|
||||
{
|
||||
/// \brief Main engine class, that brings together all the components of OpenMW
|
||||
class Engine : private Ogre::FrameListener
|
||||
{
|
||||
std::string mEncoding;
|
||||
boost::filesystem::path mDataDir;
|
||||
Files::PathContainer mDataDirs;
|
||||
boost::filesystem::path mResDir;
|
||||
OEngine::Render::OgreRenderer *mOgre;
|
||||
std::string mCellName;
|
||||
|
@ -101,7 +105,7 @@ namespace OMW
|
|||
virtual bool frameRenderingQueued (const Ogre::FrameEvent& evt);
|
||||
|
||||
public:
|
||||
Engine(Cfg::ConfigurationManager& configurationManager);
|
||||
Engine(Files::ConfigurationManager& configurationManager);
|
||||
virtual ~Engine();
|
||||
|
||||
/// Enable strict filesystem mode (do not fold case)
|
||||
|
@ -161,7 +165,7 @@ namespace OMW
|
|||
void setAnimationVerbose(bool animverbose);
|
||||
|
||||
private:
|
||||
Cfg::ConfigurationManager& mCfgMgr;
|
||||
Files::ConfigurationManager& mCfgMgr;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <components/files/fileops.hpp>
|
||||
#include <components/files/path.hpp>
|
||||
#include <components/files/fixedpath.hpp>
|
||||
#include <components/files/collections.hpp>
|
||||
#include <components/cfg/configurationmanager.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
#include "engine.hpp"
|
||||
|
||||
|
@ -35,6 +35,23 @@
|
|||
|
||||
#include "config.hpp"
|
||||
|
||||
#include <boost/version.hpp>
|
||||
/**
|
||||
* Workaround for problems with whitespaces in paths in older versions of Boost library
|
||||
*/
|
||||
#if (BOOST_VERSION <= 104600)
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<>
|
||||
inline boost::filesystem::path lexical_cast<boost::filesystem::path, std::string>(const std::string& arg)
|
||||
{
|
||||
return boost::filesystem::path(arg);
|
||||
}
|
||||
|
||||
} /* namespace boost */
|
||||
#endif /* (BOOST_VERSION <= 104600) */
|
||||
|
||||
using namespace std;
|
||||
|
||||
/**
|
||||
|
@ -46,7 +63,7 @@ using namespace std;
|
|||
* \retval true - Everything goes OK
|
||||
* \retval false - Error
|
||||
*/
|
||||
bool parseOptions (int argc, char** argv, OMW::Engine& engine, Cfg::ConfigurationManager& cfgMgr)
|
||||
bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::ConfigurationManager& cfgMgr)
|
||||
{
|
||||
// Create a local alias for brevity
|
||||
namespace bpo = boost::program_options;
|
||||
|
@ -164,14 +181,19 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Cfg::Configuratio
|
|||
std::string local(variables["data-local"].as<std::string>());
|
||||
if (!local.empty())
|
||||
{
|
||||
dataDirs.push_back(Files::PathContainer::value_type(local));
|
||||
std::cout << "Ignoring data-local (currently not supported)" << std::endl;
|
||||
// dataDirs.push_back(Files::PathContainer::value_type(local));
|
||||
}
|
||||
|
||||
if (dataDirs.empty())
|
||||
if (dataDirs.size()>1)
|
||||
{
|
||||
dataDirs.push_back(cfgMgr.getLocalDataPath());
|
||||
dataDirs.resize (1);
|
||||
std::cout << "Ignoring all but the first data path (multiple data paths currently not supported)"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
cfgMgr.processPaths(dataDirs);
|
||||
|
||||
engine.setDataDirs(dataDirs);
|
||||
|
||||
engine.setResourceDir(variables["resources"].as<std::string>());
|
||||
|
@ -224,7 +246,7 @@ int main(int argc, char**argv)
|
|||
|
||||
try
|
||||
{
|
||||
Cfg::ConfigurationManager cfgMgr;
|
||||
Files::ConfigurationManager cfgMgr;
|
||||
OMW::Engine engine(cfgMgr);
|
||||
|
||||
if (parseOptions(argc, argv, engine, cfgMgr))
|
||||
|
|
|
@ -99,14 +99,15 @@ void Actors::removeCell(MWWorld::Ptr::CellStore* store){
|
|||
mRend.getScene()->destroySceneNode(base);
|
||||
base = 0;
|
||||
}
|
||||
for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); iter++)
|
||||
{
|
||||
if(iter->first.getCell() == store){
|
||||
delete iter->second;
|
||||
mAllActors.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
for(std::map<MWWorld::Ptr, Animation*>::iterator iter = mAllActors.begin(); iter != mAllActors.end(); )
|
||||
{
|
||||
if(iter->first.getCell() == store){
|
||||
delete iter->second;
|
||||
mAllActors.erase(iter++);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
void Actors::playAnimationGroup (const MWWorld::Ptr& ptr, const std::string& groupName, int mode, int number){
|
||||
|
|
|
@ -276,6 +276,7 @@ namespace MWRender{
|
|||
rotmult = bonePtr->getOrientation();
|
||||
scale = bonePtr->getScale().x;
|
||||
boneSequenceIter++;
|
||||
|
||||
for(; boneSequenceIter != boneSequence.end(); boneSequenceIter++)
|
||||
{
|
||||
if(creaturemodel->getSkeleton()->hasBone(*boneSequenceIter)){
|
||||
|
@ -330,7 +331,7 @@ namespace MWRender{
|
|||
}
|
||||
|
||||
}
|
||||
bool Animation::timeIndex( float time, std::vector<float> times, int & i, int & j, float & x ){
|
||||
bool Animation::timeIndex( float time, const std::vector<float> & times, int & i, int & j, float & x ){
|
||||
int count;
|
||||
if ( (count = times.size()) > 0 )
|
||||
{
|
||||
|
@ -388,6 +389,8 @@ namespace MWRender{
|
|||
}
|
||||
|
||||
void Animation::handleAnimationTransforms(){
|
||||
|
||||
|
||||
Ogre::SkeletonInstance* skel = base->getSkeleton();
|
||||
|
||||
|
||||
|
@ -404,10 +407,10 @@ namespace MWRender{
|
|||
for(unsigned int i = 0; i < entityparts.size(); i++){
|
||||
//Ogre::SkeletonInstance* skel = entityparts[i]->getSkeleton();
|
||||
|
||||
Ogre::Bone* b = skel->getRootBone();
|
||||
b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3));//This is a trick
|
||||
//Ogre::Bone* b = skel->getRootBone();
|
||||
//b->setOrientation(Ogre::Real(.3),Ogre::Real(.3),Ogre::Real(.3), Ogre::Real(.3));//This is a trick
|
||||
|
||||
entityparts[i]->getAllAnimationStates()->_notifyDirty();
|
||||
//entityparts[i]->getAllAnimationStates()->_notifyDirty();
|
||||
}
|
||||
|
||||
|
||||
|
@ -424,18 +427,19 @@ namespace MWRender{
|
|||
float x;
|
||||
float x2;
|
||||
|
||||
std::vector<Ogre::Quaternion> quats = iter->getQuat();
|
||||
const std::vector<Ogre::Quaternion> & quats = iter->getQuat();
|
||||
|
||||
std::vector<float> ttime = iter->gettTime();
|
||||
std::vector<float>::iterator ttimeiter = ttime.begin();
|
||||
const std::vector<float> & ttime = iter->gettTime();
|
||||
|
||||
|
||||
std::vector<float> rtime = iter->getrTime();
|
||||
int rindexJ = 0;
|
||||
const std::vector<float> & rtime = iter->getrTime();
|
||||
int rindexJ = rindexI[slot];
|
||||
|
||||
timeIndex(time, rtime, rindexI[slot], rindexJ, x2);
|
||||
int tindexJ = 0;
|
||||
int tindexJ = tindexI[slot];
|
||||
|
||||
|
||||
std::vector<Ogre::Vector3> translist1 = iter->getTranslist1();
|
||||
const std::vector<Ogre::Vector3> & translist1 = iter->getTranslist1();
|
||||
|
||||
timeIndex(time, ttime, tindexI[slot], tindexJ, x);
|
||||
|
||||
|
@ -443,34 +447,35 @@ namespace MWRender{
|
|||
Ogre::Quaternion r;
|
||||
|
||||
bool bTrans = translist1.size() > 0;
|
||||
if(bTrans){
|
||||
Ogre::Vector3 v1 = translist1[tindexI[slot]];
|
||||
Ogre::Vector3 v2 = translist1[tindexJ];
|
||||
t = (v1 + (v2 - v1) * x);
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool bQuats = quats.size() > 0;
|
||||
if(bQuats){
|
||||
r = Ogre::Quaternion::Slerp(x2, quats[rindexI[slot]], quats[rindexJ], true);
|
||||
}
|
||||
skel = base->getSkeleton();
|
||||
|
||||
if(skel->hasBone(iter->getBonename())){
|
||||
Ogre::Bone* bone = skel->getBone(iter->getBonename());
|
||||
if(bTrans)
|
||||
if(bTrans){
|
||||
Ogre::Vector3 v1 = translist1[tindexI[slot]];
|
||||
Ogre::Vector3 v2 = translist1[tindexJ];
|
||||
t = (v1 + (v2 - v1) * x);
|
||||
bone->setPosition(t);
|
||||
if(bQuats)
|
||||
|
||||
}
|
||||
if(bQuats){
|
||||
r = Ogre::Quaternion::Slerp(x2, quats[rindexI[slot]], quats[rindexJ], true);
|
||||
bone->setOrientation(r);
|
||||
}
|
||||
|
||||
|
||||
|
||||
skel->_updateTransforms();
|
||||
base->getAllAnimationStates()->_notifyDirty();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
slot++;
|
||||
}
|
||||
skel->_updateTransforms();
|
||||
base->getAllAnimationStates()->_notifyDirty();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ class Animation{
|
|||
MWWorld::Environment& mEnvironment;
|
||||
std::map<Nif::NiSkinData::BoneInfoCopy*, PosAndRot> vecRotPos;
|
||||
static std::map<std::string, int> mUniqueIDs;
|
||||
|
||||
|
||||
|
||||
std::vector<std::vector<Nif::NiTriShapeCopy>* > shapeparts; //All the NiTriShape data that we need for animating an npc
|
||||
|
@ -55,7 +56,7 @@ class Animation{
|
|||
Ogre::Entity* base;
|
||||
void handleShapes(std::vector<Nif::NiTriShapeCopy>* allshapes, Ogre::Entity* creaturemodel, Ogre::SkeletonInstance *skel);
|
||||
void handleAnimationTransforms();
|
||||
bool timeIndex( float time, std::vector<float> times, int & i, int & j, float & x );
|
||||
bool timeIndex( float time, const std::vector<float> & times, int & i, int & j, float & x );
|
||||
std::string getUniqueID(std::string mesh);
|
||||
|
||||
public:
|
||||
|
|
|
@ -42,6 +42,7 @@ NpcAnimation::NpcAnimation(const MWWorld::Ptr& ptr, MWWorld::Environment& _env,O
|
|||
std::string bodyRaceID = headID.substr(0, headID.find_last_of("head_") - 4);
|
||||
char secondtolast = bodyRaceID.at(bodyRaceID.length() - 2);
|
||||
bool female = tolower(secondtolast) == 'f';
|
||||
std::transform(bodyRaceID.begin(), bodyRaceID.end(), bodyRaceID.begin(), ::tolower);
|
||||
bool beast = bodyRaceID == "b_n_khajiit_m_" || bodyRaceID == "b_n_khajiit_f_" || bodyRaceID == "b_n_argonian_m_" || bodyRaceID == "b_n_argonian_f_";
|
||||
|
||||
/*std::cout << "Race: " << ref->base->race ;
|
||||
|
@ -276,6 +277,7 @@ void NpcAnimation::runAnimation(float timepassed){
|
|||
shapepartsiter++;
|
||||
entitypartsiter++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -101,6 +101,14 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
|
|||
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
|
||||
//Create the scenenode and put it in the map
|
||||
mStaticGeometry[ptr.getCell()] = sg;
|
||||
|
||||
// This specifies the size of a single batch region.
|
||||
// If it is set too high:
|
||||
// - there will be problems choosing the correct lights
|
||||
// - the culling will be more inefficient
|
||||
// If it is set too low:
|
||||
// - there will be too many batches.
|
||||
sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -108,7 +116,6 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
|
|||
}
|
||||
|
||||
sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale());
|
||||
sg->setRegionDimensions(Ogre::Vector3(100000,10000,100000));
|
||||
|
||||
mRenderer.getScene()->destroyEntity(ent);
|
||||
}
|
||||
|
|
|
@ -658,9 +658,15 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
|
|||
|
||||
if (weather.mNight && mStarsOpacity != weather.mNightFade)
|
||||
{
|
||||
for (int i=0; i<7; ++i)
|
||||
mStarsMaterials[i]->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, weather.mNightFade);
|
||||
mStarsOpacity = weather.mNightFade;
|
||||
if (weather.mNightFade == 0)
|
||||
mAtmosphereNight->setVisible(false);
|
||||
else
|
||||
{
|
||||
mAtmosphereNight->setVisible(true);
|
||||
for (int i=0; i<7; ++i)
|
||||
mStarsMaterials[i]->getTechnique(0)->getPass(0)->setDiffuse(0.0, 0.0, 0.0, weather.mNightFade);
|
||||
mStarsOpacity = weather.mNightFade;
|
||||
}
|
||||
}
|
||||
|
||||
float strength;
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
#include <algorithm>
|
||||
#include <map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include <OgreRoot.h>
|
||||
|
||||
#include <openengine/sound/sndmanager.hpp>
|
||||
|
@ -15,6 +13,7 @@ using namespace std;
|
|||
#include <components/file_finder/file_finder.hpp>
|
||||
#include <components/esm_store/store.hpp>
|
||||
|
||||
|
||||
#include "../mwworld/environment.hpp"
|
||||
#include "../mwworld/world.hpp"
|
||||
#include "../mwworld/player.hpp"
|
||||
|
@ -90,24 +89,28 @@ namespace MWSound
|
|||
// relative to the sound dir, and translates them into full paths
|
||||
// of existing files in the filesystem, if they exist.
|
||||
bool FSstrict;
|
||||
FileFinder::FileFinder files;
|
||||
FileFinder::FileFinderStrict strict;
|
||||
FileFinder::FileFinder musicpath;
|
||||
FileFinder::FileFinderStrict musicpathStrict;
|
||||
FileFinder::LessTreeFileFinder files;
|
||||
FileFinder::StrictTreeFileFinder strict;
|
||||
FileFinder::LessTreeFileFinder musicpath;
|
||||
FileFinder::StrictTreeFileFinder musicpathStrict;
|
||||
|
||||
SoundImpl(Ogre::Root *root, Ogre::Camera *camera,
|
||||
const ESMS::ESMStore &str,
|
||||
const std::string &soundDir, const std::string &musicDir, bool fsstrict)
|
||||
SoundImpl(Ogre::Root *root, Ogre::Camera *camera, const ESMS::ESMStore &str,
|
||||
const Files::PathContainer& soundDir,
|
||||
const Files::PathContainer& musicDir,
|
||||
bool fsstrict)
|
||||
: mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY)))
|
||||
, updater(mgr)
|
||||
, cameraTracker(mgr)
|
||||
, store(str)
|
||||
, files(soundDir), strict(soundDir)
|
||||
,musicpath(musicDir), musicpathStrict(musicDir)
|
||||
, FSstrict(fsstrict)
|
||||
, files(soundDir)
|
||||
, strict(soundDir)
|
||||
, musicpath(musicDir)
|
||||
, musicpathStrict(musicDir)
|
||||
{
|
||||
FSstrict = fsstrict;
|
||||
cout << "Sound output: " << SOUND_OUT << endl;
|
||||
cout << "Sound decoder: " << SOUND_IN << endl;
|
||||
|
||||
std::cout << "Sound output: " << SOUND_OUT << std::endl;
|
||||
std::cout << "Sound decoder: " << SOUND_IN << std::endl;
|
||||
// Attach the camera to the camera tracker
|
||||
cameraTracker.followCamera(camera);
|
||||
|
||||
|
@ -136,36 +139,49 @@ namespace MWSound
|
|||
|
||||
bool hasFile(const std::string &str, bool music = false)
|
||||
{
|
||||
if(FSstrict == false)
|
||||
bool found = false;
|
||||
if(!FSstrict)
|
||||
{
|
||||
if(music)
|
||||
{
|
||||
if(musicpath.has(str)) return true;
|
||||
|
||||
found = musicpath.has(str);
|
||||
// Not found? Try with .mp3
|
||||
return musicpath.has(toMp3(str));
|
||||
if (!found)
|
||||
{
|
||||
found = musicpath.has(toMp3(str));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(files.has(str)) return true;
|
||||
return files.has(toMp3(str));
|
||||
found = files.has(str);
|
||||
if (!found)
|
||||
{
|
||||
found = files.has(toMp3(str));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(music)
|
||||
{
|
||||
if(musicpathStrict.has(str)) return true;
|
||||
|
||||
found = musicpathStrict.has(str);
|
||||
// Not found? Try with .mp3
|
||||
return musicpathStrict.has(toMp3(str));
|
||||
if (!found)
|
||||
{
|
||||
found = musicpathStrict.has(toMp3(str));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(strict.has(str)) return true;
|
||||
return strict.has(toMp3(str));
|
||||
found = strict.has(str);
|
||||
if (!found)
|
||||
{
|
||||
found = strict.has(toMp3(str));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
// Convert a Morrowind sound path (eg. Fx\funny.wav) to full path
|
||||
|
@ -258,13 +274,13 @@ namespace MWSound
|
|||
}
|
||||
catch(...)
|
||||
{
|
||||
cout << "Error loading " << file << ", skipping.\n";
|
||||
std::cout << "Error loading " << file << ", skipping.\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Clears all the sub-elements of a given iterator, and then
|
||||
// removes it from 'sounds'.
|
||||
void clearAll(PtrMap::iterator it)
|
||||
void clearAll(PtrMap::iterator& it)
|
||||
{
|
||||
IDMap::iterator sit = it->second.begin();
|
||||
|
||||
|
@ -362,9 +378,9 @@ namespace MWSound
|
|||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}; /* SoundImpl */
|
||||
|
||||
void SoundManager::streamMusicFull (const std::string& filename)
|
||||
void SoundManager::streamMusicFull(const std::string& filename)
|
||||
{
|
||||
if(!mData) return;
|
||||
|
||||
|
@ -381,20 +397,29 @@ namespace MWSound
|
|||
}
|
||||
|
||||
SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera,
|
||||
const ESMS::ESMStore &store,
|
||||
boost::filesystem::path dataDir,
|
||||
bool useSound, bool fsstrict, MWWorld::Environment& environment)
|
||||
: mData(NULL), fsStrict (fsstrict), mEnvironment (environment)
|
||||
const ESMS::ESMStore &store, const Files::PathContainer& dataDirs,
|
||||
bool useSound, bool fsstrict, MWWorld::Environment& environment)
|
||||
: mData(NULL)
|
||||
, fsStrict(fsstrict)
|
||||
, mEnvironment(environment)
|
||||
{
|
||||
MP3Lookup(dataDir / "Music/Explore/");
|
||||
if(useSound)
|
||||
mData = new SoundImpl(root, camera, store, (dataDir / "Sound").string(), (dataDir / "Music").string(), fsstrict);
|
||||
for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
|
||||
{
|
||||
MP3Lookup((*it) / "Music/Explore/");
|
||||
}
|
||||
|
||||
if(useSound)
|
||||
{
|
||||
Files::PathContainer soundDirs;;
|
||||
for (Files::PathContainer::const_iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
|
||||
{
|
||||
soundDirs.push_back( *it / std::string("Sound"));
|
||||
}
|
||||
mData = new SoundImpl(root, camera, store, soundDirs /* Sound */, dataDirs /* Music */, fsstrict);
|
||||
}
|
||||
|
||||
test.name = "";
|
||||
total = 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
SoundManager::~SoundManager()
|
||||
|
@ -407,14 +432,12 @@ namespace MWSound
|
|||
{
|
||||
if(mData->hasFile(filename, true))
|
||||
{
|
||||
std::string fullpath = mData->convertPath(filename, true);
|
||||
streamMusicFull(fullpath);
|
||||
streamMusicFull(mData->convertPath(filename, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SoundManager::MP3Lookup(boost::filesystem::path dir)
|
||||
{
|
||||
void SoundManager::MP3Lookup(const boost::filesystem::path& dir)
|
||||
{
|
||||
boost::filesystem::directory_iterator dir_iter(dir), dir_end;
|
||||
|
||||
std::string mp3extension = ".mp3";
|
||||
|
@ -425,35 +448,30 @@ namespace MWSound
|
|||
files.push_back(*dir_iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoundManager::startRandomTitle()
|
||||
{
|
||||
std::vector<boost::filesystem::path>::iterator fileIter;
|
||||
|
||||
if(files.size() > 0)
|
||||
{
|
||||
if(!files.empty())
|
||||
{
|
||||
fileIter = files.begin();
|
||||
srand ( time(NULL) );
|
||||
Files::PathContainer::iterator fileIter = files.begin();
|
||||
srand( time(NULL) );
|
||||
int r = rand() % files.size() + 1; //old random code
|
||||
|
||||
for(int i = 1; i < r; i++)
|
||||
{
|
||||
fileIter++;
|
||||
}
|
||||
std::advance(fileIter, r - 1);
|
||||
std::string music = fileIter->string();
|
||||
std::cout << "Playing " << music << "\n";
|
||||
|
||||
try
|
||||
{
|
||||
std::cout << "Playing " << music << "\n";
|
||||
streamMusicFull(music);
|
||||
}
|
||||
catch(std::exception &e)
|
||||
catch (std::exception &e)
|
||||
{
|
||||
std::cout << " Music Error: " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool SoundManager::isMusicPlaying()
|
||||
{
|
||||
|
@ -465,14 +483,12 @@ namespace MWSound
|
|||
return test;
|
||||
}
|
||||
|
||||
SoundManager::SoundImpl SoundManager::getMData()
|
||||
SoundManager::SoundImpl SoundManager::getMData()
|
||||
{
|
||||
// bool test = mData->music->isPlaying();
|
||||
return *mData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename)
|
||||
{
|
||||
// The range values are not tested
|
||||
|
@ -480,7 +496,7 @@ namespace MWSound
|
|||
if(mData->hasFile(filename))
|
||||
mData->add(mData->convertPath(filename), ptr, "_say_sound", 1, 1, 100, 20000, false);
|
||||
else
|
||||
cout << "Sound file " << filename << " not found, skipping.\n";
|
||||
std::cout << "Sound file " << filename << " not found, skipping.\n";
|
||||
}
|
||||
|
||||
bool SoundManager::sayDone (MWWorld::Ptr ptr) const
|
||||
|
@ -490,20 +506,20 @@ namespace MWSound
|
|||
}
|
||||
|
||||
|
||||
void SoundManager::playSound (const std::string& soundId, float volume, float pitch)
|
||||
void SoundManager::playSound(const std::string& soundId, float volume, float pitch)
|
||||
{
|
||||
if(!mData) return;
|
||||
// Play and forget
|
||||
float min, max;
|
||||
const std::string &file = mData->lookup(soundId, volume, min, max);
|
||||
if(file != "")
|
||||
{
|
||||
if (file != "")
|
||||
{
|
||||
SoundPtr snd = mData->mgr->load(file);
|
||||
snd->setVolume(volume);
|
||||
snd->setRange(min,max);
|
||||
snd->setPitch(pitch);
|
||||
snd->play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SoundManager::playSound3D (MWWorld::Ptr ptr, const std::string& soundId,
|
||||
|
@ -514,7 +530,7 @@ namespace MWSound
|
|||
// Look up the sound in the ESM data
|
||||
float min, max;
|
||||
const std::string &file = mData->lookup(soundId, volume, min, max);
|
||||
if(file != "")
|
||||
if (file != "")
|
||||
mData->add(file, ptr, soundId, volume, pitch, min, max, loop);
|
||||
}
|
||||
|
||||
|
@ -541,18 +557,19 @@ namespace MWSound
|
|||
|
||||
void SoundManager::updateObject(MWWorld::Ptr ptr)
|
||||
{
|
||||
if(!mData) return;
|
||||
mData->updatePositions(ptr);
|
||||
if (mData != NULL)
|
||||
{
|
||||
mData->updatePositions(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void SoundManager::update (float duration)
|
||||
{
|
||||
std::string effect;
|
||||
|
||||
MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell();
|
||||
|
||||
//If the region has changed
|
||||
if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10){
|
||||
if(!(current->cell->data.flags & current->cell->Interior) && timer.elapsed() >= 10)
|
||||
{
|
||||
timer.restart();
|
||||
if (test.name != current->cell->region)
|
||||
{
|
||||
|
@ -564,11 +581,12 @@ namespace MWSound
|
|||
{
|
||||
std::vector<ESM::Region::SoundRef>::iterator soundIter = test.soundList.begin();
|
||||
//mEnvironment.mSoundManager
|
||||
if(total == 0){
|
||||
while (!(soundIter == test.soundList.end()))
|
||||
if(total == 0)
|
||||
{
|
||||
while (soundIter != test.soundList.end())
|
||||
{
|
||||
ESM::NAME32 go = soundIter->sound;
|
||||
int chance = (int) soundIter->chance;
|
||||
//ESM::NAME32 go = soundIter->sound;
|
||||
//std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
|
||||
soundIter++;
|
||||
total += chance;
|
||||
|
@ -578,7 +596,7 @@ namespace MWSound
|
|||
int r = rand() % total; //old random code
|
||||
int pos = 0;
|
||||
soundIter = test.soundList.begin();
|
||||
while (!(soundIter == test.soundList.end()))
|
||||
while (soundIter != test.soundList.end())
|
||||
{
|
||||
const ESM::NAME32 go = soundIter->sound;
|
||||
int chance = (int) soundIter->chance;
|
||||
|
@ -586,13 +604,11 @@ namespace MWSound
|
|||
soundIter++;
|
||||
if( r - pos < chance)
|
||||
{
|
||||
effect = go.name;
|
||||
//play sound
|
||||
std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n";
|
||||
mEnvironment.mSoundManager->playSound(effect, 20.0, 1.0);
|
||||
mEnvironment.mSoundManager->playSound(go.name, 20.0, 1.0);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
pos += chance;
|
||||
}
|
||||
|
|
|
@ -2,14 +2,15 @@
|
|||
#define GAME_SOUND_SOUNDMANAGER_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/timer.hpp>
|
||||
|
||||
#include "../mwworld/ptr.hpp"
|
||||
#include <openengine/sound/sndmanager.hpp>
|
||||
#include <components/files/multidircollection.hpp>
|
||||
|
||||
|
||||
#include <boost/timer.hpp>
|
||||
|
||||
namespace Ogre
|
||||
{
|
||||
|
@ -37,7 +38,7 @@ namespace MWSound
|
|||
struct SoundImpl;
|
||||
|
||||
SoundImpl *mData;
|
||||
std::vector<boost::filesystem::path> files;
|
||||
Files::PathContainer files;
|
||||
bool fsStrict;
|
||||
MWWorld::Environment& mEnvironment;
|
||||
|
||||
|
@ -52,7 +53,7 @@ namespace MWSound
|
|||
public:
|
||||
|
||||
SoundManager(Ogre::Root*, Ogre::Camera*, const ESMS::ESMStore &store,
|
||||
boost::filesystem::path dataDir, bool useSound, bool fsstrict,
|
||||
const Files::PathContainer& dataDir, bool useSound, bool fsstrict,
|
||||
MWWorld::Environment& environment);
|
||||
~SoundManager();
|
||||
|
||||
|
@ -61,7 +62,7 @@ namespace MWSound
|
|||
/// \param filename name of a sound file in "Music/" in the data directory.
|
||||
|
||||
void startRandomTitle();
|
||||
void MP3Lookup(boost::filesystem::path dir);
|
||||
void MP3Lookup(const boost::filesystem::path& dir);
|
||||
|
||||
bool isMusicPlaying();
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ namespace MWWorld
|
|||
void PhysicsSystem::addObject (const std::string& handle, const std::string& mesh,
|
||||
const Ogre::Quaternion& rotation, float scale, const Ogre::Vector3& position)
|
||||
{
|
||||
OEngine::Physic::RigidBody* body = mEngine->createRigidBody(mesh,handle);
|
||||
OEngine::Physic::RigidBody* body = mEngine->createRigidBody(mesh,handle,scale);
|
||||
mEngine->addRigidBody(body);
|
||||
btTransform tr;
|
||||
tr.setOrigin(btVector3(position.x,position.y,position.z));
|
||||
|
|
|
@ -758,7 +758,7 @@ unsigned int WeatherManager::getWeatherID() const
|
|||
return 3;
|
||||
else if (mCurrentWeather == "rain")
|
||||
return 4;
|
||||
else if (mCurrentWeather == "thunder")
|
||||
else if (mCurrentWeather == "thunderstorm")
|
||||
return 5;
|
||||
else if (mCurrentWeather == "ashstorm")
|
||||
return 6;
|
||||
|
@ -787,7 +787,7 @@ void WeatherManager::changeWeather(const std::string& region, const unsigned int
|
|||
else if (id==4)
|
||||
weather = "rain";
|
||||
else if (id==5)
|
||||
weather = "thunder";
|
||||
weather = "thunderstorm";
|
||||
else if (id==6)
|
||||
weather = "ashstorm";
|
||||
else if (id==7)
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# Once done, this will define
|
||||
#
|
||||
# OGRE_FOUND - system has OGRE
|
||||
# OGRE_INCLUDE_DIRS - the OGRE include directories
|
||||
# OGRE_INCLUDE_DIRS - the OGRE include directories
|
||||
# OGRE_LIBRARIES - link these to use the OGRE core
|
||||
# OGRE_BINARY_REL - location of the main Ogre binary (win32 non-static only, release)
|
||||
# OGRE_BINARY_DBG - location of the main Ogre binaries (win32 non-static only, debug)
|
||||
|
@ -33,9 +33,10 @@
|
|||
#
|
||||
# For each of these components, the following variables are defined:
|
||||
#
|
||||
|
||||
# OGRE_${COMPONENT}_FOUND - ${COMPONENT} is available
|
||||
# OGRE_${COMPONENT}_INCLUDE_DIRS - additional include directories for ${COMPONENT}
|
||||
# OGRE_${COMPONENT}_LIBRARIES - link these to use ${COMPONENT}
|
||||
# OGRE_${COMPONENT}_LIBRARIES - link these to use ${COMPONENT}
|
||||
# OGRE_${COMPONENT}_BINARY_REL - location of the component binary (win32 non-static only, release)
|
||||
# OGRE_${COMPONENT}_BINARY_DBG - location of the component binary (win32 non-static only, debug)
|
||||
#
|
||||
|
@ -112,7 +113,7 @@ if (OGRE_PREFIX_SOURCE AND OGRE_PREFIX_BUILD)
|
|||
set(OGRE_BIN_SEARCH_PATH ${dir}/bin ${OGRE_BIN_SEARCH_PATH})
|
||||
set(OGRE_BIN_SEARCH_PATH ${dir}/Samples/Common/bin ${OGRE_BIN_SEARCH_PATH})
|
||||
endforeach(dir)
|
||||
|
||||
|
||||
if (OGRE_PREFIX_DEPENDENCIES_DIR)
|
||||
set(OGRE_INC_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/include ${OGRE_INC_SEARCH_PATH})
|
||||
set(OGRE_LIB_SEARCH_PATH ${OGRE_PREFIX_DEPENDENCIES_DIR}/lib ${OGRE_LIB_SEARCH_PATH})
|
||||
|
@ -124,12 +125,12 @@ else()
|
|||
endif ()
|
||||
|
||||
# redo search if any of the environmental hints changed
|
||||
set(OGRE_COMPONENTS Paging Terrain
|
||||
set(OGRE_COMPONENTS Paging Terrain
|
||||
Plugin_BSPSceneManager Plugin_CgProgramManager Plugin_OctreeSceneManager
|
||||
Plugin_OctreeZone Plugin_PCZSceneManager Plugin_ParticleFX
|
||||
RenderSystem_Direct3D11 RenderSystem_Direct3D9 RenderSystem_GL RenderSystem_GLES RenderSystem_GLES2)
|
||||
set(OGRE_RESET_VARS
|
||||
OGRE_CONFIG_INCLUDE_DIR OGRE_INCLUDE_DIR
|
||||
set(OGRE_RESET_VARS
|
||||
OGRE_CONFIG_INCLUDE_DIR OGRE_INCLUDE_DIR
|
||||
OGRE_LIBRARY_FWK OGRE_LIBRARY_REL OGRE_LIBRARY_DBG
|
||||
OGRE_PLUGIN_DIR_DBG OGRE_PLUGIN_DIR_REL OGRE_MEDIA_DIR)
|
||||
foreach (comp ${OGRE_COMPONENTS})
|
||||
|
@ -265,7 +266,7 @@ if (OGRE_STATIC)
|
|||
if (APPLE AND NOT OGRE_BUILD_PLATFORM_APPLE_IOS)
|
||||
set(OGRE_LIBRARIES ${OGRE_LIBRARIES} ${X11_LIBRARIES} ${X11_Xt_LIBRARIES} ${XAW_LIBRARY} ${X11_Xrandr_LIB} ${Carbon_LIBRARIES} ${Cocoa_LIBRARIES})
|
||||
endif()
|
||||
|
||||
|
||||
if (NOT ZLIB_FOUND OR NOT ZZip_FOUND)
|
||||
set(OGRE_DEPS_FOUND FALSE)
|
||||
endif ()
|
||||
|
@ -308,7 +309,7 @@ if (OGRE_STATIC)
|
|||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
if (NOT OGRE_DEPS_FOUND)
|
||||
pkg_message(OGRE "Could not find all required dependencies for the Ogre package.")
|
||||
set(OGRE_FOUND FALSE)
|
||||
|
@ -340,7 +341,7 @@ endif()
|
|||
# Find Ogre components
|
||||
#########################################################
|
||||
|
||||
set(OGRE_COMPONENT_SEARCH_PATH_REL
|
||||
set(OGRE_COMPONENT_SEARCH_PATH_REL
|
||||
${OGRE_LIBRARY_DIR_REL}/..
|
||||
${OGRE_LIBRARY_DIR_REL}/../..
|
||||
${OGRE_BIN_SEARCH_PATH}
|
||||
|
@ -392,17 +393,17 @@ macro(ogre_find_plugin PLUGIN HEADER)
|
|||
set(TMP_CMAKE_LIB_PREFIX ${CMAKE_FIND_LIBRARY_PREFIXES})
|
||||
set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES} "")
|
||||
endif()
|
||||
|
||||
|
||||
# strip RenderSystem_ or Plugin_ prefix from plugin name
|
||||
string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN})
|
||||
string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP})
|
||||
|
||||
|
||||
# header files for plugins are not usually needed, but find them anyway if they are present
|
||||
set(OGRE_PLUGIN_PATH_SUFFIXES
|
||||
PlugIns PlugIns/${PLUGIN_NAME} Plugins Plugins/${PLUGIN_NAME} ${PLUGIN}
|
||||
PlugIns PlugIns/${PLUGIN_NAME} Plugins Plugins/${PLUGIN_NAME} ${PLUGIN}
|
||||
RenderSystems RenderSystems/${PLUGIN_NAME} ${ARGN})
|
||||
find_path(OGRE_${PLUGIN}_INCLUDE_DIR NAMES ${HEADER}
|
||||
HINTS ${OGRE_INCLUDE_DIRS} ${OGRE_PREFIX_SOURCE}
|
||||
find_path(OGRE_${PLUGIN}_INCLUDE_DIR NAMES ${HEADER}
|
||||
HINTS ${OGRE_INCLUDE_DIRS} ${OGRE_PREFIX_SOURCE}
|
||||
PATH_SUFFIXES ${OGRE_PLUGIN_PATH_SUFFIXES})
|
||||
# find link libraries for plugins
|
||||
set(OGRE_${PLUGIN}_LIBRARY_NAMES "${PLUGIN}${OGRE_LIB_SUFFIX}")
|
||||
|
@ -428,7 +429,7 @@ macro(ogre_find_plugin PLUGIN HEADER)
|
|||
if (OGRE_${PLUGIN}_FOUND)
|
||||
if (NOT OGRE_PLUGIN_DIR_REL OR NOT OGRE_PLUGIN_DIR_DBG)
|
||||
if (WIN32)
|
||||
set(OGRE_PLUGIN_SEARCH_PATH_REL
|
||||
set(OGRE_PLUGIN_SEARCH_PATH_REL
|
||||
${OGRE_LIBRARY_DIR_REL}/..
|
||||
${OGRE_LIBRARY_DIR_REL}/../..
|
||||
${OGRE_BIN_SEARCH_PATH}
|
||||
|
@ -449,7 +450,7 @@ macro(ogre_find_plugin PLUGIN HEADER)
|
|||
set(OGRE_PLUGIN_DIR_DBG ${OGRE_PLUGIN_DIR_TMP} CACHE STRING "Ogre plugin dir (debug)" FORCE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
|
||||
# find binaries
|
||||
if (NOT OGRE_STATIC)
|
||||
if (WIN32)
|
||||
|
@ -458,7 +459,7 @@ macro(ogre_find_plugin PLUGIN HEADER)
|
|||
endif()
|
||||
mark_as_advanced(OGRE_${PLUGIN}_REL OGRE_${PLUGIN}_DBG)
|
||||
endif()
|
||||
|
||||
|
||||
endif ()
|
||||
|
||||
if (TMP_CMAKE_LIB_PREFIX)
|
||||
|
@ -498,7 +499,7 @@ if (OGRE_STATIC)
|
|||
if (NOT Cg_FOUND)
|
||||
set(OGRE_Plugin_CgProgramManager_FOUND FALSE)
|
||||
endif ()
|
||||
|
||||
|
||||
set(OGRE_RenderSystem_Direct3D9_LIBRARIES ${OGRE_RenderSystem_Direct3D9_LIBRARIES}
|
||||
${DirectX_LIBRARIES}
|
||||
)
|
||||
|
|
|
@ -6,10 +6,6 @@ add_component_dir (bsa
|
|||
bsa_archive bsa_file
|
||||
)
|
||||
|
||||
add_component_dir (cfg
|
||||
configurationmanager
|
||||
)
|
||||
|
||||
add_component_dir (nif
|
||||
controlled effect nif_types record controller extra node record_ptr data nif_file property
|
||||
)
|
||||
|
@ -47,7 +43,7 @@ add_component_dir (misc
|
|||
)
|
||||
|
||||
add_component_dir (files
|
||||
linuxpath windowspath macospath path multidircollection collections fileops
|
||||
linuxpath windowspath macospath fixedpath multidircollection collections fileops configurationmanager
|
||||
)
|
||||
|
||||
add_component_dir (compiler
|
||||
|
|
|
@ -1,157 +0,0 @@
|
|||
#include "configurationmanager.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
namespace Cfg
|
||||
{
|
||||
|
||||
static const char* const openmwCfgFile = "openmw.cfg";
|
||||
static const char* const ogreCfgFile = "ogre.cfg";
|
||||
static const char* const pluginsCfgFile = "plugins.cfg";
|
||||
|
||||
|
||||
ConfigurationManager::ConfigurationManager()
|
||||
: mPath("openmw")
|
||||
{
|
||||
/**
|
||||
* According to task #168 plugins.cfg file shall be located in global
|
||||
* configuration path or in runtime configuration path.
|
||||
*/
|
||||
mPluginsCfgPath = mPath.getGlobalConfigPath() / pluginsCfgFile;
|
||||
if (!boost::filesystem::is_regular_file(mPluginsCfgPath))
|
||||
{
|
||||
mPluginsCfgPath = mPath.getRuntimeConfigPath() / pluginsCfgFile;
|
||||
if (!boost::filesystem::is_regular_file(mPluginsCfgPath))
|
||||
{
|
||||
std::cerr << "Failed to find " << pluginsCfgFile << " file!" << std::endl;
|
||||
mPluginsCfgPath.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* According to task #168 ogre.cfg file shall be located only
|
||||
* in user configuration path.
|
||||
*/
|
||||
mOgreCfgPath = mPath.getLocalConfigPath() / ogreCfgFile;
|
||||
|
||||
mLogPath = mPath.getLocalConfigPath();
|
||||
}
|
||||
|
||||
ConfigurationManager::~ConfigurationManager()
|
||||
{
|
||||
}
|
||||
|
||||
void ConfigurationManager::readConfiguration(boost::program_options::variables_map& variables,
|
||||
boost::program_options::options_description& description)
|
||||
{
|
||||
loadConfig(mPath.getLocalConfigPath(), variables, description);
|
||||
boost::program_options::notify(variables);
|
||||
loadConfig(mPath.getRuntimeConfigPath(), variables, description);
|
||||
boost::program_options::notify(variables);
|
||||
loadConfig(mPath.getGlobalConfigPath(), variables, description);
|
||||
boost::program_options::notify(variables);
|
||||
}
|
||||
|
||||
void ConfigurationManager::loadConfig(const boost::filesystem::path& path,
|
||||
boost::program_options::variables_map& variables,
|
||||
boost::program_options::options_description& description)
|
||||
{
|
||||
boost::filesystem::path cfgFile(path);
|
||||
cfgFile /= std::string(openmwCfgFile);
|
||||
if (boost::filesystem::is_regular_file(cfgFile))
|
||||
{
|
||||
std::cout << "Loading config file: " << cfgFile.string() << "... ";
|
||||
|
||||
std::ifstream configFileStream(cfgFile.string().c_str());
|
||||
if (configFileStream.is_open())
|
||||
{
|
||||
boost::program_options::store(boost::program_options::parse_config_file(
|
||||
configFileStream, description), variables);
|
||||
|
||||
std::cout << "done." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "failed." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getGlobalConfigPath() const
|
||||
{
|
||||
return mPath.getGlobalConfigPath();
|
||||
}
|
||||
|
||||
void ConfigurationManager::setGlobalConfigPath(const boost::filesystem::path& newPath)
|
||||
{
|
||||
mPath.setGlobalConfigPath(newPath);
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getLocalConfigPath() const
|
||||
{
|
||||
return mPath.getLocalConfigPath();
|
||||
}
|
||||
|
||||
void ConfigurationManager::setLocalConfigPath(const boost::filesystem::path& newPath)
|
||||
{
|
||||
mPath.setLocalConfigPath(newPath);
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getRuntimeConfigPath() const
|
||||
{
|
||||
return mPath.getRuntimeConfigPath();
|
||||
}
|
||||
|
||||
void ConfigurationManager::setRuntimeConfigPath(const boost::filesystem::path& newPath)
|
||||
{
|
||||
mPath.setRuntimeConfigPath(newPath);
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getGlobalDataPath() const
|
||||
{
|
||||
return mPath.getGlobalDataPath();
|
||||
}
|
||||
|
||||
void ConfigurationManager::setGlobalDataPath(const boost::filesystem::path& newPath)
|
||||
{
|
||||
mPath.setGlobalDataPath(newPath);
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getLocalDataPath() const
|
||||
{
|
||||
return mPath.getLocalDataPath();
|
||||
}
|
||||
|
||||
void ConfigurationManager::setLocalDataPath(const boost::filesystem::path& newPath)
|
||||
{
|
||||
mPath.setLocalDataPath(newPath);
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getRuntimeDataPath() const
|
||||
{
|
||||
return mPath.getRuntimeDataPath();
|
||||
}
|
||||
|
||||
void ConfigurationManager::setRuntimeDataPath(const boost::filesystem::path& newPath)
|
||||
{
|
||||
mPath.setRuntimeDataPath(newPath);
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getOgreConfigPath() const
|
||||
{
|
||||
return mOgreCfgPath;
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getPluginsConfigPath() const
|
||||
{
|
||||
return mPluginsCfgPath;
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getLogPath() const
|
||||
{
|
||||
return mLogPath;
|
||||
}
|
||||
|
||||
} /* namespace Cfg */
|
|
@ -1,62 +0,0 @@
|
|||
#ifndef COMPONENTS_CFG_CONFIGURATIONMANAGER_HPP
|
||||
#define COMPONENTS_CFG_CONFIGURATIONMANAGER_HPP
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <components/files/path.hpp>
|
||||
|
||||
/**
|
||||
* \namespace Cfg
|
||||
*/
|
||||
namespace Cfg
|
||||
{
|
||||
|
||||
/**
|
||||
* \struct ConfigurationManager
|
||||
*/
|
||||
struct ConfigurationManager
|
||||
{
|
||||
ConfigurationManager();
|
||||
virtual ~ConfigurationManager();
|
||||
|
||||
void readConfiguration(boost::program_options::variables_map& variables,
|
||||
boost::program_options::options_description& description);
|
||||
|
||||
const boost::filesystem::path& getGlobalConfigPath() const;
|
||||
void setGlobalConfigPath(const boost::filesystem::path& newPath);
|
||||
|
||||
const boost::filesystem::path& getLocalConfigPath() const;
|
||||
void setLocalConfigPath(const boost::filesystem::path& newPath);
|
||||
|
||||
const boost::filesystem::path& getRuntimeConfigPath() const;
|
||||
void setRuntimeConfigPath(const boost::filesystem::path& newPath);
|
||||
|
||||
const boost::filesystem::path& getGlobalDataPath() const;
|
||||
void setGlobalDataPath(const boost::filesystem::path& newPath);
|
||||
|
||||
const boost::filesystem::path& getLocalDataPath() const;
|
||||
void setLocalDataPath(const boost::filesystem::path& newPath);
|
||||
|
||||
const boost::filesystem::path& getRuntimeDataPath() const;
|
||||
void setRuntimeDataPath(const boost::filesystem::path& newPath);
|
||||
|
||||
const boost::filesystem::path& getOgreConfigPath() const;
|
||||
const boost::filesystem::path& getPluginsConfigPath() const;
|
||||
const boost::filesystem::path& getLogPath() const;
|
||||
|
||||
private:
|
||||
void loadConfig(const boost::filesystem::path& path,
|
||||
boost::program_options::variables_map& variables,
|
||||
boost::program_options::options_description& description);
|
||||
|
||||
Files::Path<> mPath;
|
||||
|
||||
boost::filesystem::path mOgreCfgPath;
|
||||
boost::filesystem::path mPluginsCfgPath;
|
||||
boost::filesystem::path mLogPath;
|
||||
};
|
||||
|
||||
} /* namespace Cfg */
|
||||
|
||||
#endif /* COMPONENTS_CFG_CONFIGURATIONMANAGER_HPP */
|
|
@ -153,7 +153,7 @@ public:
|
|||
*************************************************************************/
|
||||
|
||||
int getVer() { return mCtx.header.version; }
|
||||
float getFVer() { return *((float*)&mCtx.header.version); }
|
||||
float getFVer() { if(mCtx.header.version == VER_12) return 1.2; else return 1.3; }
|
||||
int getSpecial() { return mSpf; }
|
||||
const std::string getAuthor() { return mCtx.header.author.toString(); }
|
||||
const std::string getDesc() { return mCtx.header.desc.toString(); }
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#ifndef FILE_FINDER_MAIN_H
|
||||
#define FILE_FINDER_MAIN_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "search.hpp"
|
||||
#include "filename_less.hpp"
|
||||
#include <map>
|
||||
#include <components/files/multidircollection.hpp>
|
||||
|
||||
namespace FileFinder
|
||||
{
|
||||
|
@ -11,7 +13,8 @@ namespace FileFinder
|
|||
template <typename LESS>
|
||||
class FileFinderT
|
||||
{
|
||||
std::map<std::string, std::string, LESS> table;
|
||||
typedef std::map<std::string, std::string, LESS> TableContainer;
|
||||
TableContainer table;
|
||||
|
||||
struct Inserter : ReturnPath
|
||||
{
|
||||
|
@ -35,12 +38,12 @@ public:
|
|||
|
||||
// Remember the original path length, so we can cut it away from
|
||||
// the relative paths used as keys
|
||||
std::string pstring = path.string();
|
||||
const std::string& pstring = path.string();
|
||||
inserter.cut = pstring.size();
|
||||
|
||||
// If the path does not end in a slash, then boost will add one
|
||||
// later, which means one more character we have to remove.
|
||||
char last = pstring[pstring.size()-1];
|
||||
char last = *pstring.rbegin();
|
||||
if(last != '\\' && last != '/')
|
||||
inserter.cut++;
|
||||
|
||||
|
@ -56,12 +59,84 @@ public:
|
|||
// Find the full path from a relative path.
|
||||
const std::string &lookup(const std::string& file) const
|
||||
{
|
||||
return table.find(file)->second;
|
||||
static std::string empty;
|
||||
typename TableContainer::const_iterator it = table.find(file);
|
||||
return (it != table.end()) ? it->second : empty;
|
||||
}
|
||||
};
|
||||
|
||||
template
|
||||
<
|
||||
class LESS
|
||||
>
|
||||
struct TreeFileFinder
|
||||
{
|
||||
typedef TreeFileFinder<LESS> finder_t;
|
||||
|
||||
TreeFileFinder(const Files::PathContainer& paths, bool recurse = true)
|
||||
{
|
||||
struct : ReturnPath
|
||||
{
|
||||
finder_t *owner;
|
||||
int cut;
|
||||
|
||||
void add(const boost::filesystem::path &pth)
|
||||
{
|
||||
std::string file = pth.string();
|
||||
std::string key = file.substr(cut);
|
||||
owner->mTable[key] = file;
|
||||
}
|
||||
} inserter;
|
||||
|
||||
inserter.owner = this;
|
||||
|
||||
for (Files::PathContainer::const_iterator it = paths.begin(); it != paths.end(); ++it)
|
||||
{
|
||||
|
||||
// Remember the original path length, so we can cut it away from
|
||||
// the relative paths used as keys
|
||||
const std::string& pstring = it->string();
|
||||
inserter.cut = pstring.size();
|
||||
|
||||
// If the path does not end in a slash, then boost will add one
|
||||
// later, which means one more character we have to remove.
|
||||
char last = *pstring.rbegin();
|
||||
if (last != '\\' && last != '/')
|
||||
{
|
||||
inserter.cut++;
|
||||
}
|
||||
|
||||
// Fill the map
|
||||
find(*it, inserter, recurse);
|
||||
}
|
||||
}
|
||||
|
||||
bool has(const std::string& file) const
|
||||
{
|
||||
return mTable.find(file) != mTable.end();
|
||||
}
|
||||
|
||||
const std::string& lookup(const std::string& file) const
|
||||
{
|
||||
static std::string empty;
|
||||
typename TableContainer::const_iterator it = mTable.find(file);
|
||||
return (it != mTable.end()) ? it->second : empty;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, std::string, LESS> TableContainer;
|
||||
TableContainer mTable;
|
||||
|
||||
// Inserter inserter;
|
||||
};
|
||||
|
||||
|
||||
// The default is to use path_less for equality checks
|
||||
typedef FileFinderT<path_less> FileFinder;
|
||||
typedef FileFinderT<path_slash> FileFinderStrict;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef TreeFileFinder<path_less> LessTreeFileFinder;
|
||||
typedef TreeFileFinder<path_slash> StrictTreeFileFinder;
|
||||
|
||||
} /* namespace FileFinder */
|
||||
#endif /* FILE_FINDER_MAIN_H */
|
||||
|
|
|
@ -2,27 +2,35 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::filesystem;
|
||||
|
||||
void FileFinder::find(const path & dir_path, ReturnPath &ret, bool recurse)
|
||||
void FileFinder::find(const boost::filesystem::path & dir_path, ReturnPath &ret, bool recurse)
|
||||
{
|
||||
if ( !exists( dir_path ) )
|
||||
if (boost::filesystem::exists(dir_path))
|
||||
{
|
||||
cout << "Path " << dir_path << " not found\n";
|
||||
return;
|
||||
}
|
||||
|
||||
directory_iterator end_itr; // default construction yields past-the-end
|
||||
for ( directory_iterator itr(dir_path);
|
||||
itr != end_itr;
|
||||
++itr )
|
||||
{
|
||||
if ( is_directory( *itr ) )
|
||||
if (!recurse)
|
||||
{
|
||||
if(recurse) find(*itr, ret);
|
||||
boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
|
||||
for (boost::filesystem::directory_iterator itr(dir_path); itr != end_itr; ++itr)
|
||||
{
|
||||
if (!boost::filesystem::is_directory( *itr ))
|
||||
{
|
||||
ret.add(*itr);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ret.add(*itr);
|
||||
else
|
||||
{
|
||||
boost::filesystem::recursive_directory_iterator end_itr; // default construction yields past-the-end
|
||||
for (boost::filesystem::recursive_directory_iterator itr(dir_path); itr != end_itr; ++itr)
|
||||
{
|
||||
if (!boost::filesystem::is_directory(*itr))
|
||||
{
|
||||
ret.add(*itr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Path " << dir_path << " not found" << std::endl;
|
||||
}
|
||||
}
|
||||
|
|
182
components/files/configurationmanager.cpp
Normal file
182
components/files/configurationmanager.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
#include "configurationmanager.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/algorithm/string/erase.hpp>
|
||||
|
||||
/**
|
||||
* \namespace Files
|
||||
*/
|
||||
namespace Files
|
||||
{
|
||||
|
||||
static const char* const openmwCfgFile = "openmw.cfg";
|
||||
static const char* const ogreCfgFile = "ogre.cfg";
|
||||
static const char* const pluginsCfgFile = "plugins.cfg";
|
||||
|
||||
const char* const mwToken = "?mw?";
|
||||
const char* const localToken = "?local?";
|
||||
const char* const userToken = "?user?";
|
||||
const char* const globalToken = "?global?";
|
||||
|
||||
ConfigurationManager::ConfigurationManager()
|
||||
: mFixedPath("openmw")
|
||||
{
|
||||
setupTokensMapping();
|
||||
|
||||
mPluginsCfgPath = mFixedPath.getGlobalPath() / pluginsCfgFile;
|
||||
if (!boost::filesystem::is_regular_file(mPluginsCfgPath))
|
||||
{
|
||||
mPluginsCfgPath = mFixedPath.getLocalPath() / pluginsCfgFile;
|
||||
if (!boost::filesystem::is_regular_file(mPluginsCfgPath))
|
||||
{
|
||||
std::cerr << "Failed to find " << pluginsCfgFile << " file!" << std::endl;
|
||||
mPluginsCfgPath.clear();
|
||||
}
|
||||
}
|
||||
|
||||
mOgreCfgPath = mFixedPath.getUserPath() / ogreCfgFile;
|
||||
mLogPath = mFixedPath.getUserPath();
|
||||
}
|
||||
|
||||
ConfigurationManager::~ConfigurationManager()
|
||||
{
|
||||
}
|
||||
|
||||
void ConfigurationManager::setupTokensMapping()
|
||||
{
|
||||
mTokensMapping.insert(std::make_pair(mwToken, &FixedPath<>::getInstallPath));
|
||||
mTokensMapping.insert(std::make_pair(localToken, &FixedPath<>::getLocalPath));
|
||||
mTokensMapping.insert(std::make_pair(userToken, &FixedPath<>::getUserPath));
|
||||
mTokensMapping.insert(std::make_pair(globalToken, &FixedPath<>::getGlobalDataPath));
|
||||
}
|
||||
|
||||
void ConfigurationManager::readConfiguration(boost::program_options::variables_map& variables,
|
||||
boost::program_options::options_description& description)
|
||||
{
|
||||
loadConfig(mFixedPath.getUserPath(), variables, description);
|
||||
boost::program_options::notify(variables);
|
||||
|
||||
loadConfig(mFixedPath.getLocalPath(), variables, description);
|
||||
boost::program_options::notify(variables);
|
||||
loadConfig(mFixedPath.getGlobalPath(), variables, description);
|
||||
boost::program_options::notify(variables);
|
||||
|
||||
}
|
||||
|
||||
void ConfigurationManager::processPaths(Files::PathContainer& dataDirs)
|
||||
{
|
||||
std::string path;
|
||||
for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it)
|
||||
{
|
||||
path = it->string();
|
||||
boost::erase_all(path, "\"");
|
||||
*it = boost::filesystem::path(path);
|
||||
|
||||
// Check if path contains a token
|
||||
if (!path.empty() && *path.begin() == '?')
|
||||
{
|
||||
std::string::size_type pos = path.find('?', 1);
|
||||
if (pos != std::string::npos && pos != 0)
|
||||
{
|
||||
TokensMappingContainer::iterator tokenIt = mTokensMapping.find(path.substr(0, pos + 1));
|
||||
if (tokenIt != mTokensMapping.end())
|
||||
{
|
||||
boost::filesystem::path tempPath(((mFixedPath).*(tokenIt->second))());
|
||||
if (pos < path.length() - 1)
|
||||
{
|
||||
// There is something after the token, so we should
|
||||
// append it to the path
|
||||
tempPath /= path.substr(pos + 1, path.length() - pos);
|
||||
}
|
||||
|
||||
*it = tempPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Clean invalid / unknown token, it will be removed outside the loop
|
||||
(*it).clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!boost::filesystem::is_directory(*it))
|
||||
{
|
||||
(*it).clear();
|
||||
}
|
||||
}
|
||||
|
||||
dataDirs.erase(std::remove_if(dataDirs.begin(), dataDirs.end(),
|
||||
boost::bind(&boost::filesystem::path::empty, _1)), dataDirs.end());
|
||||
}
|
||||
|
||||
void ConfigurationManager::loadConfig(const boost::filesystem::path& path,
|
||||
boost::program_options::variables_map& variables,
|
||||
boost::program_options::options_description& description)
|
||||
{
|
||||
boost::filesystem::path cfgFile(path);
|
||||
cfgFile /= std::string(openmwCfgFile);
|
||||
if (boost::filesystem::is_regular_file(cfgFile))
|
||||
{
|
||||
std::cout << "Loading config file: " << cfgFile.string() << "... ";
|
||||
|
||||
std::ifstream configFileStream(cfgFile.string().c_str());
|
||||
if (configFileStream.is_open())
|
||||
{
|
||||
boost::program_options::store(boost::program_options::parse_config_file(
|
||||
configFileStream, description, true), variables);
|
||||
|
||||
std::cout << "done." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "failed." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getGlobalPath() const
|
||||
{
|
||||
return mFixedPath.getGlobalPath();
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getUserPath() const
|
||||
{
|
||||
return mFixedPath.getUserPath();
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getLocalPath() const
|
||||
{
|
||||
return mFixedPath.getLocalPath();
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getGlobalDataPath() const
|
||||
{
|
||||
return mFixedPath.getGlobalDataPath();
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getInstallPath() const
|
||||
{
|
||||
return mFixedPath.getInstallPath();
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getOgreConfigPath() const
|
||||
{
|
||||
return mOgreCfgPath;
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getPluginsConfigPath() const
|
||||
{
|
||||
return mPluginsCfgPath;
|
||||
}
|
||||
|
||||
const boost::filesystem::path& ConfigurationManager::getLogPath() const
|
||||
{
|
||||
return mLogPath;
|
||||
}
|
||||
|
||||
} /* namespace Cfg */
|
71
components/files/configurationmanager.hpp
Normal file
71
components/files/configurationmanager.hpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
#ifndef COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP
|
||||
#define COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <boost/tr1/tr1/unordered_map>
|
||||
#else
|
||||
#include <tr1/unordered_map>
|
||||
#endif
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <components/files/fixedpath.hpp>
|
||||
#include <components/files/collections.hpp>
|
||||
|
||||
/**
|
||||
* \namespace Files
|
||||
*/
|
||||
namespace Files
|
||||
{
|
||||
|
||||
/**
|
||||
* \struct ConfigurationManager
|
||||
*/
|
||||
struct ConfigurationManager
|
||||
{
|
||||
ConfigurationManager();
|
||||
virtual ~ConfigurationManager();
|
||||
|
||||
void readConfiguration(boost::program_options::variables_map& variables,
|
||||
boost::program_options::options_description& description);
|
||||
void processPaths(Files::PathContainer& dataDirs);
|
||||
|
||||
/**< Fixed paths */
|
||||
const boost::filesystem::path& getGlobalPath() const;
|
||||
const boost::filesystem::path& getUserPath() const;
|
||||
const boost::filesystem::path& getLocalPath() const;
|
||||
|
||||
const boost::filesystem::path& getGlobalDataPath() const;
|
||||
const boost::filesystem::path& getUserDataPath() const;
|
||||
const boost::filesystem::path& getLocalDataPath() const;
|
||||
const boost::filesystem::path& getInstallPath() const;
|
||||
|
||||
const boost::filesystem::path& getOgreConfigPath() const;
|
||||
const boost::filesystem::path& getPluginsConfigPath() const;
|
||||
const boost::filesystem::path& getLogPath() const;
|
||||
|
||||
private:
|
||||
typedef Files::FixedPath<> FixedPathType;
|
||||
|
||||
typedef const boost::filesystem::path& (FixedPathType::*path_type_f)() const;
|
||||
typedef std::tr1::unordered_map<std::string, path_type_f> TokensMappingContainer;
|
||||
|
||||
void loadConfig(const boost::filesystem::path& path,
|
||||
boost::program_options::variables_map& variables,
|
||||
boost::program_options::options_description& description);
|
||||
|
||||
void setupTokensMapping();
|
||||
|
||||
FixedPathType mFixedPath;
|
||||
|
||||
boost::filesystem::path mOgreCfgPath;
|
||||
boost::filesystem::path mPluginsCfgPath;
|
||||
boost::filesystem::path mLogPath;
|
||||
|
||||
TokensMappingContainer mTokensMapping;
|
||||
};
|
||||
|
||||
} /* namespace Cfg */
|
||||
|
||||
#endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */
|
145
components/files/fixedpath.hpp
Normal file
145
components/files/fixedpath.hpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
/**
|
||||
* Open Morrowind - an opensource Elder Scrolls III: Morrowind
|
||||
* engine implementation.
|
||||
*
|
||||
* Copyright (C) 2011 Open Morrowind Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** \file components/files/fixedpath.hpp */
|
||||
|
||||
#ifndef COMPONENTS_FILES_FIXEDPATH_HPP
|
||||
#define COMPONENTS_FILES_FIXEDPATH_HPP
|
||||
|
||||
#include <string>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
#include <components/files/linuxpath.hpp>
|
||||
namespace Files { typedef LinuxPath TargetPathType; }
|
||||
|
||||
#elif defined(__WIN32) || defined(__WINDOWS__) || defined(_WIN32)
|
||||
#include <components/files/windowspath.hpp>
|
||||
namespace Files { typedef WindowsPath TargetPathType; }
|
||||
|
||||
#elif defined(macintosh) || defined(Macintosh) || defined(__APPLE__) || defined(__MACH__)
|
||||
#include <components/files/macospath.hpp>
|
||||
namespace Files { typedef MacOsPath TargetPathType; }
|
||||
|
||||
#else
|
||||
#error "Unknown platform!"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* \namespace Files
|
||||
*/
|
||||
namespace Files
|
||||
{
|
||||
|
||||
/**
|
||||
* \struct Path
|
||||
*
|
||||
* \tparam P - Path strategy class type (depends on target system)
|
||||
*
|
||||
*/
|
||||
template
|
||||
<
|
||||
class P = TargetPathType
|
||||
>
|
||||
struct FixedPath
|
||||
{
|
||||
typedef P PathType;
|
||||
|
||||
/**
|
||||
* \brief Path constructor.
|
||||
*
|
||||
* \param [in] application_name - Name of the application
|
||||
*/
|
||||
FixedPath(const std::string& application_name)
|
||||
: mPath()
|
||||
, mUserPath(mPath.getUserPath())
|
||||
, mGlobalPath(mPath.getGlobalPath())
|
||||
, mLocalPath(mPath.getLocalPath())
|
||||
, mGlobalDataPath(mPath.getGlobalDataPath())
|
||||
, mInstallPath(mPath.getInstallPath())
|
||||
{
|
||||
if (!application_name.empty())
|
||||
{
|
||||
boost::filesystem::path suffix(application_name + std::string("/"));
|
||||
|
||||
mUserPath /= suffix;
|
||||
mGlobalPath /= suffix;
|
||||
mGlobalDataPath /= suffix;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return path pointing to the user local configuration directory.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
const boost::filesystem::path& getUserPath() const
|
||||
{
|
||||
return mUserPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return path pointing to the global (system) configuration directory.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
const boost::filesystem::path& getGlobalPath() const
|
||||
{
|
||||
return mGlobalPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return path pointing to the directory where application was started.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
const boost::filesystem::path& getLocalPath() const
|
||||
{
|
||||
return mLocalPath;
|
||||
}
|
||||
|
||||
const boost::filesystem::path& getInstallPath() const
|
||||
{
|
||||
return mInstallPath;
|
||||
}
|
||||
|
||||
const boost::filesystem::path& getGlobalDataPath() const
|
||||
{
|
||||
return mGlobalDataPath;
|
||||
}
|
||||
|
||||
private:
|
||||
PathType mPath;
|
||||
|
||||
boost::filesystem::path mUserPath; /**< User path */
|
||||
boost::filesystem::path mGlobalPath; /**< Global path */
|
||||
boost::filesystem::path mLocalPath; /**< It is the same directory where application was run */
|
||||
|
||||
boost::filesystem::path mGlobalDataPath; /**< Global application data path */
|
||||
|
||||
boost::filesystem::path mInstallPath;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} /* namespace Files */
|
||||
|
||||
#endif /* COMPONENTS_FILES_FIXEDPATH_HPP */
|
|
@ -22,12 +22,13 @@
|
|||
|
||||
#include "linuxpath.hpp"
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
/**
|
||||
* \namespace Files
|
||||
|
@ -35,126 +36,128 @@
|
|||
namespace Files
|
||||
{
|
||||
|
||||
boost::filesystem::path LinuxPath::getLocalConfigPath() const
|
||||
boost::filesystem::path LinuxPath::getUserPath() const
|
||||
{
|
||||
boost::filesystem::path localConfigPath(".");
|
||||
boost::filesystem::path userPath(".");
|
||||
boost::filesystem::path suffix("/");
|
||||
|
||||
const char* theDir = getenv("OPENMW_CONFIG");
|
||||
const char* theDir = getenv("HOME");
|
||||
if (theDir == NULL)
|
||||
{
|
||||
theDir = getenv("XDG_CONFIG_HOME");
|
||||
if (theDir == NULL)
|
||||
struct passwd* pwd = getpwuid(getuid());
|
||||
if (pwd != NULL)
|
||||
{
|
||||
theDir = getenv("HOME");
|
||||
if (theDir == NULL)
|
||||
{
|
||||
struct passwd* pwd = getpwuid(getuid());
|
||||
if (pwd != NULL)
|
||||
{
|
||||
theDir = pwd->pw_dir;
|
||||
}
|
||||
}
|
||||
if (theDir != NULL)
|
||||
{
|
||||
suffix = boost::filesystem::path("/.config/");
|
||||
}
|
||||
theDir = pwd->pw_dir;
|
||||
}
|
||||
}
|
||||
|
||||
if (theDir != NULL) {
|
||||
localConfigPath = boost::filesystem::path(theDir);
|
||||
}
|
||||
|
||||
localConfigPath /= suffix;
|
||||
|
||||
return localConfigPath;
|
||||
}
|
||||
|
||||
boost::filesystem::path LinuxPath::getGlobalConfigPath() const
|
||||
{
|
||||
boost::filesystem::path globalConfigPath("/etc/xdg/");
|
||||
|
||||
char* theDir = getenv("XDG_CONFIG_DIRS");
|
||||
if (theDir != NULL)
|
||||
{
|
||||
// We take only first path from list
|
||||
char* ptr = strtok(theDir, ":");
|
||||
if (ptr != NULL)
|
||||
{
|
||||
globalConfigPath = boost::filesystem::path(ptr);
|
||||
globalConfigPath /= boost::filesystem::path("/");
|
||||
}
|
||||
suffix = boost::filesystem::path("/.config/");
|
||||
userPath = boost::filesystem::path(theDir);
|
||||
}
|
||||
|
||||
return globalConfigPath;
|
||||
userPath /= suffix;
|
||||
|
||||
return userPath;
|
||||
}
|
||||
|
||||
boost::filesystem::path LinuxPath::getRuntimeConfigPath() const
|
||||
boost::filesystem::path LinuxPath::getGlobalPath() const
|
||||
{
|
||||
boost::filesystem::path globalPath("/etc/");
|
||||
return globalPath;
|
||||
}
|
||||
|
||||
boost::filesystem::path LinuxPath::getLocalPath() const
|
||||
{
|
||||
return boost::filesystem::path("./");
|
||||
}
|
||||
|
||||
boost::filesystem::path LinuxPath::getLocalDataPath() const
|
||||
{
|
||||
boost::filesystem::path localDataPath(".");
|
||||
boost::filesystem::path suffix("/");
|
||||
|
||||
const char* theDir = getenv("OPENMW_DATA");
|
||||
if (theDir == NULL)
|
||||
{
|
||||
theDir = getenv("XDG_DATA_HOME");
|
||||
if (theDir == NULL)
|
||||
{
|
||||
theDir = getenv("HOME");
|
||||
if (theDir == NULL)
|
||||
{
|
||||
struct passwd* pwd = getpwuid(getuid());
|
||||
if (pwd != NULL)
|
||||
{
|
||||
theDir = pwd->pw_dir;
|
||||
}
|
||||
}
|
||||
if (theDir != NULL)
|
||||
{
|
||||
suffix = boost::filesystem::path("/.local/share/");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (theDir != NULL) {
|
||||
localDataPath = boost::filesystem::path(theDir);
|
||||
}
|
||||
|
||||
localDataPath /= suffix;
|
||||
return localDataPath;
|
||||
}
|
||||
|
||||
boost::filesystem::path LinuxPath::getGlobalDataPath() const
|
||||
{
|
||||
boost::filesystem::path globalDataPath("/usr/local/share/");
|
||||
|
||||
char* theDir = getenv("XDG_DATA_DIRS");
|
||||
if (theDir != NULL)
|
||||
{
|
||||
// We take only first path from list
|
||||
char* ptr = strtok(theDir, ":");
|
||||
if (ptr != NULL)
|
||||
{
|
||||
globalDataPath = boost::filesystem::path(ptr);
|
||||
globalDataPath /= boost::filesystem::path("/");
|
||||
}
|
||||
}
|
||||
|
||||
boost::filesystem::path globalDataPath("/usr/share/games/");
|
||||
return globalDataPath;
|
||||
}
|
||||
|
||||
boost::filesystem::path LinuxPath::getRuntimeDataPath() const
|
||||
boost::filesystem::path LinuxPath::getInstallPath() const
|
||||
{
|
||||
return boost::filesystem::path("./data/");
|
||||
}
|
||||
boost::filesystem::path installPath;
|
||||
|
||||
char *homePath = getenv("HOME");
|
||||
if (homePath == NULL)
|
||||
{
|
||||
struct passwd* pwd = getpwuid(getuid());
|
||||
if (pwd != NULL)
|
||||
{
|
||||
homePath = pwd->pw_dir;
|
||||
}
|
||||
}
|
||||
|
||||
if (homePath != NULL)
|
||||
{
|
||||
boost::filesystem::path wineDefaultRegistry(homePath);
|
||||
wineDefaultRegistry /= ".wine/system.reg";
|
||||
|
||||
if (boost::filesystem::is_regular_file(wineDefaultRegistry))
|
||||
{
|
||||
boost::filesystem::ifstream file(wineDefaultRegistry);
|
||||
bool isRegEntry = false;
|
||||
std::string line;
|
||||
std::string mwpath;
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line[0] == '[') // we found an entry
|
||||
{
|
||||
if (isRegEntry)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
isRegEntry = (line.find("Softworks\\\\Morrowind]") != std::string::npos);
|
||||
}
|
||||
else if (isRegEntry)
|
||||
{
|
||||
if (line[0] == '"') // empty line means new registry key
|
||||
{
|
||||
std::string key = line.substr(1, line.find('"', 1) - 1);
|
||||
if (strcasecmp(key.c_str(), "Installed Path") == 0)
|
||||
{
|
||||
std::string::size_type valuePos = line.find('=') + 2;
|
||||
mwpath = line.substr(valuePos, line.rfind('"') - valuePos);
|
||||
|
||||
std::string::size_type pos = mwpath.find("\\");
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
mwpath.replace(pos, 2, "/");
|
||||
pos = mwpath.find("\\", pos + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mwpath.empty())
|
||||
{
|
||||
// Change drive letter to lowercase, so we could use
|
||||
// ~/.wine/dosdevices symlinks
|
||||
mwpath[0] = tolower(mwpath[0]);
|
||||
installPath /= homePath;
|
||||
installPath /= ".wine/dosdevices/";
|
||||
installPath /= mwpath;
|
||||
|
||||
if (!boost::filesystem::is_directory(installPath))
|
||||
{
|
||||
installPath.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return installPath;
|
||||
}
|
||||
|
||||
} /* namespace Files */
|
||||
|
||||
#endif /* defined(__linux__) */
|
||||
#endif /* defined(__linux__) || defined(__FreeBSD__) */
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#ifndef COMPONENTS_FILES_LINUXPATH_H
|
||||
#define COMPONENTS_FILES_LINUXPATH_H
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
|
@ -39,18 +39,18 @@ namespace Files
|
|||
struct LinuxPath
|
||||
{
|
||||
/**
|
||||
* \brief Return path to the local configuration directory.
|
||||
* \brief Return path to the user directory.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getLocalConfigPath() const;
|
||||
boost::filesystem::path getUserPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return path to the global (system) configuration directory.
|
||||
* \brief Return path to the global (system) directory where game files could be placed.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getGlobalConfigPath() const;
|
||||
boost::filesystem::path getGlobalPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return path to the runtime configuration directory which is the
|
||||
|
@ -58,33 +58,25 @@ struct LinuxPath
|
|||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getRuntimeConfigPath() const;
|
||||
boost::filesystem::path getLocalPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return path to the local data directory.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getLocalDataPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return path to the global (system) data directory.
|
||||
* \brief
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getGlobalDataPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return runtime data path which is a location where
|
||||
* an application was started with 'data' suffix.
|
||||
* \brief Gets the path of the installed Morrowind version if there is one.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getRuntimeDataPath() const;
|
||||
boost::filesystem::path getInstallPath() const;
|
||||
};
|
||||
|
||||
} /* namespace Files */
|
||||
|
||||
#endif /* defined(__linux__) */
|
||||
#endif /* defined(__linux__) || defined(__FreeBSD__) */
|
||||
|
||||
#endif /* COMPONENTS_FILES_LINUXPATH_H */
|
||||
|
|
|
@ -27,6 +27,11 @@
|
|||
#include <cstdlib>
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
||||
/**
|
||||
* FIXME: Someone with MacOS system should check this and correct if necessary
|
||||
*/
|
||||
|
||||
/**
|
||||
* \namespace Files
|
||||
|
@ -34,9 +39,9 @@
|
|||
namespace Files
|
||||
{
|
||||
|
||||
boost::filesystem::path MacOsPath::getLocalConfigPath() const
|
||||
boost::filesystem::path MacOsPath::getUserPath() const
|
||||
{
|
||||
boost::filesystem::path localConfigPath(".");
|
||||
boost::filesystem::path userPath(".");
|
||||
boost::filesystem::path suffix("/");
|
||||
|
||||
const char* theDir = getenv("HOME");
|
||||
|
@ -50,66 +55,107 @@ boost::filesystem::path MacOsPath::getLocalConfigPath() const
|
|||
}
|
||||
if (theDir != NULL)
|
||||
{
|
||||
localConfigPath = boost::filesystem::path(theDir) / "Library/Preferences/";
|
||||
userPath = boost::filesystem::path(theDir) / "Library/Preferences/";
|
||||
}
|
||||
|
||||
localConfigPath /= suffix;
|
||||
userPath /= suffix;
|
||||
|
||||
return localConfigPath;
|
||||
return userPath;
|
||||
}
|
||||
|
||||
boost::filesystem::path MacOsPath::getGlobalConfigPath() const
|
||||
boost::filesystem::path MacOsPath::getGlobalPath() const
|
||||
{
|
||||
boost::filesystem::path globalConfigPath("/Library/Preferences/");
|
||||
return globalConfigPath;
|
||||
boost::filesystem::path globalPath("/Library/Preferences/");
|
||||
return globalPath;
|
||||
}
|
||||
|
||||
boost::filesystem::path MacOsPath::getRuntimeConfigPath() const
|
||||
boost::filesystem::path MacOsPath::getLocalPath() const
|
||||
{
|
||||
return boost::filesystem::path("./");
|
||||
}
|
||||
|
||||
boost::filesystem::path MacOsPath::getLocalDataPath() const
|
||||
{
|
||||
boost::filesystem::path localDataPath(".");
|
||||
boost::filesystem::path suffix("/");
|
||||
|
||||
const char* theDir = getenv("OPENMW_DATA");
|
||||
if (theDir == NULL)
|
||||
{
|
||||
theDir = getenv("HOME");
|
||||
if (theDir == NULL)
|
||||
{
|
||||
struct passwd* pwd = getpwuid(getuid());
|
||||
if (pwd != NULL)
|
||||
{
|
||||
theDir = pwd->pw_dir;
|
||||
}
|
||||
}
|
||||
if (theDir != NULL)
|
||||
{
|
||||
suffix = boost::filesystem::path("/Library/Application Support/");
|
||||
}
|
||||
}
|
||||
|
||||
if (theDir != NULL)
|
||||
{
|
||||
localDataPath = boost::filesystem::path(theDir);
|
||||
}
|
||||
|
||||
localDataPath /= suffix;
|
||||
return localDataPath;
|
||||
}
|
||||
|
||||
boost::filesystem::path MacOsPath::getGlobalDataPath() const
|
||||
{
|
||||
boost::filesystem::path globalDataPath("/Library/Application Support/");
|
||||
return globalDataPath;
|
||||
}
|
||||
|
||||
boost::filesystem::path MacOsPath::getRuntimeDataPath() const
|
||||
boost::filesystem::path MacOsPath::getInstallPath() const
|
||||
{
|
||||
return boost::filesystem::path("./data/");
|
||||
boost::filesystem::path installPath;
|
||||
|
||||
char *homePath = getenv("HOME");
|
||||
if (homePath == NULL)
|
||||
{
|
||||
struct passwd* pwd = getpwuid(getuid());
|
||||
if (pwd != NULL)
|
||||
{
|
||||
homePath = pwd->pw_dir;
|
||||
}
|
||||
}
|
||||
|
||||
if (homePath != NULL)
|
||||
{
|
||||
boost::filesystem::path wineDefaultRegistry(homePath);
|
||||
wineDefaultRegistry /= ".wine/system.reg";
|
||||
|
||||
if (boost::filesystem::is_regular_file(wineDefaultRegistry))
|
||||
{
|
||||
boost::filesystem::ifstream file(wineDefaultRegistry);
|
||||
bool isRegEntry = false;
|
||||
std::string line;
|
||||
std::string mwpath;
|
||||
|
||||
while (std::getline(file, line))
|
||||
{
|
||||
if (line[0] == '[') // we found an entry
|
||||
{
|
||||
if (isRegEntry)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
isRegEntry = (line.find("Softworks\\\\Morrowind]") != std::string::npos);
|
||||
}
|
||||
else if (isRegEntry)
|
||||
{
|
||||
if (line[0] == '"') // empty line means new registry key
|
||||
{
|
||||
std::string key = line.substr(1, line.find('"', 1) - 1);
|
||||
if (strcasecmp(key.c_str(), "Installed Path") == 0)
|
||||
{
|
||||
std::string::size_type valuePos = line.find('=') + 2;
|
||||
mwpath = line.substr(valuePos, line.rfind('"') - valuePos);
|
||||
|
||||
std::string::size_type pos = mwpath.find("\\");
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
mwpath.replace(pos, 2, "/");
|
||||
pos = mwpath.find("\\", pos + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mwpath.empty())
|
||||
{
|
||||
// Change drive letter to lowercase, so we could use ~/.wine/dosdevice symlinks
|
||||
mwpath[0] = tolower(mwpath[0]);
|
||||
installPath /= homePath;
|
||||
installPath /= ".wine/dosdevices/";
|
||||
installPath /= mwpath;
|
||||
|
||||
if (!boost::filesystem::is_directory(installPath))
|
||||
{
|
||||
installPath.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return installPath;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -39,48 +39,35 @@ namespace Files
|
|||
struct MacOsPath
|
||||
{
|
||||
/**
|
||||
* \brief Return path to the local configuration directory.
|
||||
* \brief Return path to the local directory.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getLocalConfigPath() const;
|
||||
boost::filesystem::path getUserPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return path to the global (system) configuration directory.
|
||||
* \brief Return path to the global (system) directory.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getGlobalConfigPath() const;
|
||||
boost::filesystem::path getGlobalPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return path to the runtime configuration directory which is the
|
||||
* \brief Return path to the runtime directory which is the
|
||||
* place where an application was started.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getRuntimeConfigPath() const;
|
||||
boost::filesystem::path getLocalPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return path to the local data directory.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getLocalDataPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return path to the global (system) data directory.
|
||||
* \brief
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getGlobalDataPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return runtime data path which is a location where
|
||||
* an application was started with 'data' suffix.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getRuntimeDataPath() const;
|
||||
boost::filesystem::path getInstallPath() const;
|
||||
};
|
||||
|
||||
} /* namespace Files */
|
||||
|
|
|
@ -68,7 +68,7 @@ namespace Files
|
|||
/// \param foldCase Ignore filename case
|
||||
|
||||
boost::filesystem::path getPath (const std::string& file) const;
|
||||
///< Return full path (including filename) of \æ file.
|
||||
///< Return full path (including filename) of \a file.
|
||||
///
|
||||
/// If the file does not exist, an exception is thrown. \a file must include
|
||||
/// the extension.
|
||||
|
|
|
@ -1,232 +0,0 @@
|
|||
/**
|
||||
* Open Morrowind - an opensource Elder Scrolls III: Morrowind
|
||||
* engine implementation.
|
||||
*
|
||||
* Copyright (C) 2011 Open Morrowind Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** \file components/files/path.hpp */
|
||||
|
||||
#ifndef COMPONENTS_FILES_PATH_HPP
|
||||
#define COMPONENTS_FILES_PATH_HPP
|
||||
|
||||
#include <string>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <components/files/linuxpath.hpp>
|
||||
namespace Files { typedef LinuxPath TargetPathType; }
|
||||
|
||||
#elif defined(__WIN32) || defined(__WINDOWS__) || defined (_WINDOWS)
|
||||
#include <components/files/windowspath.hpp>
|
||||
namespace Files { typedef WindowsPath TargetPathType; }
|
||||
|
||||
#elif defined(macintosh) || defined(Macintosh) || defined(__APPLE__) || defined(__MACH__)
|
||||
#include <components/files/macospath.hpp>
|
||||
namespace Files { typedef MacOsPath TargetPathType; }
|
||||
|
||||
#else
|
||||
#error "Unknown platform!"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* \namespace Files
|
||||
*/
|
||||
namespace Files
|
||||
{
|
||||
|
||||
/**
|
||||
* \struct Path
|
||||
*
|
||||
* \tparam P - Path strategy class type (depends on target system)
|
||||
*
|
||||
*/
|
||||
template
|
||||
<
|
||||
class P = TargetPathType
|
||||
>
|
||||
struct Path
|
||||
{
|
||||
typedef P PathType;
|
||||
|
||||
/**
|
||||
* \brief Path constructor.
|
||||
*
|
||||
* \param [in] application_name - Name of the application
|
||||
*/
|
||||
Path(const std::string& application_name)
|
||||
: mPath()
|
||||
, mLocalConfigPath(mPath.getLocalConfigPath())
|
||||
, mGlobalConfigPath(mPath.getGlobalConfigPath())
|
||||
, mRuntimeConfigPath(mPath.getRuntimeConfigPath())
|
||||
, mLocalDataPath(mPath.getLocalDataPath())
|
||||
, mGlobalDataPath(mPath.getGlobalDataPath())
|
||||
, mRuntimeDataPath(mPath.getRuntimeDataPath())
|
||||
{
|
||||
if (!application_name.empty())
|
||||
{
|
||||
boost::filesystem::path suffix(application_name + std::string("/"));
|
||||
|
||||
mLocalConfigPath /= suffix;
|
||||
mGlobalConfigPath /= suffix;
|
||||
|
||||
mLocalDataPath /= suffix;
|
||||
mGlobalDataPath /= suffix;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return path pointing to the user local configuration directory.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
const boost::filesystem::path& getLocalConfigPath() const
|
||||
{
|
||||
return mLocalConfigPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets new local configuration path.
|
||||
*
|
||||
* \param [in] path - New path
|
||||
*/
|
||||
void setLocalConfigPath(const boost::filesystem::path& path)
|
||||
{
|
||||
mLocalConfigPath = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return path pointing to the global (system) configuration directory.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
const boost::filesystem::path& getGlobalConfigPath() const
|
||||
{
|
||||
return mGlobalConfigPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets new global configuration path.
|
||||
*
|
||||
* \param [in] path - New path
|
||||
*/
|
||||
void setGlobalConfigPath(const boost::filesystem::path& path)
|
||||
{
|
||||
mGlobalConfigPath = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return path pointing to the directory where application was started.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
const boost::filesystem::path& getRuntimeConfigPath() const
|
||||
{
|
||||
return mRuntimeConfigPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets new runtime configuration path.
|
||||
*
|
||||
* \param [in] path - New path
|
||||
*/
|
||||
void setRuntimeConfigPath(const boost::filesystem::path& path)
|
||||
{
|
||||
mRuntimeConfigPath = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return path pointing to the user local data directory.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
const boost::filesystem::path& getLocalDataPath() const
|
||||
{
|
||||
return mLocalDataPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets new local data path.
|
||||
*
|
||||
* \param [in] path - New path
|
||||
*/
|
||||
void setLocalDataPath(const boost::filesystem::path& path)
|
||||
{
|
||||
mLocalDataPath = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return path pointing to the global (system) data directory.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
const boost::filesystem::path& getGlobalDataPath() const
|
||||
{
|
||||
return mGlobalDataPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets new global (system) data directory.
|
||||
*
|
||||
* \param [in] path - New path
|
||||
*/
|
||||
void setGlobalDataPath(const boost::filesystem::path& path)
|
||||
{
|
||||
mGlobalDataPath = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return path pointing to the directory where application was started.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
const boost::filesystem::path& getRuntimeDataPath() const
|
||||
{
|
||||
return mRuntimeDataPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets new runtime data directory.
|
||||
*
|
||||
* \param [in] path - New path
|
||||
*/
|
||||
void setRuntimeDataPath(const boost::filesystem::path& path)
|
||||
{
|
||||
mRuntimeDataPath = path;
|
||||
}
|
||||
|
||||
private:
|
||||
PathType mPath;
|
||||
|
||||
boost::filesystem::path mLocalConfigPath; /**< User local path to the configuration files */
|
||||
boost::filesystem::path mGlobalConfigPath; /**< Global path to the configuration files */
|
||||
boost::filesystem::path mRuntimeConfigPath; /**< Runtime path to the configuration files.
|
||||
By default it is the same directory where
|
||||
application was run */
|
||||
|
||||
boost::filesystem::path mLocalDataPath; /**< User local application data path (user plugins / mods / etc.) */
|
||||
boost::filesystem::path mGlobalDataPath; /**< Global application data path */
|
||||
boost::filesystem::path mRuntimeDataPath; /**< Runtime path to the configuration files.
|
||||
By default it is a 'data' directory in same
|
||||
directory where application was run */
|
||||
|
||||
};
|
||||
|
||||
|
||||
} /* namespace Files */
|
||||
|
||||
#endif /* COMPONENTS_FILES_PATH_HPP */
|
|
@ -10,12 +10,19 @@
|
|||
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
|
||||
/**
|
||||
* FIXME: Someone with Windows system should check this and correct if necessary
|
||||
*/
|
||||
|
||||
/**
|
||||
* \namespace Files
|
||||
*/
|
||||
namespace Files
|
||||
{
|
||||
|
||||
boost::filesystem::path WindowsPath::getLocalConfigPath() const
|
||||
boost::filesystem::path WindowsPath::getUserPath() const
|
||||
{
|
||||
boost::filesystem::path localConfigPath(".");
|
||||
boost::filesystem::path userPath(".");
|
||||
boost::filesystem::path suffix("/");
|
||||
|
||||
TCHAR path[MAX_PATH];
|
||||
|
@ -24,17 +31,17 @@ boost::filesystem::path WindowsPath::getLocalConfigPath() const
|
|||
if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL | CSIDL_FLAG_CREATE, NULL, 0, path)))
|
||||
{
|
||||
PathAppend(path, TEXT("My Games"));
|
||||
localConfigPath = boost::filesystem::path(path);
|
||||
userPath = boost::filesystem::path(path);
|
||||
}
|
||||
|
||||
localConfigPath /= suffix;
|
||||
userPath /= suffix;
|
||||
|
||||
return localConfigPath;
|
||||
return userPath;
|
||||
}
|
||||
|
||||
boost::filesystem::path WindowsPath::getGlobalConfigPath() const
|
||||
boost::filesystem::path WindowsPath::getGlobalPath() const
|
||||
{
|
||||
boost::filesystem::path globalConfigPath(".");
|
||||
boost::filesystem::path globalPath(".");
|
||||
boost::filesystem::path suffix("/");
|
||||
|
||||
TCHAR path[MAX_PATH];
|
||||
|
@ -42,32 +49,54 @@ boost::filesystem::path WindowsPath::getGlobalConfigPath() const
|
|||
|
||||
if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES | CSIDL_FLAG_CREATE, NULL, 0, path)))
|
||||
{
|
||||
globalConfigPath = boost::filesystem::path(path);
|
||||
globalPath = boost::filesystem::path(path);
|
||||
}
|
||||
|
||||
globalConfigPath /= suffix;
|
||||
globalPath /= suffix;
|
||||
|
||||
return globalConfigPath;
|
||||
return globalPath;
|
||||
}
|
||||
|
||||
boost::filesystem::path WindowsPath::getRuntimeConfigPath() const
|
||||
boost::filesystem::path WindowsPath::getLocalPath() const
|
||||
{
|
||||
return boost::filesystem::path("./");
|
||||
}
|
||||
|
||||
boost::filesystem::path WindowsPath::getLocalDataPath() const
|
||||
{
|
||||
return getLocalConfigPath();
|
||||
}
|
||||
|
||||
boost::filesystem::path WindowsPath::getGlobalDataPath() const
|
||||
{
|
||||
return getGlobalConfigPath();
|
||||
return getGlobalPath();
|
||||
}
|
||||
|
||||
boost::filesystem::path WindowsPath::getRuntimeDataPath() const
|
||||
boost::filesystem::path WindowsPath::getInstallPath() const
|
||||
{
|
||||
return boost::filesystem::path("./data/");
|
||||
boost::filesystem::path installPath("");
|
||||
|
||||
HKEY hKey;
|
||||
|
||||
BOOL f64 = FALSE;
|
||||
LPCTSTR regkey;
|
||||
if ((IsWow64Process(GetCurrentProcess(), &f64) && f64) || sizeof(void*) == 8)
|
||||
{
|
||||
regkey = "SOFTWARE\\Wow6432Node\\Bethesda Softworks\\Morrowind";
|
||||
}
|
||||
else
|
||||
{
|
||||
regkey = "SOFTWARE\\Bethesda Softworks\\Morrowind";
|
||||
}
|
||||
|
||||
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT(regkey), 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS)
|
||||
{
|
||||
//Key existed, let's try to read the install dir
|
||||
std::vector<char> buf(512);
|
||||
int len = 512;
|
||||
|
||||
if (RegQueryValueEx(hKey, TEXT("Installed Path"), NULL, NULL, (LPBYTE)&buf[0], (LPDWORD)&len) == ERROR_SUCCESS)
|
||||
{
|
||||
installPath = &buf[0];
|
||||
}
|
||||
}
|
||||
|
||||
return installPath;
|
||||
}
|
||||
|
||||
} /* namespace Files */
|
||||
|
|
|
@ -39,48 +39,41 @@ namespace Files
|
|||
struct WindowsPath
|
||||
{
|
||||
/**
|
||||
* \brief Returns "X:\Documents And Settings\<User name>\My Documents\My Games\"
|
||||
* \brief Returns user path i.e.:
|
||||
* "X:\Documents And Settings\<User name>\My Documents\My Games\"
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getLocalConfigPath() const;
|
||||
boost::filesystem::path getUserPath() const;
|
||||
|
||||
/**
|
||||
* \brief Returns "X:\Program Files\"
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getGlobalConfigPath() const;
|
||||
boost::filesystem::path getGlobalPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return runtime configuration path which is a location where
|
||||
* \brief Return local path which is a location where
|
||||
* an application was started
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getRuntimeConfigPath() const;
|
||||
boost::filesystem::path getLocalPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return same path like getLocalConfigPath
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getLocalDataPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return same path like getGlobalConfigPath
|
||||
* \brief Return same path like getGlobalPath
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getGlobalDataPath() const;
|
||||
|
||||
/**
|
||||
* \brief Return runtime data path which is a location where
|
||||
* an application was started with 'data' suffix.
|
||||
* \brief Gets the path of the installed Morrowind version if there is one.
|
||||
*
|
||||
* \return boost::filesystem::path
|
||||
*/
|
||||
boost::filesystem::path getRuntimeDataPath() const;
|
||||
boost::filesystem::path getInstallPath() const;
|
||||
};
|
||||
|
||||
} /* namespace Files */
|
||||
|
|
|
@ -243,6 +243,8 @@ void NIFLoader::createMaterial(const String &name,
|
|||
/*TextureUnitState *txt =*/
|
||||
pass->createTextureUnitState(texName);
|
||||
|
||||
pass->setVertexColourTracking(TVC_DIFFUSE);
|
||||
|
||||
// As of yet UNTESTED code from Chris:
|
||||
/*pass->setTextureFiltering(Ogre::TFO_ANISOTROPIC);
|
||||
pass->setDepthFunction(Ogre::CMPF_LESS_EQUAL);
|
||||
|
@ -1328,7 +1330,10 @@ void NIFLoader::loadResource(Resource *resource)
|
|||
|
||||
(*iter)->addBoneAssignment(vba);
|
||||
}
|
||||
mesh->_notifySkeleton(mSkel);
|
||||
//Don't link on npc parts to eliminate redundant skeletons
|
||||
//Will have to be changed later slightly for robes/skirts
|
||||
if(triname == "")
|
||||
mesh->_notifySkeleton(mSkel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
data=${MORROWIND_DATA_FILES}
|
||||
data="?mw?Data Files"
|
||||
resources=${MORROWIND_RESOURCE_FILES}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 21b8456453242e132c85f92047cf9bce535c1b22
|
||||
Subproject commit 8f98718315fe11af359740c4a025fd1ca52a9157
|
|
@ -2,13 +2,33 @@
|
|||
#ifndef _STRING_WRAPPER_H
|
||||
#define _STRING_WRAPPER_H
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <Availability.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#if defined(__APPLE__) || defined(__MINGW32__)
|
||||
#if (defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1070) || defined(__MINGW32__)
|
||||
// need our own implementation of strnlen
|
||||
#ifdef __MINGW32__
|
||||
static size_t strnlen(const char *s, size_t n)
|
||||
{
|
||||
const char *p = (const char *)memchr(s, 0, n);
|
||||
return(p ? p-s : n);
|
||||
const char *p = (const char *)memchr(s, 0, n);
|
||||
return(p ? p-s : n);
|
||||
}
|
||||
#elif (defined(__APPLE__) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1070)
|
||||
static size_t mw_strnlen(const char *s, size_t n)
|
||||
{
|
||||
if (strnlen != NULL) {
|
||||
return strnlen(s, n);
|
||||
}
|
||||
else {
|
||||
const char *p = (const char *)memchr(s, 0, n);
|
||||
return(p ? p-s : n);
|
||||
}
|
||||
}
|
||||
#define strnlen mw_strnlen
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
109
readme.txt
109
readme.txt
|
@ -3,7 +3,7 @@ OpenMW: A reimplementation of The Elder Scrolls III: Morrowind
|
|||
OpenMW is an attempt at recreating the engine for the popular role-playing game
|
||||
Morrowind by Bethesda Softworks. You need to own and install the original game for OpenMW to work.
|
||||
|
||||
Version: 0.11.1
|
||||
Version: 0.12.0
|
||||
License: GPL (see GPL3.txt for more information)
|
||||
Website: http://www.openmw.org
|
||||
|
||||
|
@ -14,7 +14,7 @@ THIS IS A WORK IN PROGRESS
|
|||
INSTALLATION
|
||||
|
||||
Windows:
|
||||
Just unpack to a location of your choice. Currently there is no installer.
|
||||
Run the installer.
|
||||
|
||||
Linux:
|
||||
Ubuntu (and most others)
|
||||
|
@ -35,25 +35,87 @@ TODO add description here
|
|||
|
||||
THE DATA PATH
|
||||
|
||||
After the installation OpenMW needs to be told where to find the Morrowind data directory. Create a text file named openmw.cfg (location depends on platform) and enter the following line:
|
||||
The data path tells OpenMW where to find your Morrowind files. From 0.12.0 on OpenMW should be able to
|
||||
pick up the location of these files on its own, if both Morrowind and OpenMW are installed properly
|
||||
(installing Morrowind under WINE is considered a proper install).
|
||||
|
||||
If that does not work for you, please check if you have any leftover openmw.cfg files from versions earlier than 0.12.0. These can interfere with the configuration process, so try to remove then.
|
||||
|
||||
If you are running OpenMW without installing it, you still need to manually adjust the data path. Create a text file named openmw.cfg in the location of the binary and enter the following line:
|
||||
|
||||
data=path to your data directory
|
||||
|
||||
(where you replace "path to your data directory" with the actual location of your data directory)
|
||||
|
||||
On Windows a suitable location for the cfg file is alongside the binary. Currently the binary release comes with such a file pre-generated, but you still need to adjust the data setting.
|
||||
|
||||
On Linux and Mac the default location will be ~/.config/openmw/openmw.cfg.
|
||||
|
||||
|
||||
COMMAND LINE OPTIONS
|
||||
TODO add description of command line options
|
||||
|
||||
Syntax: openmw <options>
|
||||
Allowed options:
|
||||
--help print help message
|
||||
--version print version information and quit
|
||||
--data arg (=data) set data directories (later directories have
|
||||
higher priority)
|
||||
--data-local arg set local data directory (highest priority)
|
||||
--resources arg (=resources) set resources directory
|
||||
--start arg (=Beshara) set initial cell
|
||||
--master arg master file(s)
|
||||
--plugin arg plugin file(s)
|
||||
--fps [=arg(=1)] (=0) fps counter detail (0 = off, 1 = fps counter
|
||||
, 2 = full detail)
|
||||
--anim-verbose [=arg(=1)] (=0) output animation indices files
|
||||
--debug [=arg(=1)] (=0) debug mode
|
||||
--nosound [=arg(=1)] (=0) disable all sounds
|
||||
--script-verbose [=arg(=1)] (=0) verbose script output
|
||||
--new-game [=arg(=1)] (=0) activate char gen/new game mechanics
|
||||
--script-all [=arg(=1)] (=0) compile all scripts (excluding dialogue scri
|
||||
pts) at startup
|
||||
--fs-strict [=arg(=1)] (=0) strict file system handling (no case folding
|
||||
)
|
||||
--encoding arg (=win1252) Character encoding used in OpenMW game messa
|
||||
ges:
|
||||
|
||||
win1250 - Central and Eastern European such
|
||||
as Polish, Czech, Slovak, Hungarian, Slovene
|
||||
, Bosnian, Croatian, Serbian (Latin script),
|
||||
Romanian and Albanian languages
|
||||
|
||||
win1251 - Cyrillic alphabet such as Russian,
|
||||
Bulgarian, Serbian Cyrillic and other langua
|
||||
ges
|
||||
|
||||
win1252 - Western European (Latin) alphabet,
|
||||
used by default
|
||||
--report-focus [=arg(=1)] (=0) write name of focussed object to cout
|
||||
|
||||
|
||||
CREDITS
|
||||
|
||||
Developers:
|
||||
TODO add list of developers
|
||||
Current Developers:
|
||||
Alexander “Ace” Olofsson
|
||||
athile
|
||||
Cris “Mirceam” Mihalache
|
||||
gugus / gus
|
||||
Jacob “Yacoby” Essex
|
||||
Jason “jhooks” Hooks
|
||||
Lukasz “lgro” Gromanowski
|
||||
Marc “Zini” Zinnschlag
|
||||
Nikolay “corristo” Kasyanov
|
||||
Pieter “pvdk” van der Kloet
|
||||
Sebastian “swick” Wick
|
||||
|
||||
Retired Developers:
|
||||
Ardekantur
|
||||
Armin Preiml
|
||||
Diggory Hardy
|
||||
Jan Borsodi
|
||||
Jan-Peter “peppe” Nilsson
|
||||
Josua Grawitter
|
||||
Karl-Felix “k1ll” Glatzer
|
||||
Nicolay Korslund
|
||||
sergoz
|
||||
Star-Demon
|
||||
Yuri Krupenin
|
||||
|
||||
OpenMW:
|
||||
Thanks to DokterDume for kindly providing us with the Moon and Star logo used as the application icon and project logo.
|
||||
|
@ -64,6 +126,31 @@ Thanks to Kevin Ryan for kindly providing us with the icon used for the Data Fil
|
|||
|
||||
CHANGELOG
|
||||
|
||||
0.12.0
|
||||
|
||||
Bug #154: FPS Drop
|
||||
Bug #169: Local scripts continue running if associated object is deleted
|
||||
Bug #174: OpenMW fails to start if the config directory doesn't exist
|
||||
Bug #187: Missing lighting
|
||||
Bug #188: Lights without a mesh are not rendered
|
||||
Bug #191: Taking screenshot causes crash when running installed
|
||||
Feature #28: Sort out the cell load problem
|
||||
Feature #31: Allow the player to move away from pre-defined cells
|
||||
Feature #35: Use alternate storage location for modified object position
|
||||
Feature #45: NPC animations
|
||||
Feature #46: Creature Animation
|
||||
Feature #89: Basic Journal Window
|
||||
Feature #110: Automatically pick up the path of existing MW-installations
|
||||
Feature #183: More FPS display settings
|
||||
Task #19: Refactor engine class
|
||||
Task #109/Feature #162: Automate Packaging
|
||||
Task #112: Catch exceptions thrown in input handling functions
|
||||
Task #128/#168: Cleanup Configuration File Handling
|
||||
Task #131: NPC Activation doesn't work properly
|
||||
Task #144: MWRender cleanup
|
||||
Task #155: cmake cleanup
|
||||
|
||||
|
||||
0.11.1
|
||||
|
||||
Bug #2: Resources loading doesn't work outside of bsa files
|
||||
|
@ -90,4 +177,4 @@ Task #14: Replace tabs with 4 spaces
|
|||
Task #18: Move components from global namespace into their own namespace
|
||||
Task #123: refactor header files in components/esm
|
||||
|
||||
TODO add old changelog (take pre 0.11.0 changelog from wiki)
|
||||
TODO add old changelog (take pre 0.11.1 changelog from wiki)
|
||||
|
|
Loading…
Reference in a new issue