Syncing inventory, animations, position, 8 key attributes

Created Package system
coverity_scan^2
Koncord 8 years ago
parent e362e3e6a5
commit 1b259e2d33

1
.gitignore vendored

@ -21,6 +21,7 @@ Doxygen
.project
.settings
.directory
.idea
## qt-creator
CMakeLists.txt.user*

@ -345,6 +345,12 @@ endif (APPLE)
# Other files
configure_file(${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp-client-default.cfg
"${OpenMW_BINARY_DIR}/tes3mp-client-default.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/tes3mp/tes3mp-server-default.cfg
"${OpenMW_BINARY_DIR}/tes3mp-server-default.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
"${OpenMW_BINARY_DIR}/settings-default.cfg")
@ -454,6 +460,11 @@ IF(NOT WIN32 AND NOT APPLE)
INSTALL(FILES "${OpenMW_BINARY_DIR}/resources/version" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-client-default" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-client.install" DESTINATION "${SYSCONFDIR}" RENAME "tes3mp-client.cfg" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-server-default" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw-mp")
INSTALL(FILES "${OpenMW_BINARY_DIR}/tes3mp-server.install" DESTINATION "${SYSCONFDIR}" RENAME "tes3mp-server.cfg" COMPONENT "openmw-mp")
IF(BUILD_OPENCS)
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw-cs.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "opencs")
ENDIF(BUILD_OPENCS)
@ -473,6 +484,7 @@ if(WIN32)
"${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt"
"${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
"${OpenMW_BINARY_DIR}/settings-default.cfg"
"${OpenMW_BINARY_DIR}/tes3mp-client-default.cfg"
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
DESTINATION ".")

@ -0,0 +1,47 @@
Сделано:
0.0.1b
Пофикшен сегфолт при атаке НПЦ
Интерполляция движения
Lua скриптинг
Чат
0.0.1a
Анимация атаки.
Синхронизация атаки melee/throw/bow/crossbow
Синхронизация здоровья/маны/стамины/смерти
Синхронизация характеристик и навыков
0.0.1
Синхронизация рассовых признаков
Синхронизация положения в мире
Синхронизация состояния (оружие/заклинание/ничего)
Синхронизация анимации перемещния и прыжков
Сделать:
0.0.1b
Закончить пакет атаки (нокаут, нокдаун, заклинания и зачарования)
Улучшить синхронизацию координат при нокауте/нокдауне/смерти
Частичная синхронизация состояния предметов (не ломаемые)
Синхронизация заклинаний
0.0.2
Вампиризм
Оборотни
Синхронизация состояния предметов
Синхронизация замков
Открывание дверей
Отпирание дверей
Взаимодействие с активаторами (хук?)
0.0.2b
Чистка кода
0.0.3
Синхронизция контейнеров
Лут
Воровство у др. игроков.
Выбрасывание/подбор вещей.
Future
Отключаемая консоль (~)
клиентские скриптовые функции для синхронизации
Синхронизация погоды
Синхронизация времени
Синхронизация НПЦ
Трейд

@ -0,0 +1,25 @@
Tes3mp Team
============
Programmers
-----------
Stanislav (Koncord) Zhukov - The main loafer and part-time Project Leader
Testers:
--------
Volk Milit aka Ja'Virr-Dar - Team Manager, Debian Linux
Shnatsel - Debian Linux
Goodevil - Mint and Xubuntu Linux
Public Relations and Translations
---------------------------------
Volk Milit aka Ja'Virr-Dar - Public relations & News Writer
Shnatsel - Translator & News Writer
Thanks to developers of OpenMW. They do amazing things.

@ -0,0 +1,90 @@
#include "editor.hpp"
#include <exception>
#include <iostream>
#include <string>
#include <QApplication>
#include <QIcon>
#include <QMetaType>
#include "model/doc/messages.hpp"
#include "model/world/universalid.hpp"
#ifdef Q_OS_MAC
#include <QDir>
#endif
Q_DECLARE_METATYPE (std::string)
class Application : public QApplication
{
private:
bool notify (QObject *receiver, QEvent *event)
{
try
{
return QApplication::notify (receiver, event);
}
catch (const std::exception& exception)
{
std::cerr << "An exception has been caught: " << exception.what() << std::endl;
}
return false;
}
public:
Application (int& argc, char *argv[]) : QApplication (argc, argv) {}
};
int main(int argc, char *argv[])
{
#ifdef Q_OS_MAC
setenv("OSG_GL_TEXTURE_STORAGE", "OFF", 0);
#endif
try
{
// To allow background thread drawing in OSG
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
Q_INIT_RESOURCE (resources);
qRegisterMetaType<std::string> ("std::string");
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
qRegisterMetaType<CSMDoc::Message> ("CSMDoc::Message");
Application application (argc, argv);
#ifdef Q_OS_MAC
QDir dir(QCoreApplication::applicationDirPath());
if (dir.dirName() == "MacOS") {
dir.cdUp();
dir.cdUp();
dir.cdUp();
}
QDir::setCurrent(dir.absolutePath());
#endif
application.setWindowIcon (QIcon (":./openmw-cs.png"));
CS::Editor editor;
if(!editor.makeIPCServer())
{
editor.connectToIPCServer();
return 0;
}
return editor.run();
}
catch (std::exception& e)
{
std::cerr << "ERROR: " << e.what() << std::endl;
return 0;
}
}

@ -0,0 +1,124 @@
project(openmw-mp)
add_subdirectory(amx)
option(BUILD_WITH_PAWN "Enable Pawn language" OFF)
if(BUILD_WITH_PAWN)
#set(Pawn_ROOT ${CMAKE_SOURCE_DIR}/external/pawn/)
set(Pawn_INCLUDES ${Pawn_ROOT}/include)
set(Pawn_LIBRARY ${Pawn_ROOT}/lib/libamx.a)
set(PawnScript_Sources
Script/LangPawn/LangPAWN.cpp
Script/LangPawn/PawnFunc.cpp)
set(PawnScript_Headers ${Pawn_INCLUDES}
Script/LangPawn/LangPAWN.hpp
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_PAWN -DPAWN_CELL_SIZE=64")
#include_directories(${Pawn_INCLUDES})
include_directories("./amx/linux")
endif(BUILD_WITH_PAWN)
option(BUILD_WITH_LUA "Enable Terra/Lua language" ON)
if(BUILD_WITH_LUA)
#set(Terra_ROOT ${CMAKE_SOURCE_DIR}/external/terra/)
find_package(Terra REQUIRED)
set(LuaScript_Sources
Script/LangLua/LangLua.cpp
Script/LangLua/LuaFunc.cpp)
set(LuaScript_Headers ${Terra_INCLUDES} ${CMAKE_SOURCE_DIR}/extern/LuaBridge ${CMAKE_SOURCE_DIR}/extern/LuaBridge/detail
Script/LangLua/LangLua.hpp)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_LUA")
include_directories(${Terra_INCLUDES} ${CMAKE_SOURCE_DIR}/extern/LuaBridge)
endif(BUILD_WITH_LUA)
set(NativeScript_Sources
Script/LangNative/LangNative.cpp
)
set(NativeScript_Headers
Script/LangNative/LangNative.hpp
)
# local files
set(SERVER
main.cpp
Player.cpp
Networking.cpp
Utils.cpp
Script/Script.cpp Script/ScriptFunction.cpp
Script/ScriptFunctions.cpp
Script/Functions/Translocations.cpp Script/Functions/Stats.cpp Script/Functions/Items.cpp
Script/Functions/Timer.cpp Script/Functions/Chat.cpp
Script/API/TimerAPI.cpp Script/API/PublicFnAPI.cpp
${PawnScript_Sources}
${LuaScript_Sources}
${NativeScript_Sources}
)
set(SERVER_HEADER
Script/Types.hpp Script/Script.hpp Script/SystemInterface.hpp
Script/ScriptFunction.hpp Script/Platform.hpp
Script/ScriptFunctions.hpp Script/API/TimerAPI.hpp Script/API/PublicFnAPI.hpp
${PawnScript_Headers}
${LuaScript_Headers}
${NativeScript_Headers}
)
source_group(openmw-mp FILES ${SERVER} ${SERVER_HEADER})
include_directories("./")
# Main executable
add_executable(openmw-mp
${SERVER_FILES}
${SERVER} ${SERVER_HEADER}
${APPLE_BUNDLE_RESOURCES}
)
add_definitions(-std=gnu++11)
target_link_libraries(openmw-mp
${OSG_LIBRARIES}
${OPENTHREADS_LIBRARIES}
${OSGPARTICLE_LIBRARIES}
${OSGUTIL_LIBRARIES}
${OSGDB_LIBRARIES}
${OSGVIEWER_LIBRARIES}
${OSGGA_LIBRARIES}
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
${BULLET_LIBRARIES}
${RakNet_LIBRARY}
components
amx
${Terra_LIBRARY}
${Pawn_LIBRARY}
)
if (USE_SYSTEM_TINYXML)
target_link_libraries(openmw-mp ${TINYXML_LIBRARIES})
endif()
if (UNIX)
target_link_libraries(openmw-mp dl)
# Fix for not visible pthreads functions for linker with glibc 2.15
if(NOT APPLE)
target_link_libraries(openmw-mp ${CMAKE_THREAD_LIBS_INIT})
endif(NOT APPLE)
endif(UNIX)
if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage)
target_link_libraries(openmw-mp gcov)
endif()
if (MSVC)
# Debug version needs increased number of sections beyond 2^16
if (CMAKE_CL_64)
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj")
endif (CMAKE_CL_64)
add_definitions("-D_USE_MATH_DEFINES")
endif (MSVC)

@ -0,0 +1,395 @@
//
// Created by koncord on 12.01.16.
//
#include "Player.hpp"
#include <RakPeer.h>
#include <Kbhit.h>
#include <components/openmw-mp/NetworkMessages.hpp>
#include <iostream>
#include <Script/Script.hpp>
#include <Script/API/TimerAPI.hpp>
#include "Networking.hpp"
using namespace mwmp;
using namespace std;
Networking *Networking::sThis = 0;
Networking::Networking(RakNet::RakPeerInterface *peer)
{
sThis = this;
this->peer = peer;
players = Players::GetPlayers();
controller = new PacketsController(peer);
controller->SetStream(0, &bsOut); // set send stream
Script::Call<Script::CallbackIdentity("OnServerInit")>();
running = true;
exitCode = 0;
}
Networking::~Networking()
{
Script::Call<Script::CallbackIdentity("OnServerExit")>(false);
sThis = 0;
delete controller;
}
void Networking::Update(RakNet::Packet *packet)
{
Player *player = Players::GetPlayer(packet->guid);
if(player == 0)
{
controller->GetPacket(ID_HANDSHAKE)->RequestData(packet->guid);
NewPlayer(packet->guid);
player = Players::GetPlayer(packet->guid);
return;
}
RakNet::BitStream bsIn(&packet->data[2], packet->length, false);
{
RakNet::RakNetGUID ignoredGUID;
bsIn.Read(ignoredGUID);
(void)ignoredGUID;
}
controller->SetStream(&bsIn, 0);
BasePacket *myPacket = controller->GetPacket(packet->data[1]);
if(packet->data[1] == ID_HANDSHAKE)
{
DEBUG_PRINTF("ID_HANDSHAKE\n");
string passw = "SuperPassword";
myPacket->Read(player);
if(player->isHandshaked())
{
DEBUG_PRINTF("Wrong handshake with player %d, name: %s\n", player->GetID(), player->Npc()->mName.c_str());
KickPlayer(player->guid);
return;
}
if(*player->GetPassw() != passw)
{
DEBUG_PRINTF("Wrong server password (player %d, name: %s) pass: %s\n", player->GetID(), player->Npc()->mName.c_str(), player->GetPassw()->c_str());
KickPlayer(player->guid);
return;
}
player->Handshake();
static constexpr unsigned int ident = Script::CallbackIdentity("OnPlayerConnect");
Script::CallBackReturn<ident> result = true;
Script::Call<ident>(result, Players::GetPlayer(packet->guid)->GetID());
if(!result)
{
controller->GetPacket(ID_USER_DISCONNECTED)->Send(Players::GetPlayer(packet->guid), false);
Players::DeletePlayer(packet->guid);
return;
}
return;
}
if(!player->isHandshaked())
{
DEBUG_PRINTF("Wrong auth player %d, name: %s\n", player->GetID(), player->Npc()->mName.c_str());
//KickPlayer(player->guid);
return;
}
switch(packet->data[1])
{
case ID_GAME_BASE_INFO:
{
DEBUG_PRINTF("ID_GAME_BASE_INFO\n");
myPacket->Read(player);
myPacket->Send(player, true);
break;
}
case ID_GAME_UPDATE_POS:
{
//DEBUG_PRINTF("ID_GAME_UPDATE_POS \n");
if(!player->CreatureStats()->mDead)
{
myPacket->Read(player);
myPacket->Send(player, true); //send to other clients
}
break;
}
case ID_GAME_CELL:
{
DEBUG_PRINTF("ID_GAME_CELL \n");
if(!player->CreatureStats()->mDead)
{
myPacket->Read(player);
myPacket->Send(player, true); //send to other clients
Script::Call<Script::CallbackIdentity("OnPlayerChangeCell")>(player->GetID());
}
break;
}
case ID_GAME_UPDATE_SKILLS:
{
DEBUG_PRINTF("ID_GAME_UPDATE_SKILLS\n");
if(!player->CreatureStats()->mDead)
{
myPacket->Read(player);
myPacket->Send(player, true);
}
break;
}
case ID_GAME_UPDATE_EQUIPED:
{
DEBUG_PRINTF("ID_GAME_UPDATE_EQUIPED\n");
myPacket->Read(player);
myPacket->Send(player, true);
Script::Call<Script::CallbackIdentity("OnPlayerUpdateEquiped")>(player->GetID());
break;
}
case ID_GAME_ATTACK:
{
DEBUG_PRINTF("ID_GAME_ATTACK\n");
if(!player->CreatureStats()->mDead)
{
myPacket->Read(player);
#if defined(DEBUG)
cout << "Player: " << player->Npc()->mName << " atk state: " << (player->GetAttack()->pressed == 1) <<
endl;
if (player->GetAttack()->pressed == 0)
{
cout << "success: " << (player->GetAttack()->success == 1);
if (player->GetAttack()->success == 1)
cout << " damage: " << player->GetAttack()->damage;
cout << endl;
}
#endif
myPacket->Send(player, true);
controller->GetPacket(ID_GAME_UPDATE_BASESTATS)->RequestData(player->GetAttack()->target);
}
break;
}
case ID_GAME_UPDATE_BASESTATS:
{
DEBUG_PRINTF("ID_GAME_UPDATE_BASESTATS\n");
myPacket->Read(player);
myPacket->Send(player, true);
break;
}
case ID_GAME_DIE:
{
DEBUG_PRINTF("ID_GAME_DIE\n");
//packetMainStats.Read(player);
player->CreatureStats()->mDead = true;
myPacket->Send(player, true);
controller->GetPacket(ID_GAME_RESURRECT)->RequestData(player->guid);
Script::Call<Script::CallbackIdentity("OnPlayerDeath")>(player->GetID());
break;
}
case ID_GAME_RESURRECT:
{
DEBUG_PRINTF("ID_GAME_RESURRECT\n");
//packetResurrect.Read(player);
player->CreatureStats()->mDead = false;
myPacket->Send(player, true);
controller->GetPacket(ID_GAME_UPDATE_POS)->RequestData(player->guid);
controller->GetPacket(ID_GAME_CELL)->RequestData(player->guid);
//packetMainStats.RequestData(player->guid);
Script::Call<Script::CallbackIdentity("OnPlayerResurrect")>(player->GetID());
break;
}
case ID_GAME_DRAWSTATE:
{
DEBUG_PRINTF("ID_GAME_DRAWSTATE\n");
myPacket->Read(player);
myPacket->Send(player, true);
break;
}
case ID_CHAT_MESSAGE:
{
DEBUG_PRINTF("ID_CHAT_MESSAGE\n");
myPacket->Read(player);
Script::CallBackReturn<Script::CallbackIdentity("OnPlayerSendMessage")> result = true;
Script::Call<Script::CallbackIdentity("OnPlayerSendMessage")>(result, player->GetID(), player->ChatMessage()->c_str());
if(result)
{
*player->ChatMessage() = player->Npc()->mName + " (" + std::to_string(player->GetID()) + "): "
+ *player->ChatMessage() + "\n";
myPacket->Send(player, false);
myPacket->Send(player, true);
}
break;
}
case ID_GAME_CHARGEN:
{
DEBUG_PRINTF("ID_GAME_CHARGEN\n");
myPacket->Read(player);
if (player->CharGenStage()->current == player->CharGenStage()->end && player->CharGenStage()->current != 0)
{
Script::Call<Script::CallbackIdentity("OnPlayerEndCharGen")>(player->GetID());
cout << "RACE: " << player->Npc()->mRace << endl;
}
break;
}
default:
printf("Message with identifier %i has arrived.\n", packet->data[1]);
break;
}
}
void Networking::NewPlayer(RakNet::RakNetGUID guid)
{
Players::NewPlayer(guid);
controller->GetPacket(ID_USER_MYID)->Send(Players::GetPlayer(guid), false);
controller->GetPacket(ID_GAME_BASE_INFO)->RequestData(guid);
//controller->GetPacket(ID_GAME_UPDATE_SKILLS)->RequestData(guid);
//controller->GetPacket(ID_GAME_UPDATE_BASESTATS)->RequestData(guid);
controller->GetPacket(ID_GAME_UPDATE_POS)->RequestData(guid);
controller->GetPacket(ID_GAME_CELL)->RequestData(guid);
controller->GetPacket(ID_GAME_UPDATE_EQUIPED)->RequestData(guid);
for(TPlayers::iterator pl = players->begin(); pl != players->end(); pl++)
{
if(pl->first == guid) continue;
controller->GetPacket(ID_GAME_BASE_INFO)->Send(pl->second, guid);
//controller->GetPacket(ID_GAME_UPDATE_SKILLS)->Send(pl->second, guid);
//controller->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(pl->second, guid);
controller->GetPacket(ID_GAME_UPDATE_POS)->Send(pl->second, guid);
controller->GetPacket(ID_GAME_CELL)->Send(pl->second, guid);
controller->GetPacket(ID_GAME_UPDATE_EQUIPED)->Send(pl->second, guid);
}
}
void Networking::DisconnectPlayer(RakNet::RakNetGUID guid)
{
Script::Call<Script::CallbackIdentity("OnPlayerDisconnect")>(Players::GetPlayer(guid)->GetID());
controller->GetPacket(ID_USER_DISCONNECTED)->Send(Players::GetPlayer(guid), true);
Players::DeletePlayer(guid);
}
PacketsController *Networking::GetController() const
{
return controller;
}
const Networking &Networking::Get()
{
return *sThis;
}
Networking *Networking::GetPtr()
{
return sThis;
}
void Networking::StopServer(int code)
{
running = false;
exitCode = code;
}
int Networking::MainLoop()
{
RakNet::Packet *packet;
while (running)
{
if(kbhit() && getch() == '\n')
break;
for (packet=peer->Receive(); packet; peer->DeallocatePacket(packet), packet=peer->Receive())
{
switch (packet->data[0])
{
case ID_REMOTE_DISCONNECTION_NOTIFICATION:
printf("Another client has disconnected.\n");
break;
case ID_REMOTE_CONNECTION_LOST:
printf("Another client has lost the connection.\n");
break;
case ID_REMOTE_NEW_INCOMING_CONNECTION:
printf("Another client has connected.\n");
break;
case ID_CONNECTION_REQUEST_ACCEPTED: // client to server
{
printf("Our connection request has been accepted.\n");
break;
}
case ID_NEW_INCOMING_CONNECTION:
printf("A connection is incoming.\n");
break;
case ID_NO_FREE_INCOMING_CONNECTIONS:
printf("The server is full.\n");
break;
case ID_DISCONNECTION_NOTIFICATION:
printf("A client has disconnected.\n");
DisconnectPlayer(packet->guid);
break;
case ID_CONNECTION_LOST:
printf("A client lost the connection.\n");
DisconnectPlayer(packet->guid);
break;
case ID_CUSTOM_MESSAGE:
Update(packet);
break;
default:
printf("Message with identifier %i has arrived.\n", packet->data[0]);
break;
}
}
TimerAPI::Tick();
}
TimerAPI::Terminate();
return exitCode;
}
void Networking::KickPlayer(RakNet::RakNetGUID guid)
{
peer->CloseConnection(guid, true);
}

@ -0,0 +1,45 @@
//
// Created by koncord on 12.01.16.
//
#ifndef OPENMW_NETWORKING_HPP
#define OPENMW_NETWORKING_HPP
#include <components/openmw-mp/PacketsController.hpp>
namespace mwmp
{
class Networking
{
public:
Networking(RakNet::RakPeerInterface *peer);
~Networking();
void NewPlayer(RakNet::RakNetGUID guid);
void DisconnectPlayer(RakNet::RakNetGUID guid);
void KickPlayer(RakNet::RakNetGUID guid);
void Update(RakNet::Packet *packet);
int MainLoop();
void StopServer(int code);
PacketsController *GetController() const;
static const Networking &Get();
static Networking *GetPtr();
private:
static Networking *sThis;
RakNet::RakPeerInterface *peer;
RakNet::BitStream bsOut;
TPlayers *players;
PacketsController *controller;
bool running;
int exitCode;
};
}
#endif //OPENMW_NETWORKING_HPP

@ -0,0 +1,80 @@
//
// Created by koncord on 05.01.16.
//
#include "Player.hpp"
TPlayers Players::players;
TSlots Players::slots;
void Players::DeletePlayer(RakNet::RakNetGUID id)
{
if(players[id] != 0)
{
slots[players[id]->GetID()] = 0;
delete players[id];
players.erase(id);
}
}
void Players::NewPlayer(RakNet::RakNetGUID id)
{
players[id] = new Player(id);
for(int i = 0; i < 16; i++)
{
if(slots[i] == 0)
{
slots[i] = players[id];
slots[i]->SetID(i);
break;
}
}
}
Player *Players::GetPlayer(RakNet::RakNetGUID id)
{
return players[id];
}
std::map<RakNet::RakNetGUID, Player*> *Players::GetPlayers()
{
return &players;
}
Player::Player(RakNet::RakNetGUID id) : BasePlayer(id)
{
handshake = false;
}
Player::~Player()
{
}
unsigned short Player::GetID()
{
return id;
}
void Player::SetID(unsigned short id)
{
this->id = id;
}
void Player::Handshake()
{
handshake = true;
}
bool Player::isHandshaked()
{
return handshake;
}
Player *Players::GetPlayer(unsigned short id)
{
return slots[id];
}

@ -0,0 +1,56 @@
//
// Created by koncord on 05.01.16.
//
#ifndef OPENMW_PLAYER_HPP
#define OPENMW_PLAYER_HPP
#include <map>
#include <string>
#include <RakNetTypes.h>
#include <components/esm/npcstats.hpp>
#include <components/esm/cellid.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/esm/loadcell.hpp>
#include <components/openmw-mp/Base/BasePlayer.hpp>
struct Player;
typedef std::map<RakNet::RakNetGUID, Player*> TPlayers;
typedef std::map<unsigned short, Player*> TSlots;
class Players
{
public:
static void NewPlayer(RakNet::RakNetGUID id);
static void DeletePlayer(RakNet::RakNetGUID id);
static Player *GetPlayer(RakNet::RakNetGUID id);
static Player *GetPlayer(unsigned short id);
static TPlayers *GetPlayers();
private:
static TPlayers players;
static TSlots slots;
};
class Player : public mwmp::BasePlayer
{
unsigned short id;
public:
Player(RakNet::RakNetGUID id);
unsigned short GetID();
void SetID(unsigned short id);
bool isHandshaked();
void Handshake();
virtual ~Player();
private:
bool handshake;
};
#endif //OPENMW_PLAYER_HPP

@ -0,0 +1,93 @@
//
// Created by koncord on 14.05.16.
//
#include <Script/ScriptFunction.hpp>
#include "PublicFnAPI.hpp"
using namespace std;
unordered_map<string, Public *> Public::publics;
Public::~Public()
{
}
Public::Public(ScriptFunc _public, const std::string &name, char ret_type, const std::string &def) : ScriptFunction(_public, ret_type, def)
{
publics.emplace(name, this);
}
Public::Public(ScriptFuncLua _public, lua_State *lua, const std::string &name, char ret_type, const std::string &def) : ScriptFunction(
_public, lua, ret_type, def)
{
publics.emplace(name, this);
}
#if defined(ENABLE_PAWN)
Public::Public(ScriptFuncPAWN _public, AMX* amx, const std::string& name, char ret_type, const std::string& def): ScriptFunction(_public, amx, ret_type, def)
{
publics.emplace(name, this);
}
#endif
boost::any Public::Call(const std::string &name, const std::vector<boost::any> &args)
{
auto it = publics.find(name);
if (it == publics.end())
throw runtime_error("Public with name \"" + name + "\" does not exist");
return it->second->ScriptFunction::Call(args);
}
const std::string &Public::GetDefinition(const std::string &name)
{
auto it = publics.find(name);
if (it == publics.end())
throw runtime_error("Public with name \"" + name + "\" does not exist");
return it->second->def;
}
bool Public::IsLua(const std::string &name)
{
#if !defined(ENABLE_LUA)
return false;
#else
auto it = publics.find(name);
if (it == publics.end())
throw runtime_error("Public with name \"" + name + "\" does not exist");
return it->second->script_type == SCRIPT_LUA;
#endif
}
bool Public::IsPAWN(const std::string &name)
{
#if !defined(ENABLE_PAWN)
return false;
#else
auto it = publics.find(name);
if (it == publics.end())
throw runtime_error("Public with name \"" + name + "\" does not exist");
return it->second->script_type == SCRIPT_PAWN;
#endif
}
void Public::DeleteAll()
{
for (auto it = publics.begin(); it != publics.end(); it++)
{
Public *_public = it->second;
delete _public;
publics.erase(it);
}
}

@ -0,0 +1,42 @@
//
// Created by koncord on 14.05.16.
//
#ifndef PLUGINSYSTEM3_PUBLICFNAPI_HPP
#define PLUGINSYSTEM3_PUBLICFNAPI_HPP
#include <unordered_map>
#include <Script/ScriptFunction.hpp>
class Public : public ScriptFunction
{
private:
~Public();
static std::unordered_map<std::string, Public *> publics;
Public(ScriptFunc _public, const std::string &name, char ret_type, const std::string &def);
#if defined(ENABLE_PAWN)
Public(ScriptFuncPAWN _public, AMX* amx, const std::string& name, char ret_type, const std::string& def);
#endif
#if defined(ENABLE_LUA)
Public(ScriptFuncLua _public, lua_State *lua, const std::string &name, char ret_type, const std::string &def);
#endif
public:
template<typename... Args>
static void MakePublic(Args &&... args)
{ new Public(std::forward<Args>(args)...); }
static boost::any Call(const std::string &name, const std::vector<boost::any> &args);
static const std::string& GetDefinition(const std::string& name);
static bool IsPAWN(const std::string &name);
static bool IsLua(const std::string &name);
static void DeleteAll();
};
#endif //PLUGINSYSTEM3_PUBLICFNAPI_HPP

@ -0,0 +1,238 @@
//
// Created by koncord on 15.03.16.
//
#include "TimerAPI.hpp"
#include <chrono>
#include <iostream>
using namespace mwmp;
using namespace std;
Timer::Timer(ScriptFunc callback, long msec, const std::string& def, std::vector<boost::any> args) : ScriptFunction(callback, 'v', def)
{
targetMsec = msec;
this->args = args;
end = true;
}
#if defined(ENABLE_PAWN)
Timer::Timer(AMX *amx, ScriptFuncPAWN callback, long msec, const std::string &def, std::vector<boost::any> args): ScriptFunction(callback, amx, 'v', def)
{
targetMsec = msec;
this->args = args;
end = true;
}
#endif
#if defined(ENABLE_LUA)
Timer::Timer(lua_State *lua, ScriptFuncLua callback, long msec, const std::string& def, std::vector<boost::any> args): ScriptFunction(callback, lua, 'v', def)
{
targetMsec = msec;
this->args = args;
end = true;
}
#endif
void Timer::Tick()
{
if(end)
return;
const auto duration = chrono::system_clock::now().time_since_epoch();
const auto time = chrono::duration_cast<chrono::milliseconds>(duration).count();
if (time - startTime >= targetMsec)
{
Call(args);
end = true;
}
}
bool Timer::IsEnd()
{
return end;
}
void Timer::Stop()
{
end = true;
}
void Timer::Restart(int msec)
{
targetMsec = msec;
Start();
}
void Timer::Start()
{
end = false;
const auto duration = chrono::system_clock::now().time_since_epoch();
const auto msec = chrono::duration_cast<chrono::milliseconds>(duration).count();
startTime = msec;
}
int TimerAPI::pointer = 0;
std::unordered_map<int, Timer* > TimerAPI::timers;
#if defined(ENABLE_PAWN)
int TimerAPI::CreateTimerPAWN(AMX *amx, ScriptFuncPAWN callback, long msec, const string& def, std::vector<boost::any> args)
{
int id = -1;
for (auto timer : timers)
{
if (timer.second != nullptr)
continue;
timer.second = new Timer(amx, callback, msec, def, args);
id = timer.first;
}
if (id == -1)
{
timers[pointer] = new Timer(amx, callback, msec, def, args);
id = pointer;
pointer++;
}
return id;
}
#endif
#if defined(ENABLE_LUA)
int TimerAPI::CreateTimerLua(lua_State *lua, ScriptFuncLua callback, long msec, const std::string& def, std::vector<boost::any> args)
{
int id = -1;
for (auto timer : timers)
{
if (timer.second != nullptr)
continue;
timer.second = new Timer(lua, callback, msec, def, args);
id = timer.first;
}
if (id == -1)
{
timers[pointer] = new Timer(lua, callback, msec, def, args);
id = pointer;
pointer++;
}
return id;
}
#endif
int TimerAPI::CreateTimer(ScriptFunc callback, long msec, const std::string &def, std::vector<boost::any> args)
{
int id = -1;
for (auto timer : timers)
{
if (timer.second != nullptr)
continue;
timer.second = new Timer(callback, msec, def, args);
id = timer.first;
}
if (id == -1)
{
timers[pointer] = new Timer(callback, msec, def, args);
id = pointer;
pointer++;
}
return id;
}
void TimerAPI::FreeTimer(int timerid)
{
try
{
if(timers.at(timerid) != nullptr)
{
delete timers[timerid];
timers[timerid] = nullptr;
}
}
catch(...)
{
std::cerr << "Timer " << timerid << " not found!" << endl;
}
}
void TimerAPI::ResetTimer(int timerid, long msec)
{
try
{
timers.at(timerid)->Restart(msec);
}
catch(...)
{
std::cerr << "Timer " << timerid << " not found!" << endl;
}
}
void TimerAPI::StartTimer(int timerid)
{
try
{
Timer *timer = timers.at(timerid);
if(timer == nullptr)
throw 1;
timer->Start();
}
catch(...)
{
std::cerr << "Timer " << timerid << " not found!" << endl;
}
}
void TimerAPI::StopTimer(int timerid)
{
try
{
timers.at(timerid)->Stop();
}
catch(...)
{
std::cerr << "Timer " << timerid << " not found!" << endl;
}
}
bool TimerAPI::IsEndTimer(int timerid)
{
bool ret = false;
try
{
ret = timers.at(timerid)->IsEnd();
}
catch(...)
{
std::cerr << "Timer " << timerid << " not found!" << endl;
}
return ret;
}
void TimerAPI::Terminate()
{
for(auto timer : timers)
{
if(timer.second != nullptr)
delete timer.second;
timer.second = nullptr;
}
}
void TimerAPI::Tick()
{
for (auto timer : timers)
{
if(timer.second != nullptr)
timer.second->Tick();
}
}

@ -0,0 +1,70 @@
//
// Created by koncord on 15.03.16.
//
#ifndef OPENMW_TIMERAPI_HPP
#define OPENMW_TIMERAPI_HPP
#include <string>
#include <Script/Script.hpp>
#include <Script/ScriptFunction.hpp>
namespace mwmp
{
class TimerAPI;
class Timer: public ScriptFunction
{
friend class TimerAPI;
public:
Timer(ScriptFunc callback, long msec, const std::string& def, std::vector<boost::any> args);
#if defined(ENABLE_PAWN)
Timer(AMX *amx, ScriptFuncPAWN callback, long msec, const std::string& def, std::vector<boost::any> args);
#endif
#if defined(ENABLE_LUA)
Timer(lua_State *lua, ScriptFuncLua callback, long msec, const std::string& def, std::vector<boost::any> args);
#endif
void Tick();
bool IsEnd();
void Stop();
void Start();
void Restart(int msec);
private:
long startTime, targetMsec;
std::string publ, arg_types;
std::vector<boost::any> args;
Script *scr;
bool end;
};
class TimerAPI
{
public:
#if defined(ENABLE_PAWN)
static int CreateTimerPAWN(AMX *amx, ScriptFuncPAWN callback, long msec, const std::string& def, std::vector<boost::any> args);
#endif
#if defined(ENABLE_LUA)
static int CreateTimerLua(lua_State *lua, ScriptFuncLua callback, long msec, const std::string& def, std::vector<boost::any> args);
#endif
static int CreateTimer(ScriptFunc callback, long msec, const std::string& def, std::vector<boost::any> args);
static void FreeTimer(int timerid);
static void ResetTimer(int timerid, long msec);
static void StartTimer(int timerid);
static void StopTimer(int timerid);
static bool IsEndTimer(int timerid);
static void Terminate();
static void Tick();
private:
static std::unordered_map<int, Timer* > timers;
static int pointer;
};
}
#endif //OPENMW_TIMERAPI_HPP

@ -0,0 +1,31 @@
//
// Created by koncord on 29.04.16.
//
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
#include <apps/openmw-mp/Networking.hpp>
#include <components/openmw-mp/NetworkMessages.hpp>
void ScriptFunctions::SendMessage(unsigned short pid, const char *message, bool broadcast) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
*player->ChatMessage() = message;
DEBUG_PRINTF("System: %s", message);
mwmp::Networking::Get().GetController()->GetPacket(ID_CHAT_MESSAGE)->Send(player, false);
if(broadcast)
mwmp::Networking::Get().GetController()->GetPacket(ID_CHAT_MESSAGE)->Send(player, true);
}
void ScriptFunctions::CleanChat(unsigned short pid)
{
}
void ScriptFunctions::CleanChat()
{
}

@ -0,0 +1,56 @@
//
// Created by koncord on 02.03.16.
//
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
#include <components/openmw-mp/NetworkMessages.hpp>
#include <apps/openmw-mp/Networking.hpp>
#include <components/misc/stringops.hpp>
/*void ScriptFunctions::AddItem(unsigned short pid, const char* itemName, unsigned short count) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, true);
}*/
void ScriptFunctions::EquipItem(unsigned short pid, unsigned short slot, const char *itemName, unsigned short count) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
player->EquipedItem(slot)->refid = itemName;
player->EquipedItem(slot)->count = count;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_EQUIPED)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_EQUIPED)->Send(player, true);
}
void ScriptFunctions::UnequipItem(unsigned short pid, unsigned short slot) noexcept
{
ScriptFunctions::EquipItem(pid, slot, "", 0);
}
const char *ScriptFunctions::GetItemSlot(unsigned short pid, unsigned short slot) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
return player->EquipedItem(slot)->refid.c_str();
}
bool ScriptFunctions::HasItemEquipped(unsigned short pid, const char* itemName)
{
Player *player;
GET_PLAYER(pid, player, false);
for(int slot = 0; slot < 27; slot ++)
if(Misc::StringUtils::ciEqual(player->EquipedItem(slot)->refid, itemName))
return true;
return false;
}

@ -0,0 +1,408 @@
//
// Created by koncord on 29.02.16.
//
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
#include <components/openmw-mp/NetworkMessages.hpp>
#include <apps/openmw-mp/Networking.hpp>
#include <components/misc/stringops.hpp>
#include <iostream>
using namespace std;
void ScriptFunctions::SetName(unsigned short pid, const char *name) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
if (player->GetCell()->mName == name)
return;
player->GetCell()->mName = name;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_BASE_INFO)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_BASE_INFO)->Send(player, true);
}
const char *ScriptFunctions::GetName(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
cout << "pname: " << player->Npc()->mName.c_str() << endl;
return player->Npc()->mName.c_str();
}
void ScriptFunctions::SetBirthsign(unsigned short pid, const char *sign) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
if (player->GetCell()->mName == sign)
return;
*player->BirthSign() = sign;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_BASE_INFO)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_BASE_INFO)->Send(player, true);
}
const char *ScriptFunctions::GetBirthsign(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
return player->BirthSign()->c_str();
}
void ScriptFunctions::SetRace(unsigned short pid, const char *race) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
if (player->Npc()->mRace == race)
return;
printf("Attempt to set race %s -> %s", player->Npc()->mRace.c_str(), race);
player->Npc()->mRace = race;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_BASE_INFO)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_BASE_INFO)->Send(player, true);
}
const char *ScriptFunctions::GetRace(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
return player->Npc()->mRace.c_str();
}
void ScriptFunctions::SetHead(unsigned short pid, const char *race) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
if (player->Npc()->mHead == race)
return;
player->Npc()->mHead = race;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_BASE_INFO)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_BASE_INFO)->Send(player, true);
}
const char *ScriptFunctions::GetHead(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
return player->Npc()->mHead.c_str();
}
void ScriptFunctions::SetHairstyle(unsigned short pid, const char *style) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
if (player->Npc()->mHair == style)
return;
player->Npc()->mHair = style;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_BASE_INFO)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_BASE_INFO)->Send(player, true);
}
const char *ScriptFunctions::GetHairstyle(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
return player->Npc()->mHair.c_str();
}
int ScriptFunctions::GetIsMale(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player,false);
return player->Npc()->isMale();
}
void ScriptFunctions::SetIsMale(unsigned short pid, int value) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
player->Npc()->setIsMale(value == true);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, true);
}
float ScriptFunctions::GetHealth(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player,0.f);
return player->CreatureStats()->mDynamic[0].mBase;
}
void ScriptFunctions::SetHealth(unsigned short pid, float value) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
player->CreatureStats()->mDynamic[0].mBase = value;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, true);
}
float ScriptFunctions::GetCurrentHealth(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0.f);
return player->CreatureStats()->mDynamic[0].mCurrent;
}
void ScriptFunctions::SetCurrentHealth(unsigned short pid, float value) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
player->CreatureStats()->mDynamic[0].mCurrent = 0;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, true);
}
float ScriptFunctions::GetMagicka(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player,0.f);
return player->CreatureStats()->mDynamic[1].mBase;
}
void ScriptFunctions::SetMagicka(unsigned short pid, float value) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
player->CreatureStats()->mDynamic[1].mBase = value;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, true);
}
float ScriptFunctions::GetCurrentMagicka(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0.f);
return player->CreatureStats()->mDynamic[1].mCurrent;
}
void ScriptFunctions::SetCurrentMagicka(unsigned short pid, float value) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
player->CreatureStats()->mDynamic[1].mCurrent = 0;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, true);
}
float ScriptFunctions::GetFatigue(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player,0.f);
return player->CreatureStats()->mDynamic[2].mBase;
}
void ScriptFunctions::SetFatigue(unsigned short pid, float value) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
player->CreatureStats()->mDynamic[2].mBase = value;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, true);
}
float ScriptFunctions::GetCurrentFatigue(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0.f);
return player->CreatureStats()->mDynamic[2].mCurrent;
}
void ScriptFunctions::SetCurrentFatigue(unsigned short pid, float value) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
player->CreatureStats()->mDynamic[2].mCurrent = 0;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(player, true);
}
int ScriptFunctions::GetAttribute(unsigned short pid, unsigned short attribute) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
if(attribute > 7)
return 0;
return player->CreatureStats()->mAttributes[attribute].mBase;
}
void ScriptFunctions::SetAttribute(unsigned short pid, unsigned short attribute, int value) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
if(attribute > 7)
return;
DEBUG_PRINTF("SetAttribute(%d, %d, %d)\n", pid, attribute, value);
player->CreatureStats()->mAttributes[attribute].mBase = value;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_ATTRIBUTE)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_ATTRIBUTE)->Send(player, true);
}
int ScriptFunctions::GetCurrentAttribute(unsigned short pid, unsigned short attribute) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
if(attribute > 7)
return 0;
return player->CreatureStats()->mAttributes[attribute].mCurrent;
}
void ScriptFunctions::SetCurrentAttribute(unsigned short pid, unsigned short attribute, int value) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
if(attribute > 7)
return;
player->CreatureStats()->mAttributes[attribute].mCurrent = value;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_ATTRIBUTE)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_ATTRIBUTE)->Send(player, true);
}
int ScriptFunctions::GetSkill(unsigned short pid, unsigned short skill) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
if(skill > 27)
return 0;
return player->NpcStats()->mSkills[skill].mBase;
}
void ScriptFunctions::SetSkill(unsigned short pid, unsigned short skill, int value) noexcept //TODO: need packet for one value
{
Player *player;
GET_PLAYER(pid, player,);
if(skill > 27)
return;
player->NpcStats()->mSkills[skill].mBase = value;
DEBUG_PRINTF("SetSkill(%d, %d, %d)\n", pid, skill, value);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_SKILL)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_SKILL)->Send(player, true);
}
int ScriptFunctions::GetCurrentSkill(unsigned short pid, unsigned short skill) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
if(skill > 27)
return 0;
return player->NpcStats()->mSkills[skill].mCurrent;
}
void ScriptFunctions::SetCurrentSkill(unsigned short pid, unsigned short skill, int value) noexcept //TODO: need packet for one value
{
Player *player;
GET_PLAYER(pid, player,);
if(skill > 27)
return;
player->NpcStats()->mSkills[skill].mCurrent = value;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_SKILL)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_SKILL)->Send(player, true);
}
int ScriptFunctions::GetIncreaseSkill(unsigned short pid, unsigned int pos) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
if(pos > 7)
return 0;
return player->NpcStats()->mSkillIncrease[pos];
}
void ScriptFunctions::SetIncreaseSkill(unsigned short pid, unsigned int pos, int value) noexcept // TODO: need packet for transmit it
{
Player *player;
GET_PLAYER(pid, player,);
if(pos > 7)
return;
player->NpcStats()->mSkillIncrease[pos] = value;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_SKILL)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_SKILL)->Send(player, true);
}
void ScriptFunctions::SetCharGenStage(unsigned short pid, int start, int end) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
player->CharGenStage()->current = start;
player->CharGenStage()->end = end;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_CHARGEN)->Send(player, false);
}

@ -0,0 +1,49 @@
//
// Created by koncord on 15.03.16.
//
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
#include <components/openmw-mp/NetworkMessages.hpp>
#include <Player.hpp>
#include <Networking.hpp>
#include <Script/API/TimerAPI.hpp>
using namespace std;
using namespace mwmp;
int ScriptFunctions::CreateTimer(ScriptFunc callback, int msec) noexcept
{
}
int ScriptFunctions::CreateTimerEx(ScriptFunc callback, int msec, const char *types, ...) noexcept
{
}
void ScriptFunctions::StartTimer(int timerId) noexcept
{
TimerAPI::StartTimer(timerId);
}
void ScriptFunctions::StopTimer(int timerId) noexcept
{
TimerAPI::StopTimer(timerId);
}
void ScriptFunctions::RestartTimer(int timerId, int msec) noexcept
{
TimerAPI::ResetTimer(timerId, msec);
}
void ScriptFunctions::FreeTimer(int timerId) noexcept
{
TimerAPI::FreeTimer(timerId);
}
bool ScriptFunctions::IsTimerElapsed(int timerId) noexcept
{
TimerAPI::IsEndTimer(timerId);
}

@ -0,0 +1,106 @@
//
// Created by koncord on 29.02.16.
//
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
#include <components/openmw-mp/NetworkMessages.hpp>
#include <apps/openmw-mp/Player.hpp>
#include <apps/openmw-mp/Networking.hpp>
#include <iostream>
using namespace std;
void ScriptFunctions::GetPos(unsigned short pid, float *x, float *y, float *z) noexcept
{
*x = 0.00;
*y = 0.00;
*z = 0.00;
Player *player;
GET_PLAYER(pid, player,);
*x = player->Position()->pos[0];
*y = player->Position()->pos[1];
*z = player->Position()->pos[2];
}
void ScriptFunctions::SetPos(unsigned short pid, float x, float y, float z) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
player->Position()->pos[0] = x;
player->Position()->pos[1] = y;
player->Position()->pos[2] = z;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_POS)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_POS)->Send(player, true);
}
void ScriptFunctions::SetCell(unsigned short pid, const char *name) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
/*if(player->GetCell()->mName == name)
return;*/
cout << "attempt to move player (pid: " << pid << " name: " << player->Npc()->mName << ") from ";
if(!player->GetCell()->isExterior())
cout << "\"" << player->GetCell()->mName << "\"";
else
cout << "exterior";
player->GetCell()->mName = name;
cout << " in to cell \"" << player->GetCell()->mName << "\"" << endl;
player->GetCell()->mData.mFlags |= 1;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_CELL)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_CELL)->Send(player, true);
}
const char* ScriptFunctions::GetCell(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
return player->GetCell()->mName.c_str();
}
bool ScriptFunctions::IsInInterior(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, false);
return !player->GetCell()->isExterior();
}
void ScriptFunctions::GetAngle(unsigned short pid, float *x, float *y, float *z) noexcept
{
*x = 0.00;
*y = 0.00;
*z = 0.00;
Player *player;
GET_PLAYER(pid, player,);
*x = player->Position()->rot[0];
*y = player->Position()->rot[1];
*z = player->Position()->rot[2];
}
void ScriptFunctions::SetAngle(unsigned short pid, float x, float y, float z) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
player->Position()->rot[0] = x;
player->Position()->rot[1] = y;
player->Position()->rot[2] = z;
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_POS)->Send(player, false);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_UPDATE_POS)->Send(player, true);
}

@ -0,0 +1,235 @@
//
// Created by koncord on 08.05.16.
//
#include <iostream>
#include "LangLua.hpp"
#include <Script/Script.hpp>
#include <Script/Types.hpp>
using namespace std;
void *LangLua::GetInterface()
{
return lua;
}
LangLua::LangLua(lua_State *lua)
{
this->lua = lua;
}
LangLua::LangLua()
{
lua = luaL_newstate();
luaL_openlibs(lua); // load all lua std libs
terra_init(lua);
}
LangLua::~LangLua()
{
}
template<unsigned int I, unsigned int F>
struct Lua_dispatch_ {
template<typename R, typename... Args>
inline static R Lua_dispatch(lua_State*&& lua, Args&&... args) noexcept {
constexpr ScriptFunctionData const& F_ = ScriptFunctions::functions[F];
auto arg = luabridge::Stack<typename CharType<F_.func.types[I - 1]>::type>::get(lua, I);
return Lua_dispatch_<I - 1, F>::template Lua_dispatch<R>(
forward<lua_State*>(lua),
arg,
forward<Args>(args)...);
}
};
template<unsigned int F>
struct Lua_dispatch_<0, F> {
template<typename R, typename... Args>
inline static R Lua_dispatch(lua_State*&&, Args&&... args) noexcept {
constexpr ScriptFunctionData const& F_ = ScriptFunctions::functions[F];
return reinterpret_cast<FunctionEllipsis<R>>(F_.func.addr)(forward<Args>(args)...);
}
};
template<unsigned int I>
static typename enable_if<ScriptFunctions::functions[I].func.ret == 'v', int>::type wrapper(lua_State* lua) noexcept {
Lua_dispatch_<ScriptFunctions::functions[I].func.numargs, I>::template Lua_dispatch<void>(forward<lua_State*>(lua));
return 0;
}
template<unsigned int I>
static typename enable_if<ScriptFunctions::functions[I].func.ret != 'v', int>::type wrapper(lua_State* lua) noexcept {
auto ret = Lua_dispatch_<ScriptFunctions::functions[I].func.numargs, I>::template Lua_dispatch<typename CharType<ScriptFunctions::functions[I].func.ret>::type>(forward<lua_State*>(lua));
luabridge::Stack <typename CharType<ScriptFunctions::functions[I].func.ret>::type>::push (lua, ret);
return 1;
}
template<unsigned int I>
struct F_
{
static constexpr LuaFuctionData F{ScriptFunctions::functions[I].name, wrapper<I>};
};
template<> struct F_<0> { static constexpr LuaFuctionData F{"CreateTimer", LangLua::CreateTimer}; };
template<> struct F_<1> { static constexpr LuaFuctionData F{"CreateTimerEx", LangLua::CreateTimerEx}; };
template<> struct F_<2> { static constexpr LuaFuctionData F{"MakePublic", LangLua::MakePublic}; };
template<> struct F_<3> { static constexpr LuaFuctionData F{"CallPublic", LangLua::CallPublic}; };
template<size_t... Indices>
inline LuaFuctionData *LangLua::functions(indices<Indices...>)
{
static LuaFuctionData functions_[sizeof...(Indices)]{
F_<Indices>::F...
};
static_assert(
sizeof(functions_) / sizeof(functions_[0]) ==
sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0]),
"Not all functions have been mapped to Lua");
return functions_;
}
void LangLua::LoadProgram(const char *filename)
{
int err = 0;
if ((err = terra_loadfile(lua, filename)) != 0)
throw runtime_error("Lua script " + string(filename) + " error (" + to_string(err) + "): \"" +
string(lua_tostring(lua, -1)) + "\"");
constexpr auto functions_n = sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0]);
LuaFuctionData *functions_ = functions(IndicesFor<functions_n>{});
luabridge::Namespace tes3mp = luabridge::getGlobalNamespace(lua).beginNamespace("tes3mp");
for(int i = 0; i < functions_n; i++)
tes3mp.addCFunction(functions_[i].name, functions_[i].func);
tes3mp.endNamespace();
if ((err = lua_pcall(lua, 0, 0, 0)) != 0) // Run once script for load in memory.
throw runtime_error("Lua script " + string(filename) + " error (" + to_string(err) + "): \"" +
string(lua_tostring(lua, -1)) + "\"");
}
int LangLua::FreeProgram()
{
lua_close(lua);
}
bool LangLua::IsCallbackPresent(const char *name)
{
return luabridge::getGlobal(lua, name).isFunction();
}
boost::any LangLua::Call(const char *name, const char *argl, int buf, ...)
{
va_list vargs;
va_start(vargs, buf);
std::vector<boost::any> args;
try
{
unsigned int len = strlen(argl);
for (unsigned int i = 0; i < len; ++i)
{
switch (argl[i])
{
case 'i':
args.emplace_back(va_arg(vargs, unsigned int));
break;
case 'q':
args.emplace_back(va_arg(vargs, signed int));
break;
case 'l':
args.emplace_back(va_arg(vargs, unsigned long long));
break;
case 'w':
args.emplace_back(va_arg(vargs, signed long long));
break;
case 'f':
{
args.emplace_back(va_arg(vargs, double));
break;
}
case 'p':
args.emplace_back(va_arg(vargs, void*));
break;
case 's':
args.emplace_back(va_arg(vargs, const char*));
break;
default:
throw runtime_error("PAWN call: Unknown argument identifier " + argl[i]);
}
}
}
catch(...)
{
va_end(vargs);
throw;
}
va_end(vargs);
return Call(name, argl, args);
}
boost::any LangLua::Call(const char *name, const char *argl, const std::vector<boost::any> &args)
{
int n_args = (int)(strlen(argl)) ;
lua_getglobal (lua, name);
for (intptr_t i = 0; i < n_args; i++)
{
switch (argl[i])
{
case 'i':
luabridge::Stack<unsigned int>::push(lua, boost::any_cast<unsigned int>(args.at(i)));
break;
case 'q':
luabridge::Stack<signed int>::push(lua, boost::any_cast<signed int>(args.at(i)));
break;
case 'l':
luabridge::Stack<unsigned long long>::push(lua, boost::any_cast<unsigned long long>(args.at(i)));
break;
case 'w':
luabridge::Stack<signed long long>::push(lua, boost::any_cast<signed long long>(args.at(i)));
break;
case 'f':
luabridge::Stack<double>::push(lua, boost::any_cast<double>(args.at(i)));
break;
case 'p':
luabridge::Stack<void *>::push(lua, boost::any_cast<void *>(args.at(i)));
break;
case 's':
luabridge::Stack<const char *>::push(lua, boost::any_cast<const char *>(args.at(i)));
break;
default:
throw runtime_error("Lua call: Unknown argument identifier " + argl[i]);
}
}
luabridge::LuaException::pcall (lua, n_args, 1);
return boost::any(luabridge::LuaRef::fromStack(lua, -1));
}

@ -0,0 +1,56 @@
//
// Created by koncord on 08.05.16.
//
#ifndef PLUGINSYSTEM3_LANGLUA_HPP
#define PLUGINSYSTEM3_LANGLUA_HPP
#include <terra/terra.h>
#include <LuaBridge.h>
#include <boost/any.hpp>
#include "../ScriptFunction.hpp"
#include "../Language.hpp"
struct LuaFuctionData
{
const char* name;
lua_CFunction func;
};
class LangLua: public Language
{
private:
template<std::size_t... Is>
struct indices {};
template<std::size_t N, std::size_t... Is>
struct build_indices : build_indices<N-1, N-1, Is...> {};
template<std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<std::size_t N>
using IndicesFor = build_indices<N>;
public:
virtual void *GetInterface() override;
template<std::size_t... Indices>
static LuaFuctionData* functions(indices<Indices...>);
lua_State *lua;
public:
LangLua();
LangLua(lua_State *lua);
~LangLua();
static int MakePublic(lua_State *lua) noexcept;
static int CallPublic(lua_State *lua) noexcept;
static int CreateTimer(lua_State *lua) noexcept;
static int CreateTimerEx(lua_State *lua) noexcept;
virtual void LoadProgram(const char *filename) override;
virtual int FreeProgram() override;
virtual bool IsCallbackPresent(const char *name) override;
virtual boost::any Call(const char *name, const char *argl, int buf, ...) override;
virtual boost::any Call(const char *name, const char *argl, const std::vector<boost::any> &args) override;
};
#endif //PLUGINSYSTEM3_LANGLUA_HPP

@ -0,0 +1,182 @@
//
// Created by koncord on 09.05.16.
//
#include <iostream>
#include "LangLua.hpp"
#include <Script/API/TimerAPI.hpp>
#include <Script/API/PublicFnAPI.hpp>
using namespace std;
inline vector<boost::any> DefToVec(lua_State *lua, string types, int args_begin, int args_n)
{
vector<boost::any> args;
for(int i = args_begin; i < args_n + args_begin; i++)
{
switch(types[i - args_begin])
{
case 'i':
{
args.emplace_back(luabridge::Stack<unsigned int>::get(lua, i));
break;
}
case 'q':
{
args.emplace_back(luabridge::Stack<signed int>::get(lua, i));
break;
}
/*case 'l':
{
args.emplace_back(luabridge::Stack<unsigned long long>::get(lua, i));
break;
}
case 'w':
{
args.emplace_back(luabridge::Stack<signed long long>::get(lua, i));
break;
}*/
case 'f':
{
args.emplace_back(luabridge::Stack<double>::get(lua, i));
break;
}
case 's':
{
args.emplace_back(luabridge::Stack<const char*>::get(lua, i));
break;
}
default:
{
stringstream ssErr;
ssErr << "Lua: Unknown argument identifier" << "\"" << types[i] << "\"" << endl;
throw std::runtime_error(ssErr.str());
}
}
}
return args;
}
int LangLua::MakePublic(lua_State *lua) noexcept
{
const char * callback = luabridge::Stack<const char*>::get(lua, 1);
const char * name = luabridge::Stack<const char*>::get(lua, 2);
char ret_type = luabridge::Stack<char>::get(lua, 3);
const char * def = luabridge::Stack<const char*>::get(lua, 4);
Public::MakePublic(callback, lua, name, ret_type, def);
return 0;
}
int LangLua::CallPublic(lua_State *lua) noexcept
{
const char * name = luabridge::Stack<const char*>::get(lua, 1);
int args_n = lua_gettop(lua) - 1;
string types = Public::GetDefinition(name);
if(args_n != types.size())
throw invalid_argument("Script call: Number of arguments does not match definition");
vector<boost::any> args = DefToVec(lua, types, 2, args_n);
boost::any result = Public::Call(&name[0], args);
if(result.empty())
return 0;
if(result.type().hash_code() == typeid(signed int).hash_code())
luabridge::Stack<signed int>::push(lua, boost::any_cast<signed int>(result));
else if(result.type().hash_code() == typeid(unsigned int).hash_code())
luabridge::Stack<unsigned int>::push(lua, boost::any_cast<unsigned int>(result));
else if(result.type().hash_code() == typeid(double).hash_code())
luabridge::Stack<double>::push(lua, boost::any_cast<double>(result));
else if(result.type().hash_code() == typeid(const char*).hash_code())
luabridge::Stack<const char*>::push(lua, boost::any_cast<const char*>(result));
return 1;
}
int LangLua::CreateTimer(lua_State *lua) noexcept
{
const char * callback= luabridge::Stack<const char*>::get(lua, 1);
int msec = luabridge::Stack<int>::get(lua, 2);
int id = mwmp::TimerAPI::CreateTimerLua(lua, callback, msec, "", vector<boost::any>());
luabridge::push(lua, id);
return 1;
}
int LangLua::CreateTimerEx(lua_State *lua) noexcept
{
const char * callback = luabridge::Stack<const char*>::get(lua, 1);
int msec = luabridge::Stack<int>::get(lua, 2);
const char * types = luabridge::Stack<const char*>::get(lua, 3);
int args_n = (int)lua_strlen(lua, 3);
vector<boost::any> args;
for(int i = 4; i < args_n + 4; i++)
{
switch(types[i - 4])
{
case 'i':
{
args.emplace_back(luabridge::Stack<unsigned int>::get(lua, i));
break;
}
case 'q':
{
args.emplace_back(luabridge::Stack<signed int>::get(lua, i));
break;
}
/*case 'l':
{
args.emplace_back(luabridge::Stack<unsigned long long>::get(lua, i));
break;
}
case 'w':
{
args.emplace_back(luabridge::Stack<signed long long>::get(lua, i));
break;
}*/
case 'f':
{
args.emplace_back(luabridge::Stack<double>::get(lua, i));
break;
}
case 's':
{
args.emplace_back(luabridge::Stack<const char*>::get(lua, i));
break;
}
default:
{
stringstream ssErr;
ssErr << "Lua: Unknown argument identifier" << "\"" << types[i] << "\"" << endl;
throw std::runtime_error(ssErr.str());
}
}
}
int id = mwmp::TimerAPI::CreateTimerLua(lua, callback, msec, types, args);
luabridge::push(lua, id);
return 1;
}

@ -0,0 +1,99 @@
//
// Created by koncord on 09.05.16.
//
#include <dlfcn.h>
#include <stdexcept>
#include "LangNative.hpp"
#include <Script/SystemInterface.hpp>
#include <Script/Script.hpp>
using namespace std;
template<typename R>
bool SetScript(SystemInterface<>::lib_t lib, const char *name, R value)
{
SystemInterface<R *> result(lib, name);
if (result)
*result.result = value;
return result.operator bool();
}
void LangNative::LoadProgram(const char *filename)
{
FILE *file = fopen(filename, "rb");
if (!file)
throw runtime_error("Script not found: " + string(filename));
fclose(file);
#ifdef __WIN32__
lib = LoadLibrary(filename);
#else
lib = dlopen(filename, RTLD_LAZY);
#endif
if (!lib)
throw runtime_error("Was not able to load C++ script: " + string(filename));
try
{
const char *prefix = SystemInterface<const char *>(lib, "prefix").result;
string pf(prefix);
for (const auto &function : ScriptFunctions::functions)
if (!SetScript(lib, string(pf + function.name).c_str(), function.func.addr))
printf("Script function pointer not found: %s\n", function.name);
}
catch (...)
{
FreeProgram();
throw;
}
}
int LangNative::FreeProgram()
{
#ifdef __WIN32__
FreeLibrary(lib);
#else
dlclose(lib);
#endif
return 0;
}
bool LangNative::IsCallbackPresent(const char *name)
{
return true;
}
boost::any LangNative::Call(const char *name, const char *argl, int buf, ...)
{
return nullptr;
}
boost::any LangNative::Call(const char *name, const char *argl, const std::vector<boost::any> &args)
{
return nullptr;
}
void *LangNative::GetInterface()
{
return lib;
}
LangNative::LangNative()
{
}
LangNative::~LangNative()
{
}

@ -0,0 +1,28 @@
//
// Created by koncord on 09.05.16.
//
#ifndef PLUGINSYSTEM3_LANGNATIVE_HPP
#define PLUGINSYSTEM3_LANGNATIVE_HPP
#include <Script/Language.hpp>
#include <Script/SystemInterface.hpp>
class LangNative : public Language
{
SystemInterface<>::lib_t lib;
public:
virtual void *GetInterface() override;
LangNative();
~LangNative();
virtual void LoadProgram(const char *filename) override;
virtual int FreeProgram() override;
virtual bool IsCallbackPresent(const char *name) override;
virtual boost::any Call(const char *name, const char *argl, int buf, ...) override;
virtual boost::any Call(const char *name, const char *argl, const std::vector<boost::any> &args) override;
};
#endif //PLUGINSYSTEM3_LANGNATIVE_HPP

@ -0,0 +1,458 @@
//
// Created by koncord on 08.05.16.
//
#include "LangPAWN.hpp"
#include <amxmodules.h>
#include <amxaux.h>
#include "Script.hpp"
using namespace std;
typedef long NetworkID;
static vector<vector<char>> strings;
static vector<pair<cell*, double>> floats;
static pair<cell*, NetworkID*> data = {nullptr, nullptr};
void free_strings() noexcept {
strings.clear();
}
void free_floats() noexcept {
for (const auto& value : floats)
*value.first = amx_ftoc(value.second);
floats.clear();
}
void free_data(unsigned int size) noexcept {
if (data.first && data.second)
for (unsigned int i = 0; i < size; ++i)
data.first[i] = data.second[i];
data.first = nullptr;
data.second = nullptr;
}
void after_call() noexcept {
free_strings();
free_floats();
}
template<typename R>
void after_call(const R&) noexcept {
free_strings();
free_floats();
}
template<>
void after_call(const unsigned int& result) noexcept {
free_strings();
free_floats();
free_data(result);
}
template<typename R, unsigned int I, unsigned int F>
struct PAWN_extract_ {
inline static R PAWN_extract(AMX*&&, const cell*&& params) noexcept {
return static_cast<R>(forward<const cell*>(params)[I]);
}
};
template<unsigned int I, unsigned int F>
struct PAWN_extract_<void*, I, F>
{
inline static void* PAWN_extract(AMX *&&amx, const cell *&&params) noexcept
{
return amx_Address(amx, forward<const cell *>(params)[I]); // fixme: I'm not sure in this fix
}
};
template<unsigned int I, unsigned int F>
struct PAWN_extract_<double, I, F> {
inline static double PAWN_extract(AMX*&&, const cell*&& params) noexcept {
return amx_ctof(forward<const cell*>(params)[I]);
}
};
template<unsigned int I, unsigned int F>
struct PAWN_extract_<const char*, I, F> {
inline static const char* PAWN_extract(AMX*&& amx, const cell*&& params) noexcept {
int len;
cell* source;
source = amx_Address(amx, params[I]);
amx_StrLen(source, &len);
strings.emplace_back(len + 1);
char* value = &strings.back()[0];
amx_GetString(value, source, 0, UNLIMITED);
return value;
}
};
template<unsigned int I, unsigned int F>
struct PAWN_extract_<double*, I, F> {
inline static double* PAWN_extract(AMX*&& amx, const cell*&& params) noexcept {
floats.emplace_back(amx_Address(amx, params[I]), 0.00);
return &floats.back().second;
}
};
template<unsigned int I, unsigned int F>
struct PAWN_extract_<NetworkID**, I, F> {
inline static NetworkID** PAWN_extract(AMX*&& amx, const cell*&& params) noexcept {
constexpr ScriptFunctionData const& F_ = ScriptFunctions::functions[F];
static_assert(F_.func.numargs == I, "NetworkID** must be the last parameter");
data.first = amx_Address(amx, params[I]);
return &data.second;
}
};
template<unsigned int I, unsigned int F>
struct PAWN_dispatch_ {
template<typename R, typename... Args>
inline static R PAWN_dispatch(AMX*&& amx, const cell*&& params, Args&&... args) noexcept {
constexpr ScriptFunctionData const& F_ = ScriptFunctions::functions[F];
auto arg = PAWN_extract_<typename CharType<F_.func.types[I - 1]>::type, I, F>::PAWN_extract(forward<AMX*>(amx), forward<const cell*>(params));
return PAWN_dispatch_<I - 1, F>::template PAWN_dispatch<R>(
forward<AMX*>(amx),
forward<const cell*>(params),
arg,
forward<Args>(args)...);
}
};
template<unsigned int F>
struct PAWN_dispatch_<0, F> {
template<typename R, typename... Args>
inline static R PAWN_dispatch(AMX*&&, const cell*&&, Args&&... args) noexcept {
constexpr ScriptFunctionData const& F_ = ScriptFunctions::functions[F];
return reinterpret_cast<FunctionEllipsis<R>>(F_.func.addr)(forward<Args>(args)...);
}
};
template<unsigned int I>
static typename enable_if<ScriptFunctions::functions[I].func.ret == 'v', cell>::type wrapper(AMX* amx, const cell* params) noexcept {
PAWN_dispatch_<ScriptFunctions::functions[I].func.numargs, I>::template PAWN_dispatch<void>(forward<AMX*>(amx), forward<const cell*>(params));
after_call();
return 1;
}
template<unsigned int I>
static typename enable_if<ScriptFunctions::functions[I].func.ret == 'f', cell>::type wrapper(AMX* amx, const cell* params) noexcept {
double value = PAWN_dispatch_<ScriptFunctions::functions[I].func.numargs, I>::template PAWN_dispatch<double>(forward<AMX*>(amx), forward<const cell*>(params));
after_call();
return amx_ftoc(value);
}
template<unsigned int I>
static typename enable_if<ScriptFunctions::functions[I].func.ret == 's', cell>::type wrapper(AMX* amx, const cell* params) noexcept {
const char* value = PAWN_dispatch_<ScriptFunctions::functions[I].func.numargs, I>::template PAWN_dispatch<const char*>(forward<AMX*>(amx), forward<const cell*>(params));
after_call();
if (value) {
cell* dest = amx_Address(amx, params[ScriptFunctions::functions[I].func.numargs + 1]);
amx_SetString(dest, value, 1, 0, strlen(value) + 1);
return 1;
}
return 0;
}
template<unsigned int I>
static typename enable_if<ScriptFunctions::functions[I].func.ret != 'v' && ScriptFunctions::functions[I].func.ret != 'f' && ScriptFunctions::functions[I].func.ret != 's', cell>::type wrapper(AMX* amx, const cell* params) noexcept {
auto result = PAWN_dispatch_<ScriptFunctions::functions[I].func.numargs, I>::template PAWN_dispatch<typename CharType<ScriptFunctions::functions[I].func.ret>::type>(forward<AMX*>(amx), forward<const cell*>(params));
after_call(result);
return result;
}
template<unsigned int I> struct F_ { static constexpr AMX_NATIVE_INFO F{ScriptFunctions::functions[I].name, wrapper<I>}; };
template<> struct F_<0> { static constexpr AMX_NATIVE_INFO F{"CreateTimer", LangPAWN::CreateTimer}; };
template<> struct F_<1> { static constexpr AMX_NATIVE_INFO F{"CreateTimerEx", LangPAWN::CreateTimerEx}; };
template<> struct F_<2> { static constexpr AMX_NATIVE_INFO F{"MakePublic", LangPAWN::MakePublic}; };
template<> struct F_<3> { static constexpr AMX_NATIVE_INFO F{"CallPublic", LangPAWN::CallPublic}; };
void LangPAWN::LoadProgram(const char *filename)
{
int err = aux_LoadProgram(amx, filename, 0);
if (err != AMX_ERR_NONE)
throw runtime_error("PAWN script " + string(filename) + " error (" + to_string(err) + "): \"" + string(aux_StrError(err)) + "\"");
amx_CoreInit(amx);
amx_ConsoleInit(amx);
amx_FloatInit(amx);
amx_TimeInit(amx);
amx_StringInit(amx);
amx_FileInit(amx);
constexpr auto functions_n = sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0]);
amx_Register(amx, functions(IndicesFor<functions_n>{}), functions_n); // TODO: throw if error
}
int LangPAWN::FreeProgram()
{
int err = aux_FreeProgram(amx);
delete amx;
return err;
}
bool LangPAWN::IsCallbackPresent(const char *name)
{
int idx;
return (amx_FindPublic(amx, name, &idx) == AMX_ERR_NONE);
}
boost::any LangPAWN::Call(const char *name, const char *argl, int buf, ...)
{
va_list args;
va_start(args, buf);
cell ret = 0;
vector<pair<cell *, char *>> strings;
try
{
int idx = 0;
int err = 0;
err = amx_FindPublic(amx, name, &idx);
if (err != AMX_ERR_NONE)
throw runtime_error("PAWN runtime error (" + to_string(err) + "): \"" + string(aux_StrError(err)) + "\".");
unsigned int len = strlen(argl);
vector<cell> args_amx;
for (unsigned int i = 0; i < len; ++i)
{
switch (argl[i])
{
case 'i':
args_amx.emplace_back(va_arg(args, unsigned
int));
break;
case 'q':
args_amx.emplace_back(va_arg(args, signed
int));
break;
case 'l':
args_amx.emplace_back(va_arg(args, unsigned
long
long));
break;
case 'w':
args_amx.emplace_back(va_arg(args, signed
long
long));
break;
case 'f':
{
double value = va_arg(args, double);
args_amx.emplace_back(amx_ftoc(value));
break;
}
case 'p':
args_amx.emplace_back(reinterpret_cast<uintptr_t>(va_arg(args, void*)));
break;
case 's':
args_amx.emplace_back(reinterpret_cast<uintptr_t>(va_arg(args, char*)));
break;
default:
throw runtime_error("PAWN call: Unknown argument identifier " + argl[i]);
}
}
for (unsigned int i = len; i; --i)
{
switch (argl[i - 1])
{
case 's':
{
char *string = reinterpret_cast<char *>(static_cast<unsigned int>(args_amx[i - 1]));
cell *store;
amx_PushString(amx, &store, string, 1, 0);
strings.emplace_back(store, string);
break;
}
default:
amx_Push(amx, args_amx[i - 1]);
break;
}
}
err = amx_Exec(amx, &ret, idx);
if (err != AMX_ERR_NONE)
throw runtime_error("PAWN runtime error (" + to_string(err) + "): \"" + string(aux_StrError(err)) + "\".");
if (buf != 0)
for (const auto &str : strings)
amx_GetString(str.second, str.first, 0, strlen(str.second) + 1);
if (!strings.empty())
amx_Release(amx, strings[0].first);
}
catch (...)
{
va_end(args);
if (!strings.empty())
amx_Release(amx, strings[0].first);
throw;
}
return boost::any(ret);
}
boost::any LangPAWN::Call(const char *name, const char *argl, const std::vector<boost::any> &args)
{
cell ret = 0;
cell *str = nullptr;
try
{
int idx = 0;
int err = 0;
err = amx_FindPublic(amx, name, &idx);
if (err != AMX_ERR_NONE)
throw runtime_error("PAWN runtime error (" + to_string(err) + "): \"" + string(aux_StrError(err)) + "\".");
for (intptr_t i = strlen(argl) - 1; i >= 0; i--)
{
switch (argl[i])
{
case 'i':
{
cell value = (cell) boost::any_cast<unsigned int>(args.at(i));
amx_Push(amx, value);
break;
}
case 'q':
{
cell value = (cell) boost::any_cast<signed int>(args.at(i));
amx_Push(amx, value);
break;
}
case 'l':
{
cell value = (cell) boost::any_cast<unsigned long long>(args.at(i));
amx_Push(amx, value);
break;
}
case 'w':
{
cell value = (cell) boost::any_cast<signed long long>(args.at(i));
amx_Push(amx, value);
break;
}
case 'f':
{
double value = boost::any_cast<double>(args.at(i));
amx_Push(amx, amx_ftoc(value));
break;
}
case 'p':
{
cell value = (cell) boost::any_cast<void *>(args.at(i));
amx_Push(amx, value);
break;
}
case 's':
{
string string_ = boost::any_cast<string>(args.at(i));
cell *store;
amx_PushString(amx, &store, string_.c_str(), 1, 0);
if (!str)
str = store;
break;
}
default:
throw runtime_error("PAWN call: Unknown argument identifier " + argl[i]);
}
}
err = amx_Exec(amx, &ret, idx);
if (err != AMX_ERR_NONE)
throw runtime_error("PAWN runtime error (" + to_string(err) + "): \"" + string(aux_StrError(err)) + "\".");
if (str)
amx_Release(amx, str);
}
catch (...)
{
if (str)
amx_Release(amx, str);
throw;
}
return ret;
}
template<size_t... Indices>
inline AMX_NATIVE_INFO *LangPAWN::functions(indices<Indices...>)
{
static AMX_NATIVE_INFO functions_[sizeof...(Indices)]{
F_<Indices>::F...
};
static_assert(
sizeof(functions_) / sizeof(functions_[0]) == sizeof(ScriptFunctions::functions) / sizeof(ScriptFunctions::functions[0]),
"Not all functions have been mapped to PAWN");
return functions_;
}
void *LangPAWN::GetInterface()
{
return amx;
}
LangPAWN::LangPAWN()
{
//throw std::runtime_error("Pawn is no longer supported, use Terra/Lua!");
amx = new AMX();
}
LangPAWN::LangPAWN(AMX *amx)
{
this->amx = amx;
}
LangPAWN::~LangPAWN()
{
}

@ -0,0 +1,46 @@
//
// Created by koncord on 08.05.16.
//
#ifndef PLUGINSYSTEM3_LANGPAWN_HPP
#define PLUGINSYSTEM3_LANGPAWN_HPP
#include "Language.hpp"
#include <amx.h>
class LangPAWN: public Language
{
private:
template<std::size_t... Is>
struct indices {};
template<std::size_t N, std::size_t... Is>
struct build_indices : build_indices<N-1, N-1, Is...> {};
template<std::size_t... Is>
struct build_indices<0, Is...> : indices<Is...> {};
template<std::size_t N>
using IndicesFor = build_indices<N>;
public:
virtual void *GetInterface() override;
template<std::size_t... Indices>
static AMX_NATIVE_INFO* functions(indices<Indices...>);
AMX *amx;
public:
LangPAWN();
LangPAWN(AMX *amx);
~LangPAWN();
static cell MakePublic(AMX *amx, const cell *params) noexcept;
static cell CallPublic(AMX *amx, const cell *params) noexcept;
static cell CreateTimer(AMX *amx, const cell *params) noexcept;
static cell CreateTimerEx(AMX *amx, const cell *params) noexcept;
virtual void LoadProgram(const char *filename) override;
virtual int FreeProgram() override;
virtual bool IsCallbackPresent(const char *name) override;
virtual boost::any Call(const char *name, const char *argl, int buf, ...) override;
virtual boost::any Call(const char *name, const char *argl, const std::vector<boost::any> &args) override;
};
#endif //PLUGINSYSTEM3_LANGPAWN_HPP

@ -0,0 +1,154 @@
//
// Created by koncord on 09.05.16.
//
#include <API/PublicFnAPI.hpp>
#include "LangPAWN.hpp"
#include "API/TimerAPI.hpp"
using namespace std;
cell LangPAWN::MakePublic(AMX *amx, const cell *params) noexcept
{
int len;
cell* source;
source = amx_Address(amx, params[1]);
amx_StrLen(source, &len);
vector<char> real;
real.reserve(len + 1);
amx_GetString(&real[0], source, 0, UNLIMITED);
source = amx_Address(amx, params[2]);
amx_StrLen(source, &len);
vector<char> name;
name.reserve(len + 1);
amx_GetString(&name[0], source, 0, UNLIMITED);
cell *ret_addr = amx_Address(amx, params[3]);
char ret_type = static_cast<char>(*reinterpret_cast<cell*>(&ret_addr));
source = amx_Address(amx, params[4]);
amx_StrLen(source, &len);
vector<char> def;
def.reserve(len + 1);
amx_GetString(&def[0], source, 0, UNLIMITED);
Public::MakePublic(&real[0], amx, &name[0], ret_type, &def[0]);
return 1;
}
cell LangPAWN::CallPublic(AMX *amx, const cell *params) noexcept
{
int len;
cell* source;
source = amx_Address(amx, params[1]);
amx_StrLen(source, &len);
vector<char> name;
name.reserve(len + 1);
amx_GetString(&name[0], source, 0, UNLIMITED);
string def;
try
{
def = Public::GetDefinition(&name[0]);
}
catch (...) { return 0; }
vector<boost::any> args;
unsigned int count = (params[0] / sizeof(cell)) - 1;
if (count != def.length())
throw runtime_error("Script call: Number of arguments does not match definition");
for (unsigned int i = 0; i < count; ++i)
{
cell* data = amx_Address(amx, params[i + 2]);
switch (def[i])
{
case 'i':
{
args.emplace_back((unsigned int) *data);
break;
}
case 'q':
{
args.emplace_back((signed int) *data);
break;
}
case 'l':
{
args.emplace_back((unsigned long long) *data);
break;
}
case 'w':
{
args.emplace_back((signed long long) *data);
break;
}
case 'f':
{
args.emplace_back((double) amx_ctof(*data));
break;
}
case 'p':
{
args.emplace_back((void*) data);
break;
}
case 's':
{
amx_StrLen(data, &len);
vector<char> str;
str.reserve(len + 1);
amx_GetString(&str[0], data, 0, UNLIMITED);
args.emplace_back(string(&str[0]).c_str());
break;
}
default:
throw runtime_error("PAWN call: Unknown argument identifier " + def[i]);
}
}
boost::any result = Public::Call(&name[0], args);
if(result.empty())
return 0;
cell ret = 0;
if(result.type().hash_code() == typeid(signed int).hash_code())
ret = boost::any_cast<signed int>(result);
else if(result.type().hash_code() == typeid(unsigned int).hash_code())
ret = boost::any_cast<unsigned int>(result);
else if(result.type().hash_code() == typeid(double).hash_code())
ret = amx_ftoc(result);
return ret;
}
cell LangPAWN::CreateTimer(AMX *amx, const cell *params) noexcept
{
}
cell LangPAWN::CreateTimerEx(AMX *amx, const cell *params) noexcept
{
}

@ -0,0 +1,27 @@
//
// Created by koncord on 19.03.16.
//
#ifndef PLUGINSYSTEM3_LANGUAGE_HPP
#define PLUGINSYSTEM3_LANGUAGE_HPP
#include "Types.hpp"
#include <boost/any.hpp>
#include <vector>
class Language
{
public:
virtual void LoadProgram(const char* filename) = 0;
virtual int FreeProgram() = 0;
virtual bool IsCallbackPresent(const char* name) = 0;
virtual boost::any Call(const char* name, const char* argl, int buf, ...) = 0;
virtual boost::any Call(const char* name, const char* argl, const std::vector<boost::any>& args) = 0;
virtual void * GetInterface() = 0;
};
#endif //PLUGINSYSTEM3_LANGUAGE_HPP

@ -0,0 +1,20 @@
//
// Created by koncord on 23.01.16.
//
#ifndef SOURCEPAWN_PLATFORM_HPP
#define SOURCEPAWN_PLATFORM_HPP
#if _MSC_VER
#ifdef _M_X86
#define ARCH_X86
#endif
#endif
#if __GNUC__
#ifdef __i386__
#define ARCH_X86
#endif
#endif
#endif //SOURCEPAWN_PLATFORM_HPP

@ -0,0 +1,109 @@
//
// Created by koncord on 19.03.16.
//
#include "Script.hpp"
#include "LangNative/LangNative.hpp"
#if defined (ENABLE_PAWN)
#include "LangPawn/LangPAWN.hpp"
#endif
#if defined (ENABLE_LUA)
#include "LangLua/LangLua.hpp"
#endif
using namespace std;
Script::ScriptList Script::scripts;
Script::Script(const char *path)
{
FILE *file = fopen(path, "rb");
if (!file)
throw runtime_error("Script not found: " + string(path));
fclose(file);
#ifdef __WIN32__
if (strstr(path, ".dll"))
#else
if (strstr(path, ".so"))
#endif
{
script_type = SCRIPT_CPP;
lang = new LangNative();
}
#if defined (ENABLE_PAWN)
else if (strstr(path, ".amx"))
{
lang = new LangPAWN();
script_type = SCRIPT_PAWN;
}
#endif
#if defined (ENABLE_LUA)
else if (strstr(path, ".lua") || strstr(path, ".t"))
{
lang = new LangLua();
script_type = SCRIPT_LUA;
}
#endif
else
throw runtime_error("Script type not recognized: " + string(path));
try
{
lang->LoadProgram(path);
}
catch (...)
{
lang->FreeProgram();
throw;
}
}
Script::~Script()
{
lang->FreeProgram();
delete lang;
}
void Script::LoadScripts(char *scripts, const char *base)
{
char *token = strtok(scripts, ",");
try
{
while (token)
{
char path[4096];
snprintf(path, sizeof(path), "%s/%s/%s", base, "scripts", token);
Script::scripts.emplace_back(new Script(path));
token = strtok(nullptr, ",");
}
}
catch (...)
{
UnloadScripts();
throw;
}
}
void Script::UnloadScripts()
{
//Public::DeleteAll();
scripts.clear();
#if defined (ENABLE_LUA)
terra_llvmshutdown();
#endif
}
void Script::LoadScript(const char *script, const char *base)
{
char path[4096];
snprintf(path, sizeof(path), "%s/%s/%s", base, "scripts", script);
Script::scripts.emplace_back(new Script(path));
}

@ -0,0 +1,155 @@
//
// Created by koncord on 19.03.16.
//
#ifndef PLUGINSYSTEM3_SCRIPT_HPP
#define PLUGINSYSTEM3_SCRIPT_HPP
#include "Types.hpp"
#include "SystemInterface.hpp"
#include "ScriptFunction.hpp"
#include "ScriptFunctions.hpp"
#include "Language.hpp"
#include <boost/any.hpp>
#include <Utils.hpp>
#include <unordered_map>
#include <memory>
#if defined (ENABLE_LUA)
#include <terra/terra.h>
#include <extern/LuaBridge/LuaBridge.h>
#endif
class Script : private ScriptFunctions
{
// http://imgur.com/hU0N4EH
private:
Language *lang;
enum
{
SCRIPT_CPP,
SCRIPT_PAWN,
SCRIPT_LUA
};
template<typename R>
R GetScript(const char *name)
{
if(script_type == SCRIPT_CPP)
{
return SystemInterface<R>(lang->GetInterface(), name).result;
}
else
{
return reinterpret_cast<R>(lang->IsCallbackPresent(name));
}
}
int script_type;
std::unordered_map<unsigned int, FunctionEllipsis<void>> callbacks_;
typedef std::vector<std::unique_ptr<Script>> ScriptList;
static ScriptList scripts;
Script(const char *path);
Script(const Script&) = delete;
Script& operator=(const Script&) = delete;
public:
~Script();
static void LoadScript(const char *script, const char* base);
static void LoadScripts(char* scripts, const char* base);
static void UnloadScripts();
static constexpr ScriptCallbackData const& CallBackData(const unsigned int I, const unsigned int N = 0) {
return callbacks[N].index == I ? callbacks[N] : CallBackData(I, N + 1);
}
template<unsigned int I>
using CallBackReturn = typename CharType<CallBackData(I).callback.ret>::type;
template<size_t N>
static constexpr unsigned int CallbackIdentity(const char(&str)[N])
{
return Utils::hash(str);
}
template<unsigned int I, bool B = false, typename... Args>
static unsigned int Call(CallBackReturn<I>& result, Args&&... args) {
constexpr ScriptCallbackData const& data = CallBackData(I);
static_assert(data.callback.matches(TypeString<typename std::remove_reference<Args>::type...>::value), "Wrong number or types of arguments");
unsigned int count = 0;
for (auto& script : scripts)
{
if (!script->callbacks_.count(I))
script->callbacks_.emplace(I, script->GetScript<FunctionEllipsis<void>>(data.name));
auto callback = script->callbacks_[I];
if (!callback)
continue;
if (script->script_type == SCRIPT_CPP)
result = reinterpret_cast<FunctionEllipsis<CallBackReturn<I>>>(callback)(std::forward<Args>(args)...);
#if defined (ENABLE_PAWN)
else if(script->script_type == SCRIPT_PAWN)
{
boost::any any = script->lang->Call(data.name, data.callback.types, B, std::forward<Args>(args)...);
result = reinterpret_cast<CallBackReturn<I>> ((int)boost::any_cast<int64_t>(any)); // TODO: WTF?! int?!
}
#endif
#if defined (ENABLE_LUA)
else if(script->script_type == SCRIPT_LUA)
{
boost::any any = script->lang->Call(data.name, data.callback.types, B, std::forward<Args>(args)...);
result = static_cast<CallBackReturn<I>>(boost::any_cast<luabridge::LuaRef>(any).cast<CallBackReturn<I>>());
}
#endif
++count;
}
return count;
}
template<unsigned int I, bool B = false, typename... Args>
static unsigned int Call(Args&&... args) {
constexpr ScriptCallbackData const& data = CallBackData(I);
static_assert(data.callback.matches(TypeString<typename std::remove_reference<Args>::type...>::value), "Wrong number or types of arguments");
unsigned int count = 0;
for (auto& script : scripts)
{
if (!script->callbacks_.count(I))
script->callbacks_.emplace(I, script->GetScript<FunctionEllipsis<void>>(data.name));
auto callback = script->callbacks_[I];
if (!callback)
continue;
if (script->script_type == SCRIPT_CPP)
reinterpret_cast<FunctionEllipsis<CallBackReturn<I>>>(callback)(std::forward<Args>(args)...);
#if defined (ENABLE_PAWN)
else if(script->script_type == SCRIPT_PAWN)
script->lang->Call(data.name, data.callback.types, B, std::forward<Args>(args)...);
#endif
#if defined (ENABLE_LUA)
else if(script->script_type == SCRIPT_LUA)
script->lang->Call(data.name, data.callback.types, B, std::forward<Args>(args)...);
#endif
++count;
}
return count;
}
};
#endif //PLUGINSYSTEM3_SCRIPT_HPP

@ -0,0 +1,225 @@
//
// Created by koncord on 23.01.16.
//
#include<iostream>
#include <stdexcept>
#include "ScriptFunction.hpp"
#if defined (ENABLE_LUA)
#include "LangLua/LangLua.hpp"
#endif
#if defined (ENABLE_PAWN)
#include "LangPawn/LangPAWN.hpp"
#endif
using namespace std;
ScriptFunction::ScriptFunction(ScriptFunc fCpp,char ret_type, const string &def) : fCpp(fCpp), ret_type(ret_type), def(def), script_type(SCRIPT_CPP)
{
}
#if defined (ENABLE_LUA)
ScriptFunction::ScriptFunction(const ScriptFuncLua &fLua, lua_State *lua, char ret_type, const std::string &def) :fLua({lua, fLua}), ret_type(ret_type), def(def), script_type(SCRIPT_LUA)
{
}
#endif
#if defined (ENABLE_PAWN)
ScriptFunction::ScriptFunction(const ScriptFuncPAWN &fPawn, AMX *amx, char ret_type, const string &def) : fPawn({amx, fPawn}),
def(def), ret_type(ret_type), script_type(SCRIPT_PAWN)
{
}
#endif
ScriptFunction::~ScriptFunction()
{
#if defined (ENABLE_PAWN)
if (script_type == SCRIPT_PAWN)
fPawn.name.~ScriptFuncPAWN();
#if defined (ENABLE_LUA)
else
#endif
#endif
#if defined (ENABLE_LUA)
if (script_type == SCRIPT_LUA)
fLua.name.~ScriptFuncLua();
#endif
}
boost::any ScriptFunction::Call(const vector<boost::any> &args)
{
boost::any result;
if (def.length() != args.size())
throw runtime_error("Script call: Number of arguments does not match definition");
#if defined (ENABLE_PAWN)
if (script_type == SCRIPT_PAWN)
{
LangPAWN langPawn(fPawn.amx);
boost::any any = langPawn.Call(fPawn.name.c_str(), def.c_str(), args);
result = boost::any();
cell ret = boost::any_cast<cell>(any);
switch(ret_type)
{
case 'i':
result = static_cast<unsigned int>(ret);
break;
case 'q':
result = static_cast<signed int>(ret);
break;
case 's':
throw runtime_error("Pawn call: the Pawn does not supported strings in public functions");
case 'f':
result = static_cast<double>(amx_ctof(ret));
break;
case 'v':
result = boost::any();
break;
default:
throw runtime_error("Pawn call: Unknown return type" + ret_type);
}
}
#endif
#if defined (ENABLE_LUA)
else if (script_type == SCRIPT_LUA)
{
LangLua langLua(fLua.lua);
boost::any any = langLua.Call(fLua.name.c_str(), def.c_str(), args);
switch(ret_type)
{
case 'i':
result = boost::any_cast<luabridge::LuaRef>(any).cast<unsigned int>();
break;
case 'q':
result = boost::any_cast<luabridge::LuaRef>(any).cast<signed int>();
break;
case 'f':
result = boost::any_cast<luabridge::LuaRef>(any).cast<double>();
break;
case 's':
result = boost::any_cast<luabridge::LuaRef>(any).cast<const char*>();
break;
case 'v':
result = boost::any();
break;
default:
throw runtime_error("Lua call: Unknown return type" + ret_type);
}
}
#endif
else
{
throw runtime_error("Native Call: native calls does not supported yet");
#if 0
#ifdef ARCH_X86
// cdecl convention
string::iterator it;
vector<boost::any>::const_iterator it2;
vector<unsigned int> data;
for (it = def.begin(), it2 = args.begin(); it != def.end(); ++it, ++it2)
{
switch (*it)
{
case 'i':
{
unsigned int value = boost::any_cast<unsigned int>(*it2);
data.push_back(value);
break;
}
case 'q':
{
unsigned int value = boost::any_cast<signed int>(*it2);
data.push_back(value);
break;
}
case 'l':
{
unsigned long long value = boost::any_cast<unsigned long long>(*it2);
data.push_back(*reinterpret_cast<unsigned int *>(&value));
data.push_back(*reinterpret_cast<unsigned int *>((unsigned) &value + 4));
break;
}
case 'w':
{
signed long long value = boost::any_cast<signed long long>(*it2);
data.push_back(*reinterpret_cast<unsigned int *>(&value));
data.push_back(*reinterpret_cast<unsigned int *>((unsigned) &value + 4));
break;
}
case 'f':
{
double value = boost::any_cast<double>(*it2);
data.push_back(*reinterpret_cast<unsigned int *>(&value));
data.push_back(*reinterpret_cast<unsigned int *>((unsigned) &value + 4));
break;
}
case 'p':
{
void *value = boost::any_cast<void *>(*it2);
data.push_back(reinterpret_cast<unsigned int>(value));
break;
}
case 's':
{
const string *value = boost::any_cast<string>(&*it2);
data.push_back(reinterpret_cast<unsigned int>(value->c_str()));
break;
}
default:
throw runtime_error("C++ call: Unknown argument identifier " + *it);
}
}
unsigned int result_low;
unsigned int result_high;
unsigned int *source = &data[0];
unsigned int size = data.size() * 4;
asm(
"MOV EDI,ESP\n"
"SUB EDI,%3\n" // allocate memory in stack.
"MOV ESI,%4\n" // move ptr of source to ESI.
"MOV ECX,%3\n" // length of data.
"PUSH DS\n" // move DS
"POP ES\n" // to ES.
"CLD\n" // clear direction flag.
"REP MOVSB\n" // Move bytes at address DS:ESI to address ES:EDI (move to stack).
"MOV ESI,ESP\n" // stack pointer.
"SUB ESP,%3\n"
"CALL %2\n"
"MOV ESP,ESI\n"
"MOV %0,EAX\n" // move low result from eax
"MOV %1,EDX\n" // move high result from edx
: "=m"(result_low), "=m"(result_high)
: "m"(fCpp) //2, "m"(size) //3, "m"(source) //4
: "eax", "edx", "ecx", "esi", "edi", "cc"
);
*reinterpret_cast<unsigned int *>(&result) = result_low;
*reinterpret_cast<unsigned int *>(((unsigned) &result) + 4) = result_high;
#else
throw runtime_error("x64 Not supported yet (builtin timers and [Call/Make]Public");
#endif
#endif
}
return result;
}

@ -0,0 +1,72 @@
//
// Created by koncord on 23.01.16.
//
#ifndef SOURCEPAWN_SCRIPTFUNCTION_HPP
#define SOURCEPAWN_SCRIPTFUNCTION_HPP
#include <boost/any.hpp>
#include <string>
#include <vector>
#if defined (ENABLE_LUA)
#include <terra/terra.h>
#endif
#if defined (ENABLE_PAWN)
#include <amx.h>
#endif
typedef unsigned long long(*ScriptFunc)();
#if defined (ENABLE_PAWN)
typedef std::string ScriptFuncPAWN;
#endif
#if defined (ENABLE_LUA)
typedef std::string ScriptFuncLua;
#endif
class ScriptFunction
{
protected:
union
{
ScriptFunc fCpp;
#if defined (ENABLE_PAWN)
struct
{
AMX *amx;
ScriptFuncPAWN name;
} fPawn;
#endif
#if defined (ENABLE_LUA)
struct
{
lua_State *lua;
ScriptFuncLua name;
} fLua;
#endif
};
protected:
std::string def;
char ret_type;
int script_type;
enum
{
SCRIPT_CPP,
SCRIPT_PAWN,
SCRIPT_LUA
};
ScriptFunction(ScriptFunc fCpp, char ret_type, const std::string &def);
#if defined (ENABLE_LUA)
ScriptFunction(const ScriptFuncLua &fPawn, lua_State *lua, char ret_type, const std::string &def);
#endif
#if defined (ENABLE_PAWN)
ScriptFunction(const ScriptFuncPAWN &fPawn, AMX *amx, char ret_type, const std::string &def);
#endif
virtual ~ScriptFunction();
boost::any Call(const std::vector<boost::any> &args);
};
#endif //SOURCEPAWN_SCRIPTFUNCTION_HPP

@ -0,0 +1,120 @@
//
// Created by koncord on 24.01.16.
//
#include "ScriptFunctions.hpp"
#include "API/PublicFnAPI.hpp"
#include <cstdarg>
#include <iostream>
#include <apps/openmw-mp/Player.hpp>
#include <apps/openmw-mp/Networking.hpp>
#include <components/openmw-mp/NetworkMessages.hpp>
template<typename... Types>
constexpr char TypeString<Types...>::value[];
constexpr ScriptFunctionData ScriptFunctions::functions[];
constexpr ScriptCallbackData ScriptFunctions::callbacks[];
using namespace std;
void ScriptFunctions::GetArguments(std::vector<boost::any> &params, va_list args, const std::string &def)
{
params.reserve(def.length());
try
{
for (char c : def)
{
switch (c)
{
case 'i':
{
params.emplace_back(va_arg(args, unsigned int));
break;
}
case 'q':
{
params.emplace_back(va_arg(args, signed int));
break;
}
case 'l':
{
params.emplace_back(va_arg(args, unsigned long long));
break;
}
case 'w':
{
params.emplace_back(va_arg(args, signed long long));
break;
}
case 'f':
{
params.emplace_back(va_arg(args, double));
break;
}
case 'p':
{
params.emplace_back(va_arg(args, void*));
break;
}
case 's':
{
params.emplace_back(string(va_arg(args, const char*)));
break;
}
default:
throw runtime_error("C++ call: Unknown argument identifier " + c);
}
}
}
catch (...)
{
va_end(args);
throw;
}
}
void ScriptFunctions::MakePublic(ScriptFunc _public, const char *name, char ret_type, const char *def) noexcept
{
Public::MakePublic(_public, name, ret_type, def);
}
boost::any ScriptFunctions::CallPublic(const char *name, ...) noexcept
{
vector<boost::any> params;
try
{
string def = Public::GetDefinition(name);
va_list args;
va_start(args, name);
GetArguments(params, args, def);
va_end(args);
return Public::Call(name, params);
}
catch (...) {}
return 0;
}
void ScriptFunctions::StopServer(int code) noexcept
{
mwmp::Networking::GetPtr()->StopServer(code);
}
void ScriptFunctions::Kick(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player,);
mwmp::Networking::GetPtr()->KickPlayer(player->guid);
}

@ -0,0 +1,227 @@
//
// Created by koncord on 24.01.16.
//
#ifndef SOURCEPAWN_SCRIPTFUNCTIONS_HPP
#define SOURCEPAWN_SCRIPTFUNCTIONS_HPP
#include <RakNetTypes.h>
//#include <amx/amx.h>
#include <tuple>
#include <apps/openmw-mp/Player.hpp>
#include "ScriptFunction.hpp"
#include "Types.hpp"
#define GET_PLAYER(pid, pl, retvalue) \
pl = Players::GetPlayer(pid); \
if (player == 0) {\
fprintf(stderr, "%s: Player with pid \'%d\' not found\n", __PRETTY_FUNCTION__, pid);\
/*ScriptFunctions::StopServer(1);*/ \
return retvalue;\
}
class ScriptFunctions
{
public:
static void GetArguments(std::vector<boost::any> &params, va_list args, const std::string &def);
static void StopServer(int code) noexcept;
static void MakePublic(ScriptFunc _public, const char *name, char ret_type, const char *def) noexcept;
static boost::any CallPublic(const char *name, ...) noexcept;
static void GetPos(unsigned short pid, float *x, float *y, float *z) noexcept;
static void SetPos(unsigned short pid, float x, float y, float z) noexcept;
static void GetAngle(unsigned short pid, float *x, float *y, float *z) noexcept;
static void SetAngle(unsigned short pid, float x, float y, float z) noexcept;
static void SetCell(unsigned short pid, const char *name) noexcept;
static const char *GetCell(unsigned short pid) noexcept;
static bool IsInInterior(unsigned short pid) noexcept;
static void SetName(unsigned short pid, const char *name) noexcept;
static const char *GetName(unsigned short pid) noexcept;
static void SetBirthsign(unsigned short pid, const char *name) noexcept;
static const char *GetBirthsign(unsigned short pid) noexcept;
static void SetRace(unsigned short pid, const char *race) noexcept;
static const char *GetRace(unsigned short pid) noexcept;
static void SetHead(unsigned short pid, const char *head) noexcept;
static const char *GetHead(unsigned short pid) noexcept;
static void SetHairstyle(unsigned short pid, const char *style) noexcept;
static const char *GetHairstyle(unsigned short pid) noexcept;
static void SetIsMale(unsigned short pid, int male) noexcept;
static int GetIsMale(unsigned short pid) noexcept;
static float GetHealth(unsigned short pid) noexcept;
static void SetHealth(unsigned short pid, float health) noexcept;
static float GetCurrentHealth(unsigned short pid) noexcept;
static void SetCurrentHealth(unsigned short pid, float health) noexcept;
static float GetMagicka(unsigned short pid) noexcept;
static void SetMagicka(unsigned short pid, float magicka) noexcept;
static float GetCurrentMagicka(unsigned short pid) noexcept;
static void SetCurrentMagicka(unsigned short pid, float magicka) noexcept;
static float GetFatigue(unsigned short pid) noexcept;
static void SetFatigue(unsigned short pid, float fatigue) noexcept;
static float GetCurrentFatigue(unsigned short pid) noexcept;
static void SetCurrentFatigue(unsigned short pid, float fatigue) noexcept;
static int GetAttribute(unsigned short pid, unsigned short attribute) noexcept;
static void SetAttribute(unsigned short pid, unsigned short attribute, int value) noexcept;
static int GetCurrentAttribute(unsigned short pid, unsigned short attribute) noexcept;
static void SetCurrentAttribute(unsigned short pid, unsigned short attribute, int value) noexcept;
static int GetSkill(unsigned short pid, unsigned short skill) noexcept;
static void SetSkill(unsigned short pid, unsigned short skill, int value) noexcept;
static int GetCurrentSkill(unsigned short pid, unsigned short skill) noexcept;
static void SetCurrentSkill(unsigned short pid, unsigned short skill, int value) noexcept;
static int GetIncreaseSkill(unsigned short pid, unsigned int pos) noexcept;
static void SetIncreaseSkill(unsigned short pid, unsigned int pos, int value) noexcept;
//static void AddItem(unsigned short pid, const char* itemName, unsigned short count) noexcept;
//static void RemoveItem(unsigned short pid, const char* itemName, unsigned short count) noexcept;
//static void GetItemCount(unsigned short pid, const char* itemName) noexcept;
static void EquipItem(unsigned short pid, unsigned short slot, const char* itemName, unsigned short count) noexcept;
static void UnequipItem(unsigned short pid, unsigned short slot) noexcept;
static bool HasItemEquipped(unsigned short pid, const char* itemName);
static const char *GetItemSlot(unsigned short pid, unsigned short slot) noexcept;
static void SendMessage(unsigned short pid, const char *message, bool broadcast) noexcept;
static void CleanChat(unsigned short pid);
static void CleanChat();
static void SetCharGenStage(unsigned short pid, int start, int end) noexcept;
/**
* \brief Create timer
* \param callback
* \param msec
* \return return timer id
*/
static int CreateTimer(ScriptFunc callback, int msec) noexcept;
static int CreateTimerEx(ScriptFunc callback, int msec, const char *types, ...) noexcept;
static void StartTimer(int timerId) noexcept;
static void StopTimer(int timerId) noexcept;
static void RestartTimer(int timerId, int msec) noexcept;
static void FreeTimer(int timerId) noexcept;
static bool IsTimerElapsed(int timerId) noexcept;
static void Kick(unsigned short pid) noexcept;
static constexpr ScriptFunctionData functions[]{
{"CreateTimer", ScriptFunctions::CreateTimer},
{"CreateTimerEx", reinterpret_cast<Function<void>>(ScriptFunctions::CreateTimerEx)},
{"MakePublic", ScriptFunctions::MakePublic},
{"CallPublic", reinterpret_cast<Function<void>>(ScriptFunctions::CallPublic)},
{"StartTimer", ScriptFunctions::StartTimer},
{"StopTimer", ScriptFunctions::StopTimer},
{"RestartTimer", ScriptFunctions::RestartTimer},
{"FreeTimer", ScriptFunctions::FreeTimer},
{"IsTimerElapsed", ScriptFunctions::IsTimerElapsed},
{"StopServer", ScriptFunctions::StopServer},
{"GetPos", ScriptFunctions::GetPos},
{"SetPos", ScriptFunctions::SetPos},
{"GetAngle", ScriptFunctions::GetAngle},
{"SetAngle", ScriptFunctions::SetAngle},
{"GetCell", ScriptFunctions::GetCell},
{"SetCell", ScriptFunctions::SetCell},
{"IsInInterior", ScriptFunctions::IsInInterior},
{"GetName", ScriptFunctions::GetName},
{"SetName", ScriptFunctions::SetName},
{"GetRace", ScriptFunctions::GetRace},
{"SetRace", ScriptFunctions::SetRace},
{"GetHead", ScriptFunctions::GetHead},
{"SetHead", ScriptFunctions::SetHead},
{"GetHair", ScriptFunctions::GetHairstyle},
{"SetHair", ScriptFunctions::SetHairstyle},
{"GetIsMale", ScriptFunctions::GetIsMale},
{"SetIsMale", ScriptFunctions::SetIsMale},
{"GetBirthsign", ScriptFunctions::GetBirthsign},
{"SetBirthsign", ScriptFunctions::SetBirthsign},
{"GetAttribute", ScriptFunctions::GetAttribute},
{"SetAttribute", ScriptFunctions::SetAttribute},
{"GetCurrentAttribute", ScriptFunctions::GetCurrentAttribute},
{"SetCurrentAttribute", ScriptFunctions::SetCurrentAttribute},
{"GetSkill", ScriptFunctions::GetSkill},
{"SetSkill", ScriptFunctions::SetSkill},
{"GetCurrentSkill", ScriptFunctions::GetCurrentSkill},
{"SetCurrentSkill", ScriptFunctions::SetCurrentSkill},
{"GetHealth", ScriptFunctions::GetHealth},
{"SetHealth", ScriptFunctions::SetHealth},
{"GetCurrentHealth", ScriptFunctions::GetCurrentHealth},
{"SetCurrentHealth", ScriptFunctions::SetCurrentHealth},
{"GetMagicka", ScriptFunctions::GetMagicka},
{"SetMagicka", ScriptFunctions::SetMagicka},
{"GetCurrentMagicka", ScriptFunctions::GetCurrentMagicka},
{"SetCurrentMagicka", ScriptFunctions::SetCurrentMagicka},
{"SetFatigue", ScriptFunctions::SetFatigue},
{"GetFatigue", ScriptFunctions::GetFatigue},
{"SetCurrentFatigue", ScriptFunctions::SetCurrentFatigue},
{"GetCurrentFatigue", ScriptFunctions::GetCurrentFatigue},
// {"SetClass", ScriptFunctions::SetClass},
// {"GetClass", ScriptFunctions::GetClass},
{"GetIncreaseSkill", ScriptFunctions::GetIncreaseSkill},
{"SetIncreaseSkill", ScriptFunctions::SetIncreaseSkill},
// {"Cast", ScriptFunctions::Cast},
// {"AddItem", ScriptFunctions::AddItem},
// {"RemoveItem", ScriptFunctions::RemoveItem},
// {"GetItemCount", ScriptFunctions::GetItemCount},
{"EquipItem", ScriptFunctions::EquipItem},
{"UnequipItem", ScriptFunctions::UnequipItem},
{"GetItemSlot", ScriptFunctions::GetItemSlot},
{"HasItemEquipped", ScriptFunctions::HasItemEquipped},
{"SendMessage", ScriptFunctions::SendMessage},
{"SetCharGenStage", ScriptFunctions::SetCharGenStage},
{"Kick", ScriptFunctions::Kick},
};
static constexpr ScriptCallbackData callbacks[]{
{"Main", Function<int, int, int>()},
{"OnServerInit", Function<void>()},
{"OnServerExit", Function<void, bool>()},
{"OnPlayerConnect", Function<bool, unsigned short>()},
{"OnPlayerDisconnect", Function<void, unsigned short>()},
{"OnPlayerDeath", Function<void, unsigned short>()},
{"OnPlayerResurrect", Function<void, unsigned short>()},
{"OnPlayerChangeCell", Function<void, unsigned short>()},
{"OnPlayerUpdateEquiped", Function<void, unsigned short>()},
{"OnPlayerSendMessage", Function<bool, unsigned short, const char*>()},
{"OnPlayerEndCharGen", Function<void, unsigned short>()}
};
};
#endif //SOURCEPAWN_SCRIPTFUNCTIONS_HPP

@ -0,0 +1,44 @@
//
// Created by koncord on 19.03.16.
//
#ifndef PLUGINSYSTEM3_SYSTEMINTERFACE_HPP
#define PLUGINSYSTEM3_SYSTEMINTERFACE_HPP
#ifdef __WIN32__
#include <winsock2.h>
#else
#include <dlfcn.h>
#endif
template<typename R = void*>
struct SystemInterface
{
#ifdef __WIN32__
typedef HMODULE lib_t;
#else
typedef void* lib_t;
#endif
union
{
R result;
#ifdef __WIN32__
decltype(GetProcAddress(lib_t(), nullptr)) data;
#else
decltype(dlsym(lib_t(), nullptr)) data;
#endif
};
static_assert(sizeof(result) == sizeof(data), "R should have the same size");
SystemInterface() : data(nullptr) {}
explicit operator bool() { return data; }
#ifdef __WIN32__
SystemInterface(lib_t handle, const char* name) : data(GetProcAddress(handle, name)) {}
#else
SystemInterface(lib_t handle, const char* name) : data(dlsym(handle, name)) {}
#endif
};
#endif //PLUGINSYSTEM3_SYSTEMINTERFACE_HPP

@ -0,0 +1,101 @@
//
// Created by koncord on 23.01.16.
//
#ifndef SOURCEPAWN_TMPTYPES_HPP
#define SOURCEPAWN_TMPTYPES_HPP
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <RakNetTypes.h>
#include <Utils.hpp>
template<typename T> struct sizeof_void { enum { value = sizeof(T) }; };
template<> struct sizeof_void<void> { enum { value = 0 }; };
template<typename T, size_t t> struct TypeChar { static_assert(!t, "Unsupported type in variadic type list"); };
template<typename T> struct TypeChar<T*, sizeof(void*)> { enum { value = 'p' }; };
template<> struct TypeChar<double*, sizeof(double*)> { enum { value = 'd' }; };
template<> struct TypeChar<RakNet::NetworkID**, sizeof(RakNet::NetworkID**)> { enum { value = 'n' }; };
template<typename T> struct TypeChar<T, sizeof(uint8_t)> { enum { value = std::is_signed<T>::value ? 'q' : 'i' }; };
template<typename T> struct TypeChar<T, sizeof(uint16_t)> { enum { value = std::is_signed<T>::value ? 'q' : 'i' }; };
template<typename T> struct TypeChar<T, sizeof(uint32_t)> { enum { value = std::is_signed<T>::value ? 'q' : 'i' }; };
template<typename T> struct TypeChar<T, sizeof(uint64_t)> { enum { value = std::is_signed<T>::value ? 'w' : 'l' }; };
template<> struct TypeChar<double, sizeof(double)> { enum { value = 'f' }; };
template<> struct TypeChar<char*, sizeof(char*)> { enum { value = 's' }; };
template<> struct TypeChar<const char*, sizeof(const char*)> { enum { value = 's' }; };
template<> struct TypeChar<void, sizeof_void<void>::value> { enum { value = 'v' }; };
template<const char t> struct CharType { static_assert(!t, "Unsupported type in variadic type list"); };
template<> struct CharType<'p'> { typedef void* type; };
template<> struct CharType<'d'> { typedef double* type; };
template<> struct CharType<'n'> { typedef RakNet::NetworkID** type; };
template<> struct CharType<'q'> { typedef signed int type; };
template<> struct CharType<'i'> { typedef unsigned int type; };
template<> struct CharType<'w'> { typedef signed long long type; };
template<> struct CharType<'l'> { typedef unsigned long long type; };
template<> struct CharType<'f'> { typedef double type; };
template<> struct CharType<'s'> { typedef const char* type; };
template<> struct CharType<'v'> { typedef void type; };
template<typename... Types>
struct TypeString {
static constexpr char value[sizeof...(Types) + 1] = {
TypeChar<Types, sizeof(Types)>::value...
};
};
template<typename R, typename... Types>
using Function = R(*)(Types...);
template<typename R>
using FunctionEllipsis = R(*)(...);
struct ScriptIdentity
{
const char* types;
const char ret;
const unsigned int numargs;
constexpr bool matches(const char* types, const unsigned int N = 0) const
{
return N < numargs ? this->types[N] == types[N] && matches(types, N + 1) : this->types[N] == types[N];
}
template<typename R, typename... Types>
constexpr ScriptIdentity(Function<R, Types...>) : types(TypeString<Types...>::value), ret(TypeChar<R, sizeof_void<R>::value>::value), numargs(sizeof(TypeString<Types...>::value) - 1) {}
};
struct ScriptFunctionPointer : public ScriptIdentity
{
Function<void> addr;
template<typename R, typename... Types>
constexpr ScriptFunctionPointer(Function<R, Types...> addr) : ScriptIdentity(addr), addr(reinterpret_cast<Function<void>>(addr)) {}
};
struct ScriptFunctionData
{
const char* name;
const ScriptFunctionPointer func;
constexpr ScriptFunctionData(const char* name, ScriptFunctionPointer func) : name(name), func(func) {}
};
struct ScriptCallbackData
{
const char* name;
const unsigned int index;
const ScriptIdentity callback;
template<size_t N>
constexpr ScriptCallbackData(const char(&name)[N], ScriptIdentity _callback) : name(name), index(Utils::hash(name)), callback(_callback) {}
};
#endif //SOURCEPAWN_TMPTYPES_HPP

@ -0,0 +1,201 @@
//
// Created by koncord on 24.01.16.
//
#include "Utils.hpp"
#include <cstring>
#include <ctime>
#include <cmath>
using namespace std;
void Utils::timestamp()
{
time_t ltime;
ltime = time(nullptr);
char t[32];
snprintf(t, sizeof(t), "[%s", asctime(localtime(&ltime)));
char* newline = strchr(t, '\n');
*newline = ']';
strcat(t, " ");
printf("%s", t);
}
// http://stackoverflow.com/questions/1637587/c-libcurl-console-progress-bar
int Utils::progress_func(double TotalToDownload, double NowDownloaded)
{
// how wide you want the progress meter to be
int totaldotz=40;
double fractiondownloaded = NowDownloaded / TotalToDownload;
// part of the progressmeter that's already "full"
int dotz = round(fractiondownloaded * totaldotz);
// create the "meter"
int ii=0;
printf("%3.0f%% [",fractiondownloaded*100);
// part that's full already
for ( ; ii < dotz;ii++) {
printf("=");
}
// remaining part (spaces)
for ( ; ii < totaldotz;ii++) {
printf(" ");
}
// and back to line begin - do not forget the fflush to avoid output buffering problems!
printf("]\r");
fflush(stdout);
return 1;
}
bool Utils::DoubleCompare(double a, double b, double epsilon)
{
return fabs(a - b) < epsilon;
}
string Utils::str_replace(const string& source, const char* find, const char* replace)
{
unsigned int find_len = strlen(find);
unsigned int replace_len = strlen(replace);
long pos = 0;
string dest = source;
while ((pos = dest.find(find, pos)) != string::npos)
{
dest.replace(pos, find_len, replace);
pos += replace_len;
}
return dest;
}
string& Utils::RemoveExtension(string& file)
{
unsigned int pos = file.find_last_of('.');
if (pos)
file = file.substr(0, pos);
return file;
}
unsigned int Utils::FileLength(const char* file)
{
FILE* _file = fopen(file, "rb");
if (!_file)
return 0;
fseek(_file, 0, SEEK_END);
unsigned int size = ftell(_file);
fclose(_file);
return size;
}
/* From:
http://web.archive.org/web/20080303102530/http://c.snippets.org/snip_lister.php?fname=crc_32.c
*/
#define UPDC32(octet,crc) (crc_32_tab[((crc)\
^ ((unsigned char)octet)) & 0xff] ^ ((crc) >> 8))
static unsigned int crc_32_tab[] = /* CRC polynomial 0xedb88320 */
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
unsigned int Utils::updateCRC32(unsigned char ch, unsigned int crc)
{
return UPDC32(ch, crc);
}
bool Utils::crc32file(const char* name, unsigned int* crc)
{
FILE* fin;
unsigned int oldcrc32;
long charcnt;
int c;
oldcrc32 = 0xFFFFFFFF;
charcnt = 0;
if ((fin = fopen(name, "rb")) == nullptr)
{
return false;
}
while ((c = getc(fin)) != EOF)
{
++charcnt;
oldcrc32 = UPDC32(c, oldcrc32);
}
if (ferror(fin))
{
charcnt = -1;
}
fclose(fin);
*crc = oldcrc32 = ~oldcrc32;
return true;
}
unsigned int Utils::crc32buf(char* buf, size_t len)
{
unsigned int oldcrc32;
oldcrc32 = 0xFFFFFFFF;
for (; len; --len, ++buf)
{
oldcrc32 = UPDC32(*buf, oldcrc32);
}
return ~oldcrc32;
}

@ -0,0 +1,69 @@
//
// Created by koncord on 24.01.16.
//
#ifndef SOURCEPAWN_UTILS_HPP
#define SOURCEPAWN_UTILS_HPP
#include <cstddef>
#include <string>
#if (!defined(DEBUG_PRINTF) && defined(DEBUG))
#define DEBUG_PRINTF printf
#else
#define DEBUG_PRINTF(...)
#endif
namespace Utils
{
template<size_t N>
constexpr unsigned int hash(const char(&str)[N], size_t I = N)
{
return (I == 1 ? ((2166136261u ^ str[0]) * 16777619u) : ((hash(str, I - 1) ^ str[I - 1]) * 16777619u));
}
inline unsigned int hash(const char *str, std::size_t I)
{
return (I == 1 ? ((2166136261u ^ str[0]) * 16777619u) : ((hash(str, I - 1) ^ str[I - 1]) * 16777619u));
}
void timestamp();
int progress_func(double TotalToDownload, double NowDownloaded);
bool DoubleCompare(double a, double b, double epsilon);
std::string str_replace(const std::string &source, const char *find, const char *replace);
std::string &RemoveExtension(std::string &file);
unsigned int FileLength(const char *file);
unsigned int crc32buf(char *buf, size_t len);
unsigned int updateCRC32(unsigned char ch, unsigned int crc);
bool crc32file(const char *name, unsigned int *crc);
template<typename F, typename T, typename E = void>
struct is_static_castable : std::false_type
{
};
template<typename F, typename T>
struct is_static_castable<F, T, typename std::conditional<true, void, decltype(static_cast<T>(std::declval<F>()))>::type>
: std::true_type
{
};
template<typename T, typename F>
inline static typename std::enable_if<is_static_castable<F *, T *>::value, T *>::type static_or_dynamic_cast(
F *from)
{ return static_cast<T *>(from); }
template<typename T, typename F>
inline static typename std::enable_if<!is_static_castable<F *, T *>::value, T *>::type static_or_dynamic_cast(
F *from)
{ return dynamic_cast<T *>(from); }
}
#endif //SOURCEPAWN_UTILS_HPP

@ -0,0 +1,23 @@
include_directories(./linux)
add_definitions(-DPAWN_CELL_SIZE=64)
set(source_amx
amxexec_gcc.c
amxfile.c
fpattern.c
minIni.c
amxcons.c
amxcore.c
amxstring.c
amxtime.c
amxfloat.c
amxaux.c
amx.c
linux/binreloc.c
linux/getch.c
)
source_group(amx FILES ${source_amx})
add_library(amx STATIC ${source_amx} )

File diff suppressed because it is too large Load Diff

@ -0,0 +1,545 @@
/* Pawn Abstract Machine (for the Pawn language)
*
* Copyright (c) ITB CompuPhase, 1997-2015
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Version: $Id: amx.h 5181 2015-01-21 09:44:28Z thiadmer $
*/
#ifndef AMX_H_INCLUDED
#define AMX_H_INCLUDED
#include <stdlib.h> /* for size_t */
#include <limits.h>
#if (defined __linux || defined __linux__) && !defined __LINUX__
#define __LINUX__
#endif
#if defined FREEBSD && !defined __FreeBSD__
#define __FreeBSD__
#endif
#if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
#include <sclinux.h>
#endif
#if defined __GNUC__
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#endif
#if !defined HAVE_STDINT_H
#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) \
|| defined __GNUC__ || defined __LCC__ || defined __DMC__ \
|| (defined __WATCOMC__ && __WATCOMC__ >= 1200)
#define HAVE_STDINT_H 1
#endif
#endif
#if !defined HAVE_INTTYPES_H
#if defined __FreeBSD__ || defined __APPLE__
#define HAVE_INTTYPES_H 1
#endif
#endif
#if defined HAVE_STDINT_H
#include <stdint.h>
#elif defined HAVE_INTTYPES_H
#include <inttypes.h>
#else
#if defined __MACH__
#include <ppc/types.h>
#endif
typedef short int int16_t;
typedef unsigned short int uint16_t;
#if defined SN_TARGET_PS2
typedef int int32_t;
typedef unsigned int uint32_t;
#else
typedef long int int32_t;
typedef unsigned long int uint32_t;
#endif
#if defined __WIN32__ || defined _WIN32 || defined WIN32
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#define HAVE_I64
#endif
#if !defined _INTPTR_T_DEFINED
#if defined _LP64 || defined WIN64 || defined _WIN64
typedef __int64 intptr_t;
#else
typedef int32_t intptr_t;
#endif
#endif
#endif
#if defined _LP64 || defined WIN64 || defined _WIN64
#if !defined __64BIT__
#define __64BIT__
#endif
#endif
#if !defined HAVE_ALLOCA_H
#if defined __GNUC__ || defined __LCC__ || defined __DMC__ || defined __ARMCC_VERSION
#define HAVE_ALLOCA_H 1
#elif defined __WATCOMC__ && __WATCOMC__ >= 1200
#define HAVE_ALLOCA_H 1
#endif
#endif
#if defined HAVE_ALLOCA_H && HAVE_ALLOCA_H
#include <alloca.h>
#elif defined __BORLANDC__
#include <malloc.h>
#endif
#if defined __WIN32__ || defined _WIN32 || defined WIN32 /* || defined __MSDOS__ */
#if !defined alloca
#define alloca(n) _alloca(n)
#endif
#endif
#if !defined assert_static
#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112) || GCC_VERSION >= 40600
#define assert_static(test) _Static_assert(test, "assert")
#else
/* see "Compile-Time Assertions" by Greg Miller,
* (with modifications to port it to C)
*/
#define _ASSERT_STATIC_SYMBOL_INNER(line) __ASSERT_STATIC_ ## line
#define _ASSERT_STATIC_SYMBOL(line) _ASSERT_STATIC_SYMBOL_INNER(line)
#define assert_static(test) \
do { \
typedef char _ASSERT_STATIC_SYMBOL(__LINE__)[ ((test) ? 1 : -1) ]; \
} while (0)
#endif
#endif
#if defined __cplusplus
extern "C" {
#endif
#if defined PAWN_DLL
#if !defined AMX_NATIVE_CALL
#define AMX_NATIVE_CALL __stdcall
#endif
#if !defined AMXAPI
#define AMXAPI __stdcall
#endif
#if !defined AMXEXPORT
#define AMXEXPORT __declspec(dllexport)
#endif
#endif
/* calling convention for native functions */
#if !defined AMX_NATIVE_CALL
#define AMX_NATIVE_CALL
#endif
/* calling convention for all interface functions and callback functions */
#if !defined AMXAPI
#if defined STDECL
#define AMXAPI __stdcall
#elif defined CDECL
#define AMXAPI __cdecl
#elif defined GCC_HASCLASSVISIBILITY
#define AMXAPI __attribute__((visibility("default")))
#else
#define AMXAPI
#endif
#endif
#if !defined AMXEXPORT
#define AMXEXPORT
#endif
/* File format version (in CUR_FILE_VERSION)
* 0 original version
* 1 opcodes JUMP.pri, SWITCH and CASETBL
* 2 compressed files
* 3 public variables
* 4 opcodes SWAP.pri/alt and PUSHADDR
* 5 tagnames table
* 6 reformatted header
* 7 name table, opcodes SYMTAG & SYSREQ.D
* 8 opcode BREAK, renewed debug interface
* 9 macro opcodes
* 10 position-independent code, overlays, packed instructions
* 11 relocating instructions for the native interface, reorganized instruction set
* MIN_FILE_VERSION is the lowest file version number that the current AMX
* implementation supports. If the AMX file header gets new fields, this number
* often needs to be incremented. MIN_AMX_VERSION is the lowest AMX version that
* is needed to support the current file version. When there are new opcodes,
* this number needs to be incremented.
* The file version supported by the JIT may run behind MIN_AMX_VERSION. So
* there is an extra constant for it: MAX_FILE_VER_JIT.
*/
#define CUR_FILE_VERSION 11 /* current file version; also the current AMX version */
#define MIN_FILE_VERSION 11 /* lowest supported file format version for the current AMX version */
#define MIN_AMX_VERSION 11 /* minimum AMX version needed to support the current file format */
#define MAX_FILE_VER_JIT 11 /* file version supported by the JIT */
#define MIN_AMX_VER_JIT 11 /* AMX version supported by the JIT */
#if !defined PAWN_CELL_SIZE
#define PAWN_CELL_SIZE 32 /* by default, use 32-bit cells */
#endif
#if PAWN_CELL_SIZE==16
typedef uint16_t ucell;
typedef int16_t cell;
#elif PAWN_CELL_SIZE==32
typedef uint32_t ucell;
typedef int32_t cell;
#elif PAWN_CELL_SIZE==64
typedef uint64_t ucell;
typedef int64_t cell;
#define HAVE_I64
#else
#error Unsupported cell size (PAWN_CELL_SIZE)
#endif
#define UNPACKEDMAX (((cell)1 << (sizeof(cell)-1)*8) - 1)
#define UNLIMITED (~1u >> 1)
struct tagAMX;
typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct tagAMX *amx, const cell *params);
typedef int (AMXAPI *AMX_CALLBACK)(struct tagAMX *amx, cell index,
cell *result, const cell *params);
typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx);
typedef int (AMXAPI *AMX_OVERLAY)(struct tagAMX *amx, int index);
typedef int (AMXAPI *AMX_IDLE)(struct tagAMX *amx, int AMXAPI Exec(struct tagAMX *, cell *, int));
#if !defined _FAR
#define _FAR
#endif
#if defined _MSC_VER
#pragma warning(disable:4100) /* "'%$S' : unreferenced formal parameter" */
#pragma warning(disable:4103) /* disable warning message 4103 that complains
* about pragma pack in a header file */
#pragma warning(disable:4127) /* "conditional expression is constant" (needed for static_assert) */
#pragma warning(disable:4996) /* POSIX name is deprecated */
#endif
/* Some compilers do not support the #pragma align, which should be fine. Some
* compilers give a warning on unknown #pragmas, which is not so fine...
*/
#if (defined SN_TARGET_PS2 || defined __GNUC__) && !defined AMX_NO_ALIGN
#define AMX_NO_ALIGN
#endif
#if defined __GNUC__
#define PACKED __attribute__((packed))
#else
#define PACKED
#endif
#if !defined AMX_NO_ALIGN
#if defined __LINUX__ || defined __FreeBSD__ || defined __APPLE__
#pragma pack(1) /* structures must be packed (byte-aligned) */
#elif defined MACOS && defined __MWERKS__
#pragma options align=mac68k
#else
#pragma pack(push)
#pragma pack(1) /* structures must be packed (byte-aligned) */
#if defined __TURBOC__
#pragma option -a- /* "pack" pragma for older Borland compilers */
#endif
#endif
#endif
typedef struct tagAMX_NATIVE_INFO {
const char _FAR *name;
AMX_NATIVE func;
} PACKED AMX_NATIVE_INFO;
#if !defined AMX_USERNUM
#define AMX_USERNUM 4
#endif
#define sEXPMAX 19 /* maximum name length for file version <= 6 */
#define sNAMEMAX 31 /* maximum name length of symbol name */
typedef struct tagFUNCSTUB {
uint32_t address;
uint32_t nameofs;
} PACKED AMX_FUNCSTUB;
typedef struct tagOVERLAYINFO {
int32_t offset; /* offset relative to the start of the code block */
int32_t size; /* size in bytes */
} PACKED AMX_OVERLAYINFO;
/* The AMX structure is the internal structure for many functions. Not all
* fields are valid at all times; many fields are cached in local variables.
*/
typedef struct tagAMX {
unsigned char _FAR *base; /* points to the AMX header, perhaps followed by P-code and data */
unsigned char _FAR *code; /* points to P-code block, possibly in ROM or in an overlay pool */
unsigned char _FAR *data; /* points to separate data+stack+heap, may be NULL */
AMX_CALLBACK callback; /* native function callback */
AMX_DEBUG debug; /* debug callback */
AMX_OVERLAY overlay; /* overlay reader callback */
/* for external functions a few registers must be accessible from the outside */
cell cip; /* instruction pointer: relative to base + amxhdr->cod */
cell frm; /* stack frame base: relative to base + amxhdr->dat */
cell hea; /* top of the heap: relative to base + amxhdr->dat */
cell hlw; /* bottom of the heap: relative to base + amxhdr->dat */
cell stk; /* stack pointer: relative to base + amxhdr->dat */
cell stp; /* top of the stack: relative to base + amxhdr->dat */
int flags; /* current status, see amx_Flags() */
/* user data */
#if AMX_USERNUM > 0
long usertags[AMX_USERNUM];
void _FAR *userdata[AMX_USERNUM];
#endif
/* native functions can raise an error */
int error;
/* passing parameters requires a "count" field */
int paramcount;
/* the sleep opcode needs to store the full AMX status */
cell pri;
cell alt;
cell reset_stk;
cell reset_hea;
/* extra fields for increased performance */
cell sysreq_d; /* relocated address/value for the SYSREQ.D opcode */
/* fields for overlay support and JIT support */
int ovl_index; /* current overlay index */
long codesize; /* size of the overlay, or estimated memory footprint of the native code */
#if defined AMX_JIT
/* support variables for the JIT */
int reloc_size; /* required temporary buffer for relocations */
#endif
} PACKED AMX;
/* The AMX_HEADER structure is both the memory format as the file format. The
* structure is used internaly.
*/
typedef struct tagAMX_HEADER {
int32_t size; /* size of the "file" */
uint16_t magic; /* signature */
char file_version; /* file format version */
char amx_version; /* required version of the AMX */
int16_t flags;
int16_t defsize; /* size of a definition record */
int32_t cod; /* initial value of COD - code block */
int32_t dat; /* initial value of DAT - data block */
int32_t hea; /* initial value of HEA - start of the heap */
int32_t stp; /* initial value of STP - stack top */
int32_t cip; /* initial value of CIP - the instruction pointer */
int32_t publics; /* offset to the "public functions" table */
int32_t natives; /* offset to the "native functions" table */
int32_t libraries; /* offset to the table of libraries */
int32_t pubvars; /* offset to the "public variables" table */
int32_t tags; /* offset to the "public tagnames" table */
int32_t nametable; /* offset to the name table */
int32_t overlays; /* offset to the overlay table */
} PACKED AMX_HEADER;
#define AMX_MAGIC_16 0xf1e2
#define AMX_MAGIC_32 0xf1e0
#define AMX_MAGIC_64 0xf1e1
#if PAWN_CELL_SIZE==16
#define AMX_MAGIC AMX_MAGIC_16
#elif PAWN_CELL_SIZE==32
#define AMX_MAGIC AMX_MAGIC_32
#elif PAWN_CELL_SIZE==64
#define AMX_MAGIC AMX_MAGIC_64
#endif
enum {
AMX_ERR_NONE,
/* reserve the first 15 error codes for exit codes of the abstract machine */
AMX_ERR_EXIT, /* forced exit */
AMX_ERR_ASSERT, /* assertion failed */
AMX_ERR_STACKERR, /* stack/heap collision */
AMX_ERR_BOUNDS, /* index out of bounds */
AMX_ERR_MEMACCESS, /* invalid memory access */
AMX_ERR_INVINSTR, /* invalid instruction */
AMX_ERR_STACKLOW, /* stack underflow */
AMX_ERR_HEAPLOW, /* heap underflow */
AMX_ERR_CALLBACK, /* no callback, or invalid callback */
AMX_ERR_NATIVE, /* native function failed */
AMX_ERR_DIVIDE, /* divide by zero */
AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */
AMX_ERR_INVSTATE, /* no implementation for this state, no fall-back */
AMX_ERR_MEMORY = 16, /* out of memory */
AMX_ERR_FORMAT, /* invalid file format */
AMX_ERR_VERSION, /* file is for a newer version of the AMX */
AMX_ERR_NOTFOUND, /* function not found */
AMX_ERR_INDEX, /* invalid index parameter (bad entry point) */
AMX_ERR_DEBUG, /* debugger cannot run */
AMX_ERR_INIT, /* AMX not initialized (or doubly initialized) */
AMX_ERR_USERDATA, /* unable to set user data field (table full) */
AMX_ERR_INIT_JIT, /* cannot initialize the JIT */
AMX_ERR_PARAMS, /* parameter error */
AMX_ERR_DOMAIN, /* domain error, expression result does not fit in range */
AMX_ERR_GENERAL, /* general error (unknown or unspecific error) */
AMX_ERR_OVERLAY, /* overlays are unsupported (JIT) or uninitialized */
};
#define AMX_FLAG_OVERLAY 0x01 /* all function calls use overlays */
#define AMX_FLAG_DEBUG 0x02 /* symbolic info. available */
#define AMX_FLAG_NOCHECKS 0x04 /* no array bounds checking; no BREAK opcodes */
#define AMX_FLAG_SLEEP 0x08 /* script uses the sleep instruction (possible re-entry or power-down mode) */
#define AMX_FLAG_CRYPT 0x10 /* file is encrypted */
#define AMX_FLAG_DSEG_INIT 0x20 /* data section is explicitly initialized */
#define AMX_FLAG_SYSREQN 0x800 /* script uses new (optimized) version of SYSREQ opcode */
#define AMX_FLAG_NTVREG 0x1000 /* all native functions are registered */
#define AMX_FLAG_JITC 0x2000 /* abstract machine is JIT compiled */
#define AMX_FLAG_VERIFY 0x4000 /* busy verifying P-code */
#define AMX_FLAG_INIT 0x8000 /* AMX has been initialized */
#define AMX_EXEC_MAIN (-1) /* start at program entry point */
#define AMX_EXEC_CONT (-2) /* continue from last address */
#define AMX_USERTAG(a,b,c,d) ((a) | ((b)<<8) | ((long)(c)<<16) | ((long)(d)<<24))
/* for native functions that use floating point parameters, the following
* two macros are convenient for casting a "cell" into a "float" type _without_
* changing the bit pattern
*/
#if PAWN_CELL_SIZE==32
#define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */
#define amx_ctof(c) ( * ((float*)&c) ) /* cell to float */
#elif PAWN_CELL_SIZE==64
#define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */
#define amx_ctof(c) ( * ((double*)&c) ) /* cell to float */
#else
// amx_ftoc() and amx_ctof() cannot be used
#endif
/* when a pointer cannot be stored in a cell, cells that hold relocated
* addresses need to be expanded
*/
#if defined __64BIT__ && PAWN_CELL_SIZE<64
#define CELLMASK (((int64_t)1 << PAWN_CELL_SIZE) - 1)
#define amx_Address(amx,addr) \
(cell*)(((int64_t)((amx)->data ? (amx)->data : (amx)->code) & ~CELLMASK) | ((int64_t)(addr) & CELLMASK))
#elif defined __32BIT__ && PAWN_CELL_SIZE<32
#define CELLMASK ((1L << PAWN_CELL_SIZE) - 1)
#define amx_Address(amx,addr) \
(cell*)(((int32_t)((amx)->data ? (amx)->data : (amx)->code) & ~CELLMASK) | ((int32_t)(addr) & CELLMASK))
#else
#define amx_Address(amx,addr) ((void)(amx),(cell*)(addr))
#endif
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
/* C99: use variable-length arrays */
#define amx_StrParam_Type(amx,param,result,type) \
int result##_length_; \
amx_StrLen(amx_Address(amx,param),&result##_length_); \
char result##_vla_[(result##_length_+1)*sizeof(*(result))]; \
(result)=(type)result##_vla_; \
amx_GetString((char*)(result),amx_Address(amx,param), \
sizeof(*(result))>1,result##_length_+1)
#define amx_StrParam(amx,param,result) \
amx_StrParam_Type(amx,param,result,void*)
#else
/* macro using alloca() */
#define amx_StrParam_Type(amx,param,result,type) \
do { \
int result##_length_; \
amx_StrLen(amx_Address(amx,param),&result##_length_); \
if (result##_length_>0 && \
((result)=(type)alloca((result##_length_+1)*sizeof(*(result))))!=NULL) \
amx_GetString((char*)(result),amx_Address(amx,param), \
sizeof(*(result))>1,result##_length_+1); \
else (result) = NULL; \
} while (0)
#define amx_StrParam(amx,param,result) \
amx_StrParam_Type(amx,param,result,void*)
#endif
uint16_t * AMXAPI amx_Align16(uint16_t *v);
uint32_t * AMXAPI amx_Align32(uint32_t *v);
#if defined _I64_MAX || defined INT64_MAX || defined HAVE_I64
uint64_t * AMXAPI amx_Align64(uint64_t *v);
#endif
int AMXAPI amx_Allot(AMX *amx, int cells, cell **address);
int AMXAPI amx_Callback(AMX *amx, cell index, cell *result, const cell *params);
int AMXAPI amx_Cleanup(AMX *amx);
int AMXAPI amx_Clone(AMX *amxClone, AMX *amxSource, void *data);
int AMXAPI amx_Exec(AMX *amx, cell *retval, int index);
int AMXAPI amx_FindNative(AMX *amx, const char *name, int *index);
int AMXAPI amx_FindPublic(AMX *amx, const char *name, int *index);
int AMXAPI amx_FindPubVar(AMX *amx, const char *name, cell **address);
int AMXAPI amx_FindTagId(AMX *amx, cell tag_id, char *tagname);
int AMXAPI amx_Flags(AMX *amx,uint16_t *flags);
int AMXAPI amx_GetNative(AMX *amx, int index, char *name);
int AMXAPI amx_GetPublic(AMX *amx, int index, char *name, ucell *address);
int AMXAPI amx_GetPubVar(AMX *amx, int index, char *name, cell **address);
int AMXAPI amx_GetString(char *dest,const cell *source, int use_wchar, size_t size);
int AMXAPI amx_GetTag(AMX *amx, int index, char *tagname, cell *tag_id);
int AMXAPI amx_GetUserData(AMX *amx, long tag, void **ptr);
int AMXAPI amx_Init(AMX *amx, void *program);
int AMXAPI amx_InitJIT(AMX *amx, void *reloc_table, void *native_code);
int AMXAPI amx_MemInfo(AMX *amx, long *codesize, long *datasize, long *stackheap);
int AMXAPI amx_NameLength(AMX *amx, int *length);
AMX_NATIVE_INFO * AMXAPI amx_NativeInfo(const char *name, AMX_NATIVE func);
int AMXAPI amx_NumNatives(AMX *amx, int *number);
int AMXAPI amx_NumPublics(AMX *amx, int *number);
int AMXAPI amx_NumPubVars(AMX *amx, int *number);
int AMXAPI amx_NumTags(AMX *amx, int *number);
int AMXAPI amx_Push(AMX *amx, cell value);
int AMXAPI amx_PushAddress(AMX *amx, cell *address);
int AMXAPI amx_PushArray(AMX *amx, cell **address, const cell array[], int numcells);
int AMXAPI amx_PushString(AMX *amx, cell **address, const char *string, int pack, int use_wchar);
int AMXAPI amx_RaiseError(AMX *amx, int error);
int AMXAPI amx_Register(AMX *amx, const AMX_NATIVE_INFO *nativelist, int number);
int AMXAPI amx_Release(AMX *amx, cell *address);
int AMXAPI amx_SetCallback(AMX *amx, AMX_CALLBACK callback);
int AMXAPI amx_SetDebugHook(AMX *amx, AMX_DEBUG debug);
int AMXAPI amx_SetString(cell *dest, const char *source, int pack, int use_wchar, size_t size);
int AMXAPI amx_SetUserData(AMX *amx, long tag, void *ptr);
int AMXAPI amx_StrLen(const cell *cstring, int *length);
int AMXAPI amx_UTF8Check(const char *string, int *length);
int AMXAPI amx_UTF8Get(const char *string, const char **endptr, cell *value);
int AMXAPI amx_UTF8Len(const cell *cstr, int *length);
int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value);
#if PAWN_CELL_SIZE==16
void amx_Swap16(uint16_t *v);
#endif
#if PAWN_CELL_SIZE==32
void amx_Swap32(uint32_t *v);
#endif
#if PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined INT64_MAX || defined HAVE_I64)
void amx_Swap64(uint64_t *v);
#endif
#if PAWN_CELL_SIZE==16
#define amx_AlignCell(v) amx_Align16((uint16_t*)(v))
#define amx_SwapCell(v) amx_Swap16((uint16_t*)(v))
#elif PAWN_CELL_SIZE==32
#define amx_AlignCell(v) amx_Align32((uint32_t*)(v))
#define amx_SwapCell(v) amx_Swap32((uint32_t*)(v))
#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined INT64_MAX || defined HAVE_I64)
#define amx_AlignCell(v) amx_Align64((uint64_t*)(v))
#define amx_SwapCell(v) amx_Swap64((uint64_t*)(v))
#else
#error Unsupported cell size
#endif
#define amx_RegisterFunc(amx, name, func) \
amx_Register((amx), amx_NativeInfo((name),(func)), 1);
#if !defined AMX_NO_ALIGN
#if defined __LINUX__ || defined __FreeBSD__ || defined __APPLE__
#pragma pack() /* reset default packing */
#elif defined MACOS && defined __MWERKS__
#pragma options align=reset
#else
#pragma pack(pop) /* reset previous packing */
#endif
#endif
#ifdef __cplusplus
}
#endif
#endif /* AMX_H_INCLUDED */

@ -0,0 +1,164 @@
/* Support routines for the Pawn Abstract Machine
*
* Copyright (c) ITB CompuPhase, 2003-2011
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Version: $Id: amxaux.c 4523 2011-06-21 15:03:47Z thiadmer $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "amx.h"
#include "amxaux.h"
size_t AMXAPI aux_ProgramSize(const char *filename)
{
FILE *fp;
AMX_HEADER hdr;
if ((fp=fopen(filename,"rb")) == NULL)
return 0;
fread(&hdr, sizeof hdr, 1, fp);
fclose(fp);
amx_Align16(&hdr.magic);
amx_Align32((uint32_t *)&hdr.stp);
return (hdr.magic==AMX_MAGIC) ? (size_t)hdr.stp : 0;
}
int AMXAPI aux_LoadProgram(AMX *amx, const char *filename, void *memblock)
{
FILE *fp;
AMX_HEADER hdr;
int result, didalloc;
/* open the file, read and check the header */
if ((fp = fopen(filename, "rb")) == NULL)
return AMX_ERR_NOTFOUND;
fread(&hdr, sizeof hdr, 1, fp);
amx_Align16(&hdr.magic);
amx_Align32((uint32_t *)&hdr.size);
amx_Align32((uint32_t *)&hdr.stp);
if (hdr.magic != AMX_MAGIC) {
fclose(fp);
return AMX_ERR_FORMAT;
} /* if */
/* allocate the memblock if it is NULL */
didalloc = 0;
if (memblock == NULL) {
if ((memblock = malloc(hdr.stp)) == NULL) {
fclose(fp);
return AMX_ERR_MEMORY;
} /* if */
didalloc = 1;
/* after amx_Init(), amx->base points to the memory block */
} /* if */
/* read in the file */
rewind(fp);
fread(memblock, 1, (size_t)hdr.size, fp);
fclose(fp);
/* initialize the abstract machine */
memset(amx, 0, sizeof *amx);
result = amx_Init(amx, memblock);
/* free the memory block on error, if it was allocated here */
if (result != AMX_ERR_NONE && didalloc) {
free(memblock);
amx->base = NULL; /* avoid a double free */
} /* if */
return result;
}
int AMXAPI aux_FreeProgram(AMX *amx)
{
if (amx->base!=NULL) {
amx_Cleanup(amx);
free(amx->base);
memset(amx, 0, sizeof(AMX));
} /* if */
return AMX_ERR_NONE;
}
char * AMXAPI aux_StrError(int errnum)
{
static char *messages[] = {
/* AMX_ERR_NONE */ "(none)",
/* AMX_ERR_EXIT */ "Forced exit",
/* AMX_ERR_ASSERT */ "Assertion failed",
/* AMX_ERR_STACKERR */ "Stack/heap collision (insufficient stack size)",
/* AMX_ERR_BOUNDS */ "Array index out of bounds",
/* AMX_ERR_MEMACCESS */ "Invalid memory access",
/* AMX_ERR_INVINSTR */ "Invalid instruction",
/* AMX_ERR_STACKLOW */ "Stack underflow",
/* AMX_ERR_HEAPLOW */ "Heap underflow",
/* AMX_ERR_CALLBACK */ "No (valid) native function callback",
/* AMX_ERR_NATIVE */ "Native function failed",
/* AMX_ERR_DIVIDE */ "Divide by zero",
/* AMX_ERR_SLEEP */ "(sleep mode)",
/* AMX_ERR_INVSTATE */ "Invalid state",
/* 14 */ "(reserved)",
/* 15 */ "(reserved)",
/* AMX_ERR_MEMORY */ "Out of memory",
/* AMX_ERR_FORMAT */ "Invalid/unsupported P-code file format",
/* AMX_ERR_VERSION */ "File is for a newer version of the AMX",
/* AMX_ERR_NOTFOUND */ "File or function is not found",
/* AMX_ERR_INDEX */ "Invalid index parameter (bad entry point)",
/* AMX_ERR_DEBUG */ "Debugger cannot run",
/* AMX_ERR_INIT */ "AMX not initialized (or doubly initialized)",
/* AMX_ERR_USERDATA */ "Unable to set user data field (table full)",
/* AMX_ERR_INIT_JIT */ "Cannot initialize the JIT",
/* AMX_ERR_PARAMS */ "Parameter error",
/* AMX_ERR_DOMAIN */ "Domain error, expression result does not fit in range",
/* AMX_ERR_GENERAL */ "General error (unknown or unspecific error)",
/* AMX_ERR_OVERLAY */ "Overlays are unsupported (JIT) or uninitialized",
};
if (errnum < 0 || errnum >= sizeof messages / sizeof messages[0])
return "(unknown)";
return messages[errnum];
}
int AMXAPI aux_GetSection(const AMX *amx, int section, cell **start, size_t *size)
{
AMX_HEADER *hdr;
if (amx == NULL || start == NULL || size == NULL)
return AMX_ERR_PARAMS;
hdr = (AMX_HEADER*)amx->base;
switch(section) {
case CODE_SECTION:
*start = (cell *)(amx->base + hdr->cod);
*size = hdr->dat - hdr->cod;
break;
case DATA_SECTION:
*start = (cell *)(amx->data);
*size = hdr->hea - hdr->dat;
break;
case HEAP_SECTION:
*start = (cell *)(amx->data + hdr->hea);
*size = amx->hea - hdr->hea;
break;
case STACK_SECTION:
*start = (cell *)(amx->data + amx->stk);
*size = amx->stp - amx->stk;
break;
default:
return AMX_ERR_PARAMS;
} /* switch */
return AMX_ERR_NONE;
}

@ -0,0 +1,50 @@
/* Support routines for the Pawn Abstract Machine
*
* Copyright (c) ITB CompuPhase, 2003-2011
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Version: $Id: amxaux.h 4523 2011-06-21 15:03:47Z thiadmer $
*/
#ifndef AMXAUX_H_INCLUDED
#define AMXAUX_H_INCLUDED
#include "amx.h"
#ifdef __cplusplus
extern "C" {
#endif
/* loading and freeing programs */
size_t AMXAPI aux_ProgramSize(const char *filename);
int AMXAPI aux_LoadProgram(AMX *amx, const char *filename, void *memblock);
int AMXAPI aux_FreeProgram(AMX *amx);
/* a readable error message from an error code */
char * AMXAPI aux_StrError(int errnum);
enum {
CODE_SECTION,
DATA_SECTION,
HEAP_SECTION,
STACK_SECTION,
/* ----- */
NUM_SECTIONS
};
int AMXAPI aux_GetSection(const AMX *amx, int section, cell **start, size_t *size);
#ifdef __cplusplus
}
#endif
#endif /* AMXAUX_H_INCLUDED */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,17 @@
#ifndef AMXCONS_H_INCLUDED
#define AMXCONS_H_INCLUDED
typedef struct tagFMTINFO {
const cell *params;
int numparams;
int skip; /* number of characters to skip from the beginning */
int length; /* number of characters to print */
/* helper functions */
int (*f_putstr)(void *dest,const TCHAR *);
int (*f_putchar)(void *dest,TCHAR);
void *user; /* user data */
} AMX_FMTINFO;
int amx_printstring(AMX *amx,cell *cstr,AMX_FMTINFO *info);
#endif /* AMXCONS_H_INCLUDED */

@ -0,0 +1,500 @@
/* Core module for the Pawn AMX
*
* Copyright (c) ITB CompuPhase, 1997-2012
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Version: $Id: amxcore.c 4708 2012-05-18 12:52:49Z $
*/
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
# if !defined UNICODE /* for Windows */
# define UNICODE
# endif
# if !defined _UNICODE /* for C library */
# define _UNICODE
# endif
#endif
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include "osdefs.h"
#if defined __ECOS__
/* eCos puts include files in cyg/package_name */
#include <cyg/pawn/amx.h>
#define stricmp(a,b) strcasecmp(a,b)
#else
#include "amx.h"
#endif
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
#include <windows.h>
#endif
/* A few compilers do not provide the ANSI C standard "time" functions */
#if !defined SN_TARGET_PS2 && !defined _WIN32_WCE && !defined __ICC430__
#include <time.h>
#endif
#if defined _UNICODE
# include <tchar.h>
#elif !defined __T
typedef char TCHAR;
# define __T(string) string
# define _tcschr strchr
# define _tcscpy strcpy
# define _tcsdup strdup
# define _tcslen strlen
#endif
#define CHARBITS (8*sizeof(char))
typedef unsigned char uchar;
#if !defined AMX_NOPROPLIST
typedef struct _property_list {
struct _property_list *next;
cell id;
char *name;
cell value;
} proplist;
static proplist proproot = { NULL, 0, NULL, 0 };
static proplist *list_additem(proplist *root)
{
proplist *item;
assert(root!=NULL);
if ((item=(proplist *)malloc(sizeof(proplist)))==NULL)
return NULL;
item->name=NULL;
item->id=0;
item->value=0;
item->next=root->next;
root->next=item;
return item;
}
static void list_delete(proplist *pred,proplist *item)
{
assert(pred!=NULL);
assert(item!=NULL);
pred->next=item->next;
assert(item->name!=NULL);
free(item->name);
free(item);
}
static void list_setitem(proplist *item,cell id,char *name,cell value)
{
char *ptr;
assert(item!=NULL);
if ((ptr=(char *)malloc(strlen(name)+1))==NULL)
return;
if (item->name!=NULL)
free(item->name);
strcpy(ptr,name);
item->name=ptr;
item->id=id;
item->value=value;
}
static proplist *list_finditem(proplist *root,cell id,char *name,cell value,
proplist **pred)
{
proplist *item=root->next;
proplist *prev=root;
/* check whether to find by name or by value */
assert(name!=NULL);
if (strlen(name)>0) {
/* find by name */
while (item!=NULL && (item->id!=id || stricmp(item->name,name)!=0)) {
prev=item;
item=item->next;
} /* while */
} else {
/* find by value */
while (item!=NULL && (item->id!=id || item->value!=value)) {
prev=item;
item=item->next;
} /* while */
} /* if */
if (pred!=NULL)
*pred=prev;
return item;
}
#endif
static cell AMX_NATIVE_CALL numargs(AMX *amx,const cell *params)
{
AMX_HEADER *hdr;
uchar *data;
cell bytes;
(void)params;
hdr=(AMX_HEADER *)amx->base;
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
/* the number of bytes is on the stack, at "frm + 2*cell" */
bytes= * (cell *)(data+(int)amx->frm+2*sizeof(cell));
/* the number of arguments is the number of bytes divided
* by the size of a cell */
return bytes/sizeof(cell);
}
static cell AMX_NATIVE_CALL getarg(AMX *amx,const cell *params)
{
AMX_HEADER *hdr;
uchar *data;
cell value;
hdr=(AMX_HEADER *)amx->base;
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
/* get the base value */
value= * (cell *)(data+(int)amx->frm+((int)params[1]+3)*sizeof(cell));
/* adjust the address in "value" in case of an array access */
value+=params[2]*sizeof(cell);
/* get the value indirectly */
value= * (cell *)(data+(int)value);
return value;
}
static cell AMX_NATIVE_CALL setarg(AMX *amx,const cell *params)
{
AMX_HEADER *hdr;
uchar *data;
cell value;
hdr=(AMX_HEADER *)amx->base;
data=amx->data ? amx->data : amx->base+(int)hdr->dat;
/* get the base value */
value= * (cell *)(data+(int)amx->frm+((int)params[1]+3)*sizeof(cell));
/* adjust the address in "value" in case of an array access */
value+=params[2]*sizeof(cell);
/* verify the address */
if (value<0 || value>=amx->hea && value<amx->stk)
return 0;
/* set the value indirectly */
* (cell *)(data+(int)value) = params[3];
return 1;
}
static cell AMX_NATIVE_CALL heapspace(AMX *amx,const cell *params)
{
(void)params;
return amx->stk - amx->hea;
}
static cell AMX_NATIVE_CALL funcidx(AMX *amx,const cell *params)
{
char name[64];
cell *cstr;
int index,err;
cstr=amx_Address(amx,params[1]);
amx_GetString(name,cstr,0,sizeof name);
err=amx_FindPublic(amx,name,&index);
if (err!=AMX_ERR_NONE)
index=-1; /* this is not considered a fatal error */
return index;
}
void amx_swapcell(cell *pc)
{
union {
cell c;
#if PAWN_CELL_SIZE==16
uchar b[2];
#elif PAWN_CELL_SIZE==32
uchar b[4];
#elif PAWN_CELL_SIZE==64
uchar b[8];
#else
#error Unsupported cell size
#endif
} value;
uchar t;
assert(pc!=NULL);
value.c = *pc;
#if PAWN_CELL_SIZE==16
t = value.b[0];
value.b[0] = value.b[1];
value.b[1] = t;
#elif PAWN_CELL_SIZE==32
t = value.b[0];
value.b[0] = value.b[3];
value.b[3] = t;
t = value.b[1];
value.b[1] = value.b[2];
value.b[2] = t;
#elif PAWN_CELL_SIZE==64
t = value.b[0];
value.b[0] = value.b[7];
value.b[7] = t;
t = value.b[1];
value.b[1] = value.b[6];
value.b[6] = t;
t = value.b[2];
value.b[2] = value.b[5];
value.b[5] = t;
t = value.b[3];
value.b[3] = value.b[4];
value.b[4] = t;
#else
#error Unsupported cell size
#endif
*pc = value.c;
}
static cell AMX_NATIVE_CALL swapchars(AMX *amx,const cell *params)
{
cell c;
(void)amx;
assert((size_t)params[0]==sizeof(cell));
c=params[1];
amx_swapcell(&c);
return c;
}
static cell AMX_NATIVE_CALL core_tolower(AMX *amx,const cell *params)
{
(void)amx;
#if defined __WIN32__ || defined _WIN32 || defined WIN32
return (cell)CharLower((LPTSTR)params[1]);
#elif defined _Windows
return (cell)AnsiLower((LPSTR)params[1]);
#else
if ((unsigned)(params[1]-'A')<26u)
return params[1]+'a'-'A';
return params[1];
#endif
}
static cell AMX_NATIVE_CALL core_toupper(AMX *amx,const cell *params)
{
(void)amx;
#if defined __WIN32__ || defined _WIN32 || defined WIN32
return (cell)CharUpper((LPTSTR)params[1]);
#elif defined _Windows
return (cell)AnsiUpper((LPSTR)params[1]);
#else
if ((unsigned)(params[1]-'a')<26u)
return params[1]+'A'-'a';
return params[1];
#endif
}
static cell AMX_NATIVE_CALL core_min(AMX *amx,const cell *params)
{
(void)amx;
return params[1] <= params[2] ? params[1] : params[2];
}
static cell AMX_NATIVE_CALL core_max(AMX *amx,const cell *params)
{
(void)amx;
return params[1] >= params[2] ? params[1] : params[2];
}
static cell AMX_NATIVE_CALL core_clamp(AMX *amx,const cell *params)
{
cell value = params[1];
if (params[2] > params[3]) /* minimum value > maximum value ! */
amx_RaiseError(amx,AMX_ERR_NATIVE);
if (value < params[2])
value = params[2];
else if (value > params[3])
value = params[3];
return value;
}
#if !defined AMX_NOPROPLIST
static char *MakePackedString(cell *cptr)
{
int len;
char *dest;
amx_StrLen(cptr,&len);
dest=(char *)malloc(len+sizeof(cell));
amx_GetString(dest,cptr,0,len+sizeof(cell));
return dest;
}
/* getproperty(id=0, const name[]="", value=cellmin, string[]="", size=sizeof string) */
static cell AMX_NATIVE_CALL getproperty(AMX *amx,const cell *params)
{
cell *cstr;
char *name;
proplist *item;
(void)amx;
cstr=amx_Address(amx,params[2]);
name=MakePackedString(cstr);
item=list_finditem(&proproot,params[1],name,params[3],NULL);
/* if list_finditem() found the value, store the name */
if (item!=NULL && item->value==params[3] && strlen(name)==0) {
cstr=amx_Address(amx,params[4]);
amx_SetString(cstr,item->name,1,0,params[5]);
} /* if */
free(name);
return (item!=NULL) ? item->value : 0;
}
/* setproperty(id=0, const name[]="", value=cellmin, const string[]="") */
static cell AMX_NATIVE_CALL setproperty(AMX *amx,const cell *params)
{
cell prev=0;
cell *cstr;
char *name;
proplist *item;
cstr=amx_Address(amx,params[2]);
name=MakePackedString(cstr);
item=list_finditem(&proproot,params[1],name,params[3],NULL);
if (item==NULL)
item=list_additem(&proproot);
if (item==NULL) {
amx_RaiseError(amx,AMX_ERR_MEMORY);
} else {
prev=item->value;
if (strlen(name)==0) {
free(name);
cstr=amx_Address(amx,params[4]);
name=MakePackedString(cstr);
} /* if */
list_setitem(item,params[1],name,params[3]);
} /* if */
free(name);
return prev;
}
/* deleteproperty(id=0, const name[]="", value=cellmin) */
static cell AMX_NATIVE_CALL delproperty(AMX *amx,const cell *params)
{
cell prev=0;
cell *cstr;
char *name;
proplist *item,*pred;
(void)amx;
cstr=amx_Address(amx,params[2]);
name=MakePackedString(cstr);
item=list_finditem(&proproot,params[1],name,params[3],&pred);
if (item!=NULL) {
prev=item->value;
list_delete(pred,item);
} /* if */
free(name);
return prev;
}
/* existproperty(id=0, const name[]="", value=cellmin) */
static cell AMX_NATIVE_CALL existproperty(AMX *amx,const cell *params)
{
cell *cstr;
char *name;
proplist *item;
(void)amx;
cstr=amx_Address(amx,params[2]);
name=MakePackedString(cstr);
item=list_finditem(&proproot,params[1],name,params[3],NULL);
free(name);
return (item!=NULL);
}
#endif
#if !defined AMX_NORANDOM
/* This routine comes from the book "Inner Loops" by Rick Booth, Addison-Wesley
* (ISBN 0-201-47960-5). This is a "multiplicative congruential random number
* generator" that has been extended to 31-bits (the standard C version returns
* only 15-bits).
*/
#define INITIAL_SEED 0xcaa938dbL
static unsigned long IL_StandardRandom_seed = INITIAL_SEED; /* always use a non-zero seed */
#define IL_RMULT 1103515245L
#if defined __BORLANDC__ || defined __WATCOMC__
#pragma argsused
#endif
static cell AMX_NATIVE_CALL core_random(AMX *amx,const cell *params)
{
unsigned long lo, hi, ll, lh, hh, hl;
unsigned long result;
/* one-time initialization (or, mostly one-time) */
#if !defined SN_TARGET_PS2 && !defined _WIN32_WCE && !defined __ICC430__
if (IL_StandardRandom_seed == INITIAL_SEED)
IL_StandardRandom_seed=(unsigned long)time(NULL);
#endif
(void)amx;
lo = IL_StandardRandom_seed & 0xffff;
hi = IL_StandardRandom_seed >> 16;
IL_StandardRandom_seed = IL_StandardRandom_seed * IL_RMULT + 12345;
ll = lo * (IL_RMULT & 0xffff);
lh = lo * (IL_RMULT >> 16 );
hl = hi * (IL_RMULT & 0xffff);
hh = hi * (IL_RMULT >> 16 );
result = ((ll + 12345) >> 16) + lh + hl + (hh << 16);
result &= ~LONG_MIN; /* remove sign bit */
if (params[1]!=0)
result %= params[1];
return (cell)result;
}
#endif
#if defined __cplusplus
extern "C"
#endif
const AMX_NATIVE_INFO core_Natives[] = {
{ "numargs", numargs },
{ "getarg", getarg },
{ "setarg", setarg },
{ "heapspace", heapspace },
{ "funcidx", funcidx },
{ "swapchars", swapchars },
{ "tolower", core_tolower },
{ "toupper", core_toupper },
{ "min", core_min },
{ "max", core_max },
{ "clamp", core_clamp },
#if !defined AMX_NORANDOM
{ "random", core_random },
#endif
#if !defined AMX_NOPROPLIST
{ "getproperty", getproperty },
{ "setproperty", setproperty },
{ "deleteproperty",delproperty },
{ "existproperty", existproperty },
#endif
{ NULL, NULL } /* terminator */
};
int AMXEXPORT AMXAPI amx_CoreInit(AMX *amx)
{
return amx_Register(amx, core_Natives, -1);
}
int AMXEXPORT AMXAPI amx_CoreCleanup(AMX *amx)
{
(void)amx;
#if !defined AMX_NOPROPLIST
while (proproot.next!=NULL)
list_delete(&proproot,proproot.next);
#endif
return AMX_ERR_NONE;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,379 @@
/* Float arithmetic for the Pawn Abstract Machine
*
* Copyright (c) Artran, Inc. 1999
* Written by Greg Garner (gmg@artran.com)
* This file may be freely used. No warranties of any kind.
*
* CHANGES -
* 2002-08-27: Basic conversion of source from C++ to C by Adam D. Moss
* <adam@gimp.org> <aspirin@icculus.org>
* 2003-08-29: Removal of the dynamic memory allocation and replacing two
* type conversion functions by macros, by Thiadmer Riemersma
* 2003-09-22: Moved the type conversion macros to AMX.H, and simplifications
* of some routines, by Thiadmer Riemersma
* 2003-11-24: A few more native functions (geometry), plus minor modifications,
* mostly to be compatible with dynamically loadable extension
* modules, by Thiadmer Riemersma
* 2004-01-09: Adaptions for 64-bit cells (using "double precision"), by
* Thiadmer Riemersma
*/
#include <stdlib.h> /* for atof() */
#include <stdio.h> /* for NULL */
#include <assert.h>
#include <math.h>
#include "amx.h"
/*
#if defined __BORLANDC__
#pragma resource "amxFloat.res"
#endif
*/
#if PAWN_CELL_SIZE==32
#define REAL float
#elif PAWN_CELL_SIZE==64
#define REAL double
#else
#error Unsupported cell size
#endif
#define PI 3.1415926535897932384626433832795
/******************************************************************/
static cell AMX_NATIVE_CALL n_float(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = integer value to convert to a float
*/
REAL fValue;
(void)amx;
/* Convert to a float. Calls the compilers long to float conversion. */
fValue = (REAL) params[1];
/* Return the cell. */
return amx_ftoc(fValue);
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_strfloat(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = virtual string address to convert to a float
*/
char szSource[60];
cell *pString;
REAL fNum;
int nLen;
(void)amx;
/* They should have sent us 1 cell. */
assert(params[0]/sizeof(cell)==1);
/* Get the real address of the string. */
pString=amx_Address(amx,params[1]);
/* Find out how long the string is in characters. */
amx_StrLen(pString, &nLen);
if (nLen == 0 || nLen >= sizeof szSource)
return 0;
/* Now convert the Pawn string into a C type null terminated string */
amx_GetString(szSource, pString, 0, sizeof szSource);
/* Now convert this to a float. */
fNum = (REAL)atof(szSource);
return amx_ftoc(fNum);
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_floatmul(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float operand 1
* params[2] = float operand 2
*/
REAL fRes = amx_ctof(params[1]) * amx_ctof(params[2]);
(void)amx;
return amx_ftoc(fRes);
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_floatdiv(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float dividend (top)
* params[2] = float divisor (bottom)
*/
REAL fRes = amx_ctof(params[1]) / amx_ctof(params[2]);
(void)amx;
return amx_ftoc(fRes);
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_floatadd(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float operand 1
* params[2] = float operand 2
*/
REAL fRes = amx_ctof(params[1]) + amx_ctof(params[2]);
(void)amx;
return amx_ftoc(fRes);
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_floatsub(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float operand 1
* params[2] = float operand 2
*/
REAL fRes = amx_ctof(params[1]) - amx_ctof(params[2]);
(void)amx;
return amx_ftoc(fRes);
}
/******************************************************************/
/* Return fractional part of float */
static cell AMX_NATIVE_CALL n_floatfract(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float operand
*/
REAL fA = amx_ctof(params[1]);
fA = fA - (REAL)(floor((double)fA));
(void)amx;
return amx_ftoc(fA);
}
/******************************************************************/
/* Return integer part of float, rounded */
static cell AMX_NATIVE_CALL n_floatround(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float operand
* params[2] = Type of rounding (integer)
*/
REAL fA = amx_ctof(params[1]);
(void)amx;
switch (params[2])
{
case 1: /* round downwards */
fA = (REAL)(floor((double)fA));
break;
case 2: /* round upwards */
fA = (REAL)(ceil((double)fA));
break;
case 3: /* round towards zero (truncate) */
if ( fA>=0.0 )
fA = (REAL)(floor((double)fA));
else
fA = (REAL)(ceil((double)fA));
break;
default: /* standard, round to nearest */
fA = (REAL)(floor((double)fA+.5));
break;
}
return (cell)fA;
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_floatcmp(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float operand 1
* params[2] = float operand 2
*/
REAL fA, fB;
(void)amx;
fA = amx_ctof(params[1]);
fB = amx_ctof(params[2]);
if (fA == fB)
return 0;
else if (fA>fB)
return 1;
else
return -1;
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_floatsqroot(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float operand
*/
REAL fA = amx_ctof(params[1]);
fA = (REAL)sqrt(fA);
if (fA < 0)
return amx_RaiseError(amx, AMX_ERR_DOMAIN);
return amx_ftoc(fA);
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_floatpower(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float operand 1 (base)
* params[2] = float operand 2 (exponent)
*/
REAL fA = amx_ctof(params[1]);
REAL fB = amx_ctof(params[2]);
fA = (REAL)pow(fA, fB);
(void)amx;
return amx_ftoc(fA);
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_floatlog(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float operand 1 (value)
* params[2] = float operand 2 (base)
*/
REAL fValue = amx_ctof(params[1]);
REAL fBase = amx_ctof(params[2]);
(void)amx;
if (fValue <= 0.0 || fBase <= 0)
return amx_RaiseError(amx, AMX_ERR_DOMAIN);
if (fBase == 10.0) // ??? epsilon
fValue = (REAL)log10(fValue);
else
fValue = (REAL)(log(fValue) / log(fBase));
return amx_ftoc(fValue);
}
static REAL ToRadians(REAL angle, int radix)
{
switch (radix)
{
case 1: /* degrees, sexagesimal system (technically: degrees/minutes/seconds) */
return (REAL)(angle * PI / 180.0);
case 2: /* grades, centesimal system */
return (REAL)(angle * PI / 200.0);
default: /* assume already radian */
return angle;
} /* switch */
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_floatsin(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float operand 1 (angle)
* params[2] = float operand 2 (radix)
*/
REAL fA = amx_ctof(params[1]);
fA = ToRadians(fA, params[2]);
fA = (float)sin(fA);
(void)amx;
return amx_ftoc(fA);
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_floatcos(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float operand 1 (angle)
* params[2] = float operand 2 (radix)
*/
REAL fA = amx_ctof(params[1]);
fA = ToRadians(fA, params[2]);
fA = (float)cos(fA);
(void)amx;
return amx_ftoc(fA);
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_floattan(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = float operand 1 (angle)
* params[2] = float operand 2 (radix)
*/
REAL fA = amx_ctof(params[1]);
fA = ToRadians(fA, params[2]);
fA = (float)tan(fA);
(void)amx;
return amx_ftoc(fA);
}
/******************************************************************/
static cell AMX_NATIVE_CALL n_floatabs(AMX *amx,const cell *params)
{
REAL fA = amx_ctof(params[1]);
fA = (fA >= 0) ? fA : -fA;
(void)amx;
return amx_ftoc(fA);
}
/******************************************************************/
/* return the integer part of a real value, truncated
/* Return integer part of float, truncated (same as floatround
* with mode 3)
*/
static cell AMX_NATIVE_CALL n_floatint(AMX *amx,const cell *params)
{
REAL fA = amx_ctof(params[1]);
if ( fA>=0.0 )
fA = (REAL)(floor((double)fA));
else
fA = (REAL)(ceil((double)fA));
(void)amx;
return (cell)fA;
}
#if defined __cplusplus
extern "C"
#endif
const AMX_NATIVE_INFO float_Natives[] = {
{ "float", n_float },
{ "strfloat", n_strfloat },
{ "floatmul", n_floatmul },
{ "floatdiv", n_floatdiv },
{ "floatadd", n_floatadd },
{ "floatsub", n_floatsub },
{ "floatfract", n_floatfract },
{ "floatround", n_floatround },
{ "floatcmp", n_floatcmp },
{ "floatsqroot", n_floatsqroot},
{ "floatpower", n_floatpower },
{ "floatlog", n_floatlog },
{ "floatsin", n_floatsin },
{ "floatcos", n_floatcos },
{ "floattan", n_floattan },
{ "floatabs", n_floatabs },
{ "floatint", n_floatint }, // also add user-defined operator "="
{ NULL, NULL } /* terminator */
};
int AMXEXPORT AMXAPI amx_FloatInit(AMX *amx)
{
return amx_Register(amx,float_Natives,-1);
}
int AMXEXPORT AMXAPI amx_FloatCleanup(AMX *amx)
{
(void)amx;
return AMX_ERR_NONE;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,480 @@
/* Date/time module for the Pawn Abstract Machine
*
* Copyright (c) ITB CompuPhase, 2001-2013
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Version: $Id: amxtime.c 4983 2013-10-21 07:32:57Z $
*/
#include <time.h>
#include <assert.h>
#include "amx.h"
#if defined __WIN32__ || defined _WIN32 || defined _Windows
#include <windows.h>
#include <mmsystem.h>
#endif
#define CELLMIN (-1 << (8*sizeof(cell) - 1))
#define SECONDS_PER_MINUTE 60
#define SECONDS_PER_HOUR 3600
#define SECONDS_PER_DAY 86400
#define SECONDS_PER_YEAR 31556952 /* based on 365.2425 days per year */
#if !defined CLOCKS_PER_SEC
#define CLOCKS_PER_SEC CLK_TCK
#endif
#if defined __WIN32__ || defined _WIN32 || defined WIN32
static int timerset = 0;
/* timeGetTime() is more accurate on WindowsNT if timeBeginPeriod(1) is set */
#define INIT_TIMER() \
if (!timerset) { \
timeBeginPeriod(1); \
timerset=1; \
}
#else
#define INIT_TIMER()
#endif
static unsigned long timestamp;
static unsigned long timelimit;
static int timerepeat;
static const unsigned char monthdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
static int wrap(int value, int min, int max)
{
if (value<min)
value=max;
else if (value>max)
value=min;
return value;
}
static unsigned long gettimestamp(void)
{
unsigned long value;
#if defined __WIN32__ || defined _WIN32 || defined WIN32
value=timeGetTime(); /* this value is already in milliseconds */
#elif defined __linux || defined __linux__ || defined __LINUX__ || defined __APPLE__
struct timeval tv;
gettimeofday(&tv, NULL);
value = ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
#else
value=clock();
#if CLOCKS_PER_SEC<1000
/* convert to milliseconds */
value=(cell)((1000L * value) / CLOCKS_PER_SEC);
#elif CLOCKS_PER_SEC>1000
/* convert to milliseconds */
value=(cell)(value/(CLOCKS_PER_SEC/1000));
#endif
#endif
return value;
}
void stamp2datetime(unsigned long sec1970,
int *year, int *month, int *day,
int *hour, int *minute, int *second)
{
int days, seconds;
/* find the year */
assert(year!=NULL);
for (*year = 1970; ; *year += 1) {
days = 365 + ((*year & 0x03) == 0); /* clumsy "leap-year" routine, fails for 2100 */
seconds = days * SECONDS_PER_DAY;
if ((unsigned long)seconds > sec1970)
break;
sec1970 -= seconds;
} /* if */
/* find the month */
assert(month!=NULL);
for (*month = 1; ; *month += 1) {
days = monthdays[*month - 1];
seconds = days * SECONDS_PER_DAY;
if ((unsigned long)seconds > sec1970)
break;
sec1970 -= seconds;
} /* if */
/* find the day */
assert(day!=NULL);
for (*day = 1; sec1970 >= SECONDS_PER_DAY; *day += 1)
sec1970 -= SECONDS_PER_DAY;
/* find the hour */
assert(hour!=NULL);
for (*hour = 0; sec1970 >= SECONDS_PER_HOUR; *hour += 1)
sec1970 -= SECONDS_PER_HOUR;
/* find the minute */
assert(minute!=NULL);
for (*minute = 0; sec1970 >= SECONDS_PER_MINUTE; *minute += 1)
sec1970 -= SECONDS_PER_MINUTE;
/* remainder is the number of seconds */
assert(second!=NULL);
*second = (int)sec1970;
}
static void settime(cell hour,cell minute,cell second)
{
#if defined __WIN32__ || defined _WIN32 || defined WIN32
SYSTEMTIME systim;
GetLocalTime(&systim);
if (hour!=CELLMIN)
systim.wHour=(WORD)wrap((int)hour,0,23);
if (minute!=CELLMIN)
systim.wMinute=(WORD)wrap((int)minute,0,59);
if (second!=CELLMIN)
systim.wSecond=(WORD)wrap((int)second,0,59);
SetLocalTime(&systim);
#else
/* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
* must have "root" permission to call stime(); many POSIX systems will
* have settimeofday() instead
*/
time_t sec1970;
struct tm gtm;
#if defined __APPLE__ /* also valid for other POSIX systems */
struct timeval tv;
#endif
time(&sec1970);
gtm=*localtime(&sec1970);
if (hour!=CELLMIN)
gtm.tm_hour=wrap((int)hour,0,23);
if (minute!=CELLMIN)
gtm.tm_min=wrap((int)minute,0,59);
if (second!=CELLMIN)
gtm.tm_sec=wrap((int)second,0,59);
sec1970=mktime(&gtm);
#if defined __APPLE__ /* also valid for other POSIX systems */
tv.tv_sec = sec1970;
tv.tv_usec = 0;
settimeofday(&tv, 0);
#else
stime(&sec1970);
#endif
#endif
}
static void setdate(cell year,cell month,cell day)
{
int maxday;
#if defined __WIN32__ || defined _WIN32 || defined WIN32
SYSTEMTIME systim;
GetLocalTime(&systim);
if (year!=CELLMIN)
systim.wYear=(WORD)wrap((int)year,1970,2099);
if (month!=CELLMIN)
systim.wMonth=(WORD)wrap((int)month,1,12);
maxday=monthdays[systim.wMonth - 1];
if (systim.wMonth==2 && ((systim.wYear % 4)==0 && ((systim.wYear % 100)!=0 || (systim.wYear % 400)==0)))
maxday++;
if (day!=CELLMIN)
systim.wDay=(WORD)wrap((int)day,1,maxday);
SetLocalTime(&systim);
#else
/* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
* must have "root" permission to call stime(); many POSIX systems will
* have settimeofday() instead
*/
time_t sec1970;
struct tm gtm;
#if defined __APPLE__ /* also valid for other POSIX systems */
struct timeval tv;
#endif
time(&sec1970);
gtm=*localtime(&sec1970);
if (year!=CELLMIN)
gtm.tm_year=year-1900;
if (month!=CELLMIN)
gtm.tm_mon=month-1;
if (day!=CELLMIN)
gtm.tm_mday=day;
sec1970=mktime(&gtm);
#if defined __APPLE__ /* also valid for other POSIX systems */
tv.tv_sec = sec1970;
tv.tv_usec = 0;
settimeofday(&tv, 0);
#else
stime(&sec1970);
#endif
#endif
}
/* settime(hour, minute, second)
* Always returns 0
*/
static cell AMX_NATIVE_CALL n_settime(AMX *amx, const cell *params)
{
(void)amx;
settime(params[1],params[2],params[3]);
return 0;
}
/* gettime(&hour, &minute, &second)
* The return value is the number of seconds since 1 January 1970 (Unix system
* time).
*/
static cell AMX_NATIVE_CALL n_gettime(AMX *amx, const cell *params)
{
time_t sec1970;
struct tm gtm;
cell *cptr;
assert(params[0]==(int)(3*sizeof(cell)));
time(&sec1970);
/* on DOS/Windows, the timezone is usually not set for the C run-time
* library; in that case gmtime() and localtime() return the same value
*/
gtm=*localtime(&sec1970);
cptr=amx_Address(amx,params[1]);
*cptr=gtm.tm_hour;
cptr=amx_Address(amx,params[2]);
*cptr=gtm.tm_min;
cptr=amx_Address(amx,params[3]);
*cptr=gtm.tm_sec;
/* the time() function returns the number of seconds since January 1 1970
* in Universal Coordinated Time (the successor to Greenwich Mean Time)
*/
return (cell)sec1970;
}
/* setdate(year, month, day)
* Always returns 0
*/
static cell AMX_NATIVE_CALL n_setdate(AMX *amx, const cell *params)
{
(void)amx;
setdate(params[1],params[2],params[3]);
return 0;
}
/* getdate(&year, &month, &day)
* The return value is the number of days since the start of the year. January
* 1 is day 1 of the year.
*/
static cell AMX_NATIVE_CALL n_getdate(AMX *amx, const cell *params)
{
time_t sec1970;
struct tm gtm;
cell *cptr;
assert(params[0]==(int)(3*sizeof(cell)));
time(&sec1970);
gtm=*localtime(&sec1970);
cptr=amx_Address(amx,params[1]);
*cptr=gtm.tm_year+1900;
cptr=amx_Address(amx,params[2]);
*cptr=gtm.tm_mon+1;
cptr=amx_Address(amx,params[3]);
*cptr=gtm.tm_mday;
return gtm.tm_yday+1;
}
/* tickcount(&granularity)
* Returns the number of milliseconds since start-up. For a 32-bit cell, this
* count overflows after approximately 24 days of continuous operation.
*/
static cell AMX_NATIVE_CALL n_tickcount(AMX *amx, const cell *params)
{
cell *cptr;
assert(params[0]==(int)sizeof(cell));
INIT_TIMER();
cptr=amx_Address(amx,params[1]);
#if defined __WIN32__ || defined _WIN32 || defined WIN32
*cptr=1000; /* granularity = 1 ms */
#else
*cptr=(cell)CLOCKS_PER_SEC; /* in Unix/Linux, this is often 100 */
#endif
return gettimestamp() & 0x7fffffff;
}
/* delay(milliseconds)
* Pauses for (at least) the requested number of milliseconds.
*/
static cell AMX_NATIVE_CALL n_delay(AMX *amx, const cell *params)
{
unsigned long stamp;
(void)amx;
assert(params[0]==(int)sizeof(cell));
INIT_TIMER();
stamp=gettimestamp();
while (gettimestamp()-stamp < (unsigned long)params[1])
/* nothing */;
return 0;
}
/* settimer(milliseconds, bool: singleshot = false)
* Sets the delay until the @timer() callback is called. The timer may either
* be single-shot or repetitive.
*/
static cell AMX_NATIVE_CALL n_settimer(AMX *amx, const cell *params)
{
(void)amx;
assert(params[0]==(int)(2*sizeof(cell)));
timestamp=gettimestamp();
timelimit=params[1];
timerepeat=(int)(params[2]==0);
return 0;
}
/* bool: gettimer(&milliseconds, bool: &singleshot = false)
* Retrieves the timer set with settimer(); returns true if a timer
* was set up, or false otherwise.
*/
static cell AMX_NATIVE_CALL n_gettimer(AMX *amx, const cell *params)
{
cell *cptr;
assert(params[0]==(int)(2*sizeof(cell)));
cptr=amx_Address(amx,params[1]);
*cptr=timelimit;
cptr=amx_Address(amx,params[2]);
*cptr=timerepeat;
return timelimit>0;
}
/* settimestamp(seconds1970) sets the date and time from a single parameter: the
* number of seconds since 1 January 1970.
*/
static cell AMX_NATIVE_CALL n_settimestamp(AMX *amx, const cell *params)
{
#if defined __WIN32__ || defined _WIN32 || defined WIN32
int year, month, day, hour, minute, second;
stamp2datetime(params[1],
&year, &month, &day,
&hour, &minute, &second);
setdate(year, month, day);
settime(hour, minute, second);
#else
/* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
* must have "root" permission to call stime(); many POSIX systems will
* have settimeofday() instead
*/
#if defined __APPLE__ /* also valid for other POSIX systems */
struct timeval tv;
tv.tv_sec = params[1];
tv.tv_usec = 0;
settimeofday(&tv, 0);
#else
time_t sec1970=(time_t)params[1];
stime(&sec1970);
#endif
#endif
(void)amx;
return 0;
}
/* cvttimestamp(seconds1970, &year, &month, &day, &hour, &minute, &second)
*/
static cell AMX_NATIVE_CALL n_cvttimestamp(AMX *amx, const cell *params)
{
int year, month, day, hour, minute, second;
(void)amx;
stamp2datetime(params[1],
&year, &month, &day,
&hour, &minute, &second);
return 0;
}
#if !defined AMXTIME_NOIDLE
static AMX_IDLE PrevIdle = NULL;
static int idxTimer = -1;
static int AMXAPI amx_TimeIdle(AMX *amx, int AMXAPI Exec(AMX *, cell *, int))
{
int err=0;
assert(idxTimer >= 0);
if (PrevIdle != NULL)
PrevIdle(amx, Exec);
if (timelimit>0 && (gettimestamp()-timestamp)>=timelimit) {
if (timerepeat)
timestamp+=timelimit;
else
timelimit=0; /* do not repeat single-shot timer */
err = Exec(amx, NULL, idxTimer);
while (err == AMX_ERR_SLEEP)
err = Exec(amx, NULL, AMX_EXEC_CONT);
} /* if */
return err;
}
#endif
#if defined __cplusplus
extern "C"
#endif
const AMX_NATIVE_INFO time_Natives[] = {
{ "gettime", n_gettime },
{ "settime", n_settime },
{ "getdate", n_getdate },
{ "setdate", n_setdate },
{ "tickcount", n_tickcount },
{ "settimer", n_settimer },
{ "gettimer", n_gettimer },
{ "delay", n_delay },
{ "settimestamp", n_settimestamp },
{ "cvttimestamp", n_cvttimestamp },
{ NULL, NULL } /* terminator */
};
int AMXEXPORT AMXAPI amx_TimeInit(AMX *amx)
{
#if !defined AMXTIME_NOIDLE
/* see whether there is a @timer() function */
if (amx_FindPublic(amx,"@timer",&idxTimer) == AMX_ERR_NONE) {
if (amx_GetUserData(amx, AMX_USERTAG('I','d','l','e'), (void**)&PrevIdle) != AMX_ERR_NONE)
PrevIdle = NULL;
amx_SetUserData(amx, AMX_USERTAG('I','d','l','e'), amx_TimeIdle);
} /* if */
#endif
return amx_Register(amx, time_Natives, -1);
}
int AMXEXPORT AMXAPI amx_TimeCleanup(AMX *amx)
{
(void)amx;
#if !defined AMXTIME_NOIDLE
PrevIdle = NULL;
#endif
return AMX_ERR_NONE;
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,184 @@
/******************************************************************************
* fpattern.h
* Functions for matching filename patterns to filenames.
*
* Usage
* Filename patterns are composed of regular (printable) characters which
* may comprise a filename as well as special pattern matching characters:
*
* . Matches a period (.).
* Note that a period in a filename is not treated any
* differently than any other character.
*
* ? Any.
* Matches any single character except '/' or '\'.
*
* * Closure.
* Matches zero or more occurences of any characters other
* than '/' or '\'.
* Leading '*' characters are allowed.
*
* SUB Substitute (^Z); optionally supported.
* Similar to '*', this matches zero or more occurences of
* any characters other than '/', '\', or '.'.
* Leading '^Z' characters are allowed.
*
* [ab] Set.
* Matches the single character 'a' or 'b'.
* If the dash '-' character is to be included, it must
* immediately follow the opening bracket '['.
* If the closing bracket ']' character is to be included,
* it must be preceded by a quote '`'.
*
* [a-z] Range.
* Matches a single character in the range 'a' to 'z'.
* Ranges and sets may be combined within the same set of
* brackets.
*
* [!R] Exclusive range.
* Matches a single character not in the range 'R'.
* If range 'R' includes the dash '-' character, the dash
* must immediately follow the caret '!'.
*
* ! Not; optionally supported.
* Makes the following pattern (up to the next '/') match
* any filename except those what it would normally match.
*
* / Path separator (UNIX and DOS).
* Matches a '/' or '\' pathname (directory) separator.
* Multiple separators are treated like a single
* separator.
* A leading separator indicates an absolute pathname.
*
* \ Path separator (DOS).
* Same as the '/' character.
* Note that this character must be escaped if used within
* string constants ("\\").
*
* \ Quote (UNIX).
* Makes the next character a regular (nonspecial)
* character.
* Note that to match the quote character itself, it must
* be quoted.
* Note that this character must be escaped if used within
* string constants ("\\").
*
* ` Quote (DOS).
* Makes the next character a regular (nonspecial)
* character.
* Note that to match the quote character itself, it must
* be quoted.
*
* Upper and lower case alphabetic characters are considered identical,
* i.e., 'a' and 'A' match each other.
* (What constitutes a lowercase letter depends on the current locale
* settings.)
*
* Spaces and control characters are treated as normal characters.
*
* Examples
* The following patterns in the left column will match the filenames in
* the middle column and will not match filenames in the right column:
*
* Pattern Will Match Will Not Match
* ------- ---------- --------------
* a a (only) (anything else)
* a. a. (only) (anything else)
* a?c abc, acc, arc, a.c a, ac, abbc
* a*c ac, abc, abbc, acc, a.c a, ab, acb, bac
* a* a, ab, abb, a., a.b b, ba
* * a, ab, abb, a., .foo, a.foo (nothing)
* *. a., ab., abb., a.foo. a, ab, a.foo, .foo
* *.* a., a.b, ah.bc.foo a
* ^Z a, ab, abb a., .foo, a.foo
* ^Z. a., ab., abb. a, .foo, a.foo
* ^Z.* a, a., .foo, a.foo ab, abb
* *2.c 2.c, 12.c, foo2.c, foo.12.c 2x.c
* a[b-z]c abc, acc, azc (only) (anything else)
* [ab0-9]x ax, bx, 0x, 9x zx
* a[-.]b a-b, a.b (only) (anything else)
* a[!a-z]b a0b, a.b, a@b aab, azb, aa0b
* a[!-b]x a0x, a+x, acx a-x, abx, axxx
* a[-!b]x a-x, a!x, abx (only) (anything else)
* a[`]]x a]x (only) (anything else)
* a``x a`x (only) (anything else)
* oh`! oh! (only) (anything else)
* is`?it is?it (only) (anything else)
* !a?c a, ac, ab, abb, acb, a.foo abc, a.c, azc
*
* History
* 1.00 1997-01-03 David Tribble.
* First cut.
* 1.01 1997-01-03 David Tribble.
* Added '^Z' pattern character.
* Added fpattern_matchn().
* 1.02 1997-01-26 David Tribble.
* Changed range negation character from '^' to '!', ala Unix.
* 1.03 1997-08-02 David Tribble.
* Added 'FPAT_XXX' macro constants.
*
* Limitations
* This code is copyrighted by the author, but permission is hereby
* granted for its unlimited use provided that the original copyright
* and authorship notices are retained intact.
*
* Other queries can be sent to:
* dtribble@technologist.com
* david.tribble@beasys.com
* dtribble@flash.net
*
* Copyright ©1997 by David R. Tribble, all rights reserved.
*/
#ifndef fpattern_h
#define fpattern_h 1
#ifdef __cplusplus
extern "C"
{
#endif
/* Options */
//#define FPAT_DELIM /* handle path delimiters in a special way */
//#define FPAT_SUBCLOS /* support alternative closure */
//#define FPAT_NOT_ENABLED /* !pattern is enabled */
#define FPAT_MSET_ENABLED /* multi-set/range is enabled */
/* Manifest constants */
#define FPAT_QUOTE '`' /* Quotes a special char */
#define FPAT_DEL '/' /* Path delimiter (used only when FPAT_DELIM is true) */
#define FPAT_DEL2 '\\' /* Path delimiter (used only when FPAT_DELIM is true) */
#define FPAT_DOT '.' /* Dot char */
#define FPAT_NOT '!' /* Exclusion (also used for sets) */
#define FPAT_ANY '?' /* Any one char */
#define FPAT_CLOS '*' /* Zero or more chars */
#define FPAT_CLOSP '\x1A' /* Zero or more nondelimiters (used only when FPAT_SUBCLOS is true) */
#define FPAT_SET_L '[' /* Set/range open bracket */
#define FPAT_SET_R ']' /* Set/range close bracket */
#define FPAT_MSET_L '{' /* Multi-set/range open bracket */
#define FPAT_MSET_R '}' /* Multi-set/range close bracket*/
#define FPAT_SET_THRU '-' /* Set range of chars */
#define FPAT_INVALID 0 /* invalid pattern */
#define FPAT_CLOSED 1 /* valid pattern */
#define FPAT_OPEN 2 /* valid pattern */
/* Public functions */
extern int fpattern_isvalid(const char *pat);
extern int fpattern_match(const char *pat, const char *fname, int flength, int keepcase);
extern int fpattern_matchn(const char *pat, const char *fname, int flength, int keepcase);
extern int fpattern_matchcount(const char *pat, const char *fname, int flength, int minlength, int keepcase);
#ifdef __cplusplus
}
#endif
#endif /* fpattern_h */

@ -0,0 +1,766 @@
/*
* BinReloc - a library for creating relocatable executables
* Written by: Hongli Lai <h.lai@chello.nl>
* http://autopackage.org/
*
* This source code is public domain. You can relicense this code
* under whatever license you want.
*
* See http://autopackage.org/docs/binreloc/ for
* more information and how to use this.
*/
#ifndef __BINRELOC_C__
#define __BINRELOC_C__
#ifdef ENABLE_BINRELOC
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#endif /* ENABLE_BINRELOC */
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
#include "binreloc.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** @internal
* Find the canonical filename of the executable. Returns the filename
* (which must be freed) or NULL on error. If the parameter 'error' is
* not NULL, the error code will be stored there, if an error occured.
*/
static char *
_br_find_exe (BrInitError *error)
{
#ifndef ENABLE_BINRELOC
if (error)
*error = BR_INIT_ERROR_DISABLED;
return NULL;
#else
char *path, *path2, *line, *result;
size_t buf_size;
ssize_t size;
struct stat stat_buf;
FILE *f;
/* Read from /proc/self/exe (symlink) */
if (sizeof (path) > SSIZE_MAX)
buf_size = SSIZE_MAX - 1;
else
buf_size = PATH_MAX - 1;
path = (char *) malloc (buf_size);
if (path == NULL) {
/* Cannot allocate memory. */
if (error)
*error = BR_INIT_ERROR_NOMEM;
return NULL;
}
path2 = (char *) malloc (buf_size);
if (path2 == NULL) {
/* Cannot allocate memory. */
if (error)
*error = BR_INIT_ERROR_NOMEM;
free (path);
return NULL;
}
strncpy (path2, "/proc/self/exe", buf_size - 1);
while (1) {
int i;
size = readlink (path2, path, buf_size - 1);
if (size == -1) {
/* Error. */
free (path2);
break;
}
/* readlink() success. */
path[size] = '\0';
/* Check whether the symlink's target is also a symlink.
* We want to get the final target. */
i = stat (path, &stat_buf);
if (i == -1) {
/* Error. */
free (path2);
break;
}
/* stat() success. */
if (!S_ISLNK (stat_buf.st_mode)) {
/* path is not a symlink. Done. */
free (path2);
return path;
}
/* path is a symlink. Continue loop and resolve this. */
strncpy (path, path2, buf_size - 1);
}
/* readlink() or stat() failed; this can happen when the program is
* running in Valgrind 2.2. Read from /proc/self/maps as fallback. */
buf_size = PATH_MAX + 128;
line = (char *) realloc (path, buf_size);
if (line == NULL) {
/* Cannot allocate memory. */
free (path);
if (error)
*error = BR_INIT_ERROR_NOMEM;
return NULL;
}
f = fopen ("/proc/self/maps", "r");
if (f == NULL) {
free (line);
if (error)
*error = BR_INIT_ERROR_OPEN_MAPS;
return NULL;
}
/* The first entry should be the executable name. */
result = fgets (line, (int) buf_size, f);
if (result == NULL) {
fclose (f);
free (line);
if (error)
*error = BR_INIT_ERROR_READ_MAPS;
return NULL;
}
/* Get rid of newline character. */
buf_size = strlen (line);
if (buf_size <= 0) {
/* Huh? An empty string? */
fclose (f);
free (line);
if (error)
*error = BR_INIT_ERROR_INVALID_MAPS;
return NULL;
}
if (line[buf_size - 1] == 10)
line[buf_size - 1] = 0;
/* Extract the filename; it is always an absolute path. */
path = strchr (line, '/');
/* Sanity check. */
if (strstr (line, " r-xp ") == NULL || path == NULL) {
fclose (f);
free (line);
if (error)
*error = BR_INIT_ERROR_INVALID_MAPS;
return NULL;
}
path = strdup (path);
free (line);
fclose (f);
return path;
#endif /* ENABLE_BINRELOC */
}
/** @internal
* Find the canonical filename of the executable which owns symbol.
* Returns a filename which must be freed, or NULL on error.
*/
static char *
_br_find_exe_for_symbol (const void *symbol, BrInitError *error)
{
#ifndef ENABLE_BINRELOC
if (error)
*error = BR_INIT_ERROR_DISABLED;
return (char *) NULL;
#else
#define SIZE PATH_MAX + 100
FILE *f;
size_t address_string_len;
char *address_string, line[SIZE], *found;
if (symbol == NULL)
return (char *) NULL;
f = fopen ("/proc/self/maps", "r");
if (f == NULL)
return (char *) NULL;
address_string_len = 4;
address_string = (char *) malloc (address_string_len);
found = (char *) NULL;
while (!feof (f)) {
char *start_addr, *end_addr, *end_addr_end, *file;
void *start_addr_p, *end_addr_p;
size_t len;
if (fgets (line, SIZE, f) == NULL)
break;
/* Sanity check. */
if (strstr (line, " r-xp ") == NULL || strchr (line, '/') == NULL)
continue;
/* Parse line. */
start_addr = line;
end_addr = strchr (line, '-');
file = strchr (line, '/');
/* More sanity check. */
if (!(file > end_addr && end_addr != NULL && end_addr[0] == '-'))
continue;
end_addr[0] = '\0';
end_addr++;
end_addr_end = strchr (end_addr, ' ');
if (end_addr_end == NULL)
continue;
end_addr_end[0] = '\0';
len = strlen (file);
if (len == 0)
continue;
if (file[len - 1] == '\n')
file[len - 1] = '\0';
/* Get rid of "(deleted)" from the filename. */
len = strlen (file);
if (len > 10 && strcmp (file + len - 10, " (deleted)") == 0)
file[len - 10] = '\0';
/* I don't know whether this can happen but better safe than sorry. */
len = strlen (start_addr);
if (len != strlen (end_addr))
continue;
/* Transform the addresses into a string in the form of 0xdeadbeef,
* then transform that into a pointer. */
if (address_string_len < len + 3) {
address_string_len = len + 3;
address_string = (char *) realloc (address_string, address_string_len);
}
memcpy (address_string, "0x", 2);
memcpy (address_string + 2, start_addr, len);
address_string[2 + len] = '\0';
sscanf (address_string, "%p", &start_addr_p);
memcpy (address_string, "0x", 2);
memcpy (address_string + 2, end_addr, len);
address_string[2 + len] = '\0';
sscanf (address_string, "%p", &end_addr_p);
if (symbol >= start_addr_p && symbol < end_addr_p) {
found = file;
break;
}
}
free (address_string);
fclose (f);
if (found == NULL)
return (char *) NULL;
else
return strdup (found);
#endif /* ENABLE_BINRELOC */
}
#ifndef BINRELOC_RUNNING_DOXYGEN
#undef NULL
#define NULL ((void *) 0) /* typecasted as char* for C++ type safeness */
#endif
static char *exe = (char *) NULL;
/** Initialize the BinReloc library (for applications).
*
* This function must be called before using any other BinReloc functions.
* It attempts to locate the application's canonical filename.
*
* @note If you want to use BinReloc for a library, then you should call
* br_init_lib() instead.
*
* @param error If BinReloc failed to initialize, then the error code will
* be stored in this variable. Set to NULL if you want to
* ignore this. See #BrInitError for a list of error codes.
*
* @returns 1 on success, 0 if BinReloc failed to initialize.
*/
int
br_init (BrInitError *error)
{
exe = _br_find_exe (error);
return exe != NULL;
}
/** Initialize the BinReloc library (for libraries).
*
* This function must be called before using any other BinReloc functions.
* It attempts to locate the calling library's canonical filename.
*
* @note The BinReloc source code MUST be included in your library, or this
* function won't work correctly.
*
* @param error If BinReloc failed to initialize, then the error code will
* be stored in this variable. Set to NULL if you want to
* ignore this. See #BrInitError for a list of error codes.
*
* @returns 1 on success, 0 if a filename cannot be found.
*/
int
br_init_lib (BrInitError *error)
{
exe = _br_find_exe_for_symbol ((const void *) "", error);
return exe != NULL;
}
/** Find the canonical filename of the current application.
*
* @param default_exe A default filename which will be used as fallback.
* @returns A string containing the application's canonical filename,
* which must be freed when no longer necessary. If BinReloc is
* not initialized, or if br_init() failed, then a copy of
* default_exe will be returned. If default_exe is NULL, then
* NULL will be returned.
*/
char *
br_find_exe (const char *default_exe)
{
if (exe == (char *) NULL) {
/* BinReloc is not initialized. */
if (default_exe != (const char *) NULL)
return strdup (default_exe);
else
return (char *) NULL;
}
return strdup (exe);
}
/** Locate the directory in which the current application is installed.
*
* The prefix is generated by the following pseudo-code evaluation:
* \code
* dirname(exename)
* \endcode
*
* @param default_dir A default directory which will used as fallback.
* @return A string containing the directory, which must be freed when no
* longer necessary. If BinReloc is not initialized, or if the
* initialization function failed, then a copy of default_dir
* will be returned. If default_dir is NULL, then NULL will be
* returned.
*/
char *
br_find_exe_dir (const char *default_dir)
{
if (exe == NULL) {
/* BinReloc not initialized. */
if (default_dir != NULL)
return strdup (default_dir);
else
return NULL;
}
return br_dirname (exe);
}
/** Locate the prefix in which the current application is installed.
*
* The prefix is generated by the following pseudo-code evaluation:
* \code
* dirname(dirname(exename))
* \endcode
*
* @param default_prefix A default prefix which will used as fallback.
* @return A string containing the prefix, which must be freed when no
* longer necessary. If BinReloc is not initialized, or if
* the initialization function failed, then a copy of default_prefix
* will be returned. If default_prefix is NULL, then NULL will be returned.
*/
char *
br_find_prefix (const char *default_prefix)
{
char *dir1, *dir2;
if (exe == (char *) NULL) {
/* BinReloc not initialized. */
if (default_prefix != (const char *) NULL)
return strdup (default_prefix);
else
return (char *) NULL;
}
dir1 = br_dirname (exe);
dir2 = br_dirname (dir1);
free (dir1);
return dir2;
}
/** Locate the application's binary folder.
*
* The path is generated by the following pseudo-code evaluation:
* \code
* prefix + "/bin"
* \endcode
*
* @param default_bin_dir A default path which will used as fallback.
* @return A string containing the bin folder's path, which must be freed when
* no longer necessary. If BinReloc is not initialized, or if
* the initialization function failed, then a copy of default_bin_dir will
* be returned. If default_bin_dir is NULL, then NULL will be returned.
*/
char *
br_find_bin_dir (const char *default_bin_dir)
{
char *prefix, *dir;
prefix = br_find_prefix ((const char *) NULL);
if (prefix == (char *) NULL) {
/* BinReloc not initialized. */
if (default_bin_dir != (const char *) NULL)
return strdup (default_bin_dir);
else
return (char *) NULL;
}
dir = br_build_path (prefix, "bin");
free (prefix);
return dir;
}
/** Locate the application's superuser binary folder.
*
* The path is generated by the following pseudo-code evaluation:
* \code
* prefix + "/sbin"
* \endcode
*
* @param default_sbin_dir A default path which will used as fallback.
* @return A string containing the sbin folder's path, which must be freed when
* no longer necessary. If BinReloc is not initialized, or if the
* initialization function failed, then a copy of default_sbin_dir will
* be returned. If default_bin_dir is NULL, then NULL will be returned.
*/
char *
br_find_sbin_dir (const char *default_sbin_dir)
{
char *prefix, *dir;
prefix = br_find_prefix ((const char *) NULL);
if (prefix == (char *) NULL) {
/* BinReloc not initialized. */
if (default_sbin_dir != (const char *) NULL)
return strdup (default_sbin_dir);
else
return (char *) NULL;
}
dir = br_build_path (prefix, "sbin");
free (prefix);
return dir;
}
/** Locate the application's data folder.
*
* The path is generated by the following pseudo-code evaluation:
* \code
* prefix + "/share"
* \endcode
*
* @param default_data_dir A default path which will used as fallback.
* @return A string containing the data folder's path, which must be freed when
* no longer necessary. If BinReloc is not initialized, or if the
* initialization function failed, then a copy of default_data_dir
* will be returned. If default_data_dir is NULL, then NULL will be
* returned.
*/
char *
br_find_data_dir (const char *default_data_dir)
{
char *prefix, *dir;
prefix = br_find_prefix ((const char *) NULL);
if (prefix == (char *) NULL) {
/* BinReloc not initialized. */
if (default_data_dir != (const char *) NULL)
return strdup (default_data_dir);
else
return (char *) NULL;
}
dir = br_build_path (prefix, "share");
free (prefix);
return dir;
}
/** Locate the application's localization folder.
*
* The path is generated by the following pseudo-code evaluation:
* \code
* prefix + "/share/locale"
* \endcode
*
* @param default_locale_dir A default path which will used as fallback.
* @return A string containing the localization folder's path, which must be freed when
* no longer necessary. If BinReloc is not initialized, or if the
* initialization function failed, then a copy of default_locale_dir will be returned.
* If default_locale_dir is NULL, then NULL will be returned.
*/
char *
br_find_locale_dir (const char *default_locale_dir)
{
char *data_dir, *dir;
data_dir = br_find_data_dir ((const char *) NULL);
if (data_dir == (char *) NULL) {
/* BinReloc not initialized. */
if (default_locale_dir != (const char *) NULL)
return strdup (default_locale_dir);
else
return (char *) NULL;
}
dir = br_build_path (data_dir, "locale");
free (data_dir);
return dir;
}
/** Locate the application's library folder.
*
* The path is generated by the following pseudo-code evaluation:
* \code
* prefix + "/lib"
* \endcode
*
* @param default_lib_dir A default path which will used as fallback.
* @return A string containing the library folder's path, which must be freed when
* no longer necessary. If BinReloc is not initialized, or if the initialization
* function failed, then a copy of default_lib_dir will be returned.
* If default_lib_dir is NULL, then NULL will be returned.
*/
char *
br_find_lib_dir (const char *default_lib_dir)
{
char *prefix, *dir;
prefix = br_find_prefix ((const char *) NULL);
if (prefix == (char *) NULL) {
/* BinReloc not initialized. */
if (default_lib_dir != (const char *) NULL)
return strdup (default_lib_dir);
else
return (char *) NULL;
}
dir = br_build_path (prefix, "lib");
free (prefix);
return dir;
}
/** Locate the application's libexec folder.
*
* The path is generated by the following pseudo-code evaluation:
* \code
* prefix + "/libexec"
* \endcode
*
* @param default_libexec_dir A default path which will used as fallback.
* @return A string containing the libexec folder's path, which must be freed when
* no longer necessary. If BinReloc is not initialized, or if the initialization
* function failed, then a copy of default_libexec_dir will be returned.
* If default_libexec_dir is NULL, then NULL will be returned.
*/
char *
br_find_libexec_dir (const char *default_libexec_dir)
{
char *prefix, *dir;
prefix = br_find_prefix ((const char *) NULL);
if (prefix == (char *) NULL) {
/* BinReloc not initialized. */
if (default_libexec_dir != (const char *) NULL)
return strdup (default_libexec_dir);
else
return (char *) NULL;
}
dir = br_build_path (prefix, "libexec");
free (prefix);
return dir;
}
/** Locate the application's configuration files folder.
*
* The path is generated by the following pseudo-code evaluation:
* \code
* prefix + "/etc"
* \endcode
*
* @param default_etc_dir A default path which will used as fallback.
* @return A string containing the etc folder's path, which must be freed when
* no longer necessary. If BinReloc is not initialized, or if the initialization
* function failed, then a copy of default_etc_dir will be returned.
* If default_etc_dir is NULL, then NULL will be returned.
*/
char *
br_find_etc_dir (const char *default_etc_dir)
{
char *prefix, *dir;
prefix = br_find_prefix ((const char *) NULL);
if (prefix == (char *) NULL) {
/* BinReloc not initialized. */
if (default_etc_dir != (const char *) NULL)
return strdup (default_etc_dir);
else
return (char *) NULL;
}
dir = br_build_path (prefix, "etc");
free (prefix);
return dir;
}
/***********************
* Utility functions
***********************/
/** Concatenate str1 and str2 to a newly allocated string.
*
* @param str1 A string.
* @param str2 Another string.
* @returns A newly-allocated string. This string should be freed when no longer needed.
*/
char *
br_strcat (const char *str1, const char *str2)
{
char *result;
size_t len1, len2;
if (str1 == NULL)
str1 = "";
if (str2 == NULL)
str2 = "";
len1 = strlen (str1);
len2 = strlen (str2);
result = (char *) malloc (len1 + len2 + 1);
memcpy (result, str1, len1);
memcpy (result + len1, str2, len2);
result[len1 + len2] = '\0';
return result;
}
char *
br_build_path (const char *dir, const char *file)
{
char *dir2, *result;
size_t len;
int must_free = 0;
len = strlen (dir);
if (len > 0 && dir[len - 1] != '/') {
dir2 = br_strcat (dir, "/");
must_free = 1;
} else
dir2 = (char *) dir;
result = br_strcat (dir2, file);
if (must_free)
free (dir2);
return result;
}
/* Emulates glibc's strndup() */
static char *
br_strndup (const char *str, size_t size)
{
char *result = (char *) NULL;
size_t len;
if (str == (const char *) NULL)
return (char *) NULL;
len = strlen (str);
if (len == 0)
return strdup ("");
if (size > len)
size = len;
result = (char *) malloc (len + 1);
memcpy (result, str, size);
result[size] = '\0';
return result;
}
/** Extracts the directory component of a path.
*
* Similar to g_dirname() or the dirname commandline application.
*
* Example:
* \code
* br_dirname ("/usr/local/foobar"); --> Returns: "/usr/local"
* \endcode
*
* @param path A path.
* @returns A directory name. This string should be freed when no longer needed.
*/
char *
br_dirname (const char *path)
{
char *end, *result;
if (path == (const char *) NULL)
return (char *) NULL;
end = strrchr (path, '/');
if (end == (const char *) NULL)
return strdup (".");
while (end > path && *end == '/')
end--;
result = br_strndup (path, end - path + 1);
if (result[0] == 0) {
free (result);
return strdup ("/");
} else
return result;
}
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __BINRELOC_C__ */

@ -0,0 +1,80 @@
/*
* BinReloc - a library for creating relocatable executables
* Written by: Hongli Lai <h.lai@chello.nl>
* http://autopackage.org/
*
* This source code is public domain. You can relicense this code
* under whatever license you want.
*
* See http://autopackage.org/docs/binreloc/ for
* more information and how to use this.
*/
#ifndef __BINRELOC_H__
#define __BINRELOC_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** These error codes can be returned by br_init(), br_init_lib(), gbr_init() or gbr_init_lib(). */
typedef enum {
/** Cannot allocate memory. */
BR_INIT_ERROR_NOMEM,
/** Unable to open /proc/self/maps; see errno for details. */
BR_INIT_ERROR_OPEN_MAPS,
/** Unable to read from /proc/self/maps; see errno for details. */
BR_INIT_ERROR_READ_MAPS,
/** The file format of /proc/self/maps is invalid; kernel bug? */
BR_INIT_ERROR_INVALID_MAPS,
/** BinReloc is disabled (the ENABLE_BINRELOC macro is not defined). */
BR_INIT_ERROR_DISABLED
} BrInitError;
#ifndef BINRELOC_RUNNING_DOXYGEN
/* Mangle symbol names to avoid symbol collisions with other ELF objects. */
#define br_init SbCJ22537442193159_br_init
#define br_init_lib SbCJ22537442193159_br_init_lib
#define br_find_exe SbCJ22537442193159_br_find_exe
#define br_find_exe_dir SbCJ22537442193159_br_find_exe_dir
#define br_find_prefix SbCJ22537442193159_br_find_prefix
#define br_find_bin_dir SbCJ22537442193159_br_find_bin_dir
#define br_find_sbin_dir SbCJ22537442193159_br_find_sbin_dir
#define br_find_data_dir SbCJ22537442193159_br_find_data_dir
#define br_find_locale_dir SbCJ22537442193159_br_find_locale_dir
#define br_find_lib_dir SbCJ22537442193159_br_find_lib_dir
#define br_find_libexec_dir SbCJ22537442193159_br_find_libexec_dir
#define br_find_etc_dir SbCJ22537442193159_br_find_etc_dir
#define br_strcat SbCJ22537442193159_br_strcat
#define br_build_path SbCJ22537442193159_br_build_path
#define br_dirname SbCJ22537442193159_br_dirname
#endif
int br_init (BrInitError *error);
int br_init_lib (BrInitError *error);
char *br_find_exe (const char *default_exe);
char *br_find_exe_dir (const char *default_dir);
char *br_find_prefix (const char *default_prefix);
char *br_find_bin_dir (const char *default_bin_dir);
char *br_find_sbin_dir (const char *default_sbin_dir);
char *br_find_data_dir (const char *default_data_dir);
char *br_find_locale_dir (const char *default_locale_dir);
char *br_find_lib_dir (const char *default_lib_dir);
char *br_find_libexec_dir (const char *default_libexec_dir);
char *br_find_etc_dir (const char *default_etc_dir);
/* Utility functions */
char *br_strcat (const char *str1, const char *str2);
char *br_build_path (const char *dir, const char *file);
char *br_dirname (const char *path);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __BINRELOC_H__ */

@ -0,0 +1,104 @@
/* Extremely inefficient but portable POSIX getch() */
#include <stdio.h>
#include <string.h>
#include <termios.h> /* for tcgetattr() and tcsetattr() */
#include <unistd.h> /* for read() */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include "getch.h"
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
int
getch (void)
{
struct termios save_termios;
struct termios ios;
unsigned char b;
int c = 0;
if (!isatty (STDIN_FILENO))
return EOF;
if (tcgetattr (STDIN_FILENO, &save_termios) < 0)
return EOF;
ios = save_termios;
ios.c_lflag &= ~(ICANON | ECHO | ISIG);
ios.c_cc[VMIN] = 1; /* read() will return with one char */
ios.c_cc[VTIME] = 0; /* read() blocks forever */
if (tcsetattr (STDIN_FILENO, TCSANOW, &ios) < 0)
return EOF;
if (read (STDIN_FILENO, &b, 1) == 1)
c = (int)(0xff & b);
else
c = EOF;
tcsetattr (STDIN_FILENO, TCSANOW, &save_termios);
return c;
}
int
kbhit (void)
{
struct termios save_termios;
struct termios ios;
fd_set inp;
struct timeval timeout = {0, 0};
int result;
if (!isatty (STDIN_FILENO))
return 0;
if (tcgetattr (STDIN_FILENO, &save_termios) < 0)
return 0;
ios = save_termios;
ios.c_lflag &= ~(ICANON | ECHO | ISIG);
ios.c_cc[VMIN] = 1; /* read() will return with one char */
ios.c_cc[VTIME] = 0; /* read() blocks forever */
if (tcsetattr (STDIN_FILENO, TCSANOW, &ios) < 0)
return 0;
/* set up select() args */
FD_ZERO(&inp);
FD_SET(STDIN_FILENO, &inp);
result = select (STDIN_FILENO+1, &inp, NULL, NULL, &timeout) == 1;
tcsetattr (STDIN_FILENO, TCSANOW, &save_termios);
return result;
}
#if defined TEST_GETCH
int
main ()
{
int i;
char c[4];
printf("Enter %d keys to continue: ", sizeof c - 1);
fflush (stdout);
memset(c, 0, sizeof c);
for (i=0; i<sizeof c - 1; i++)
c[i] = getch ();
printf("Your input: [%s]\n", c);
printf("Now hit any key to abort: ");
while (!kbhit())
printf(".");
return 0;
}
#endif

@ -0,0 +1,15 @@
/* Extremely inefficient but portable POSIX getch(), see getch.c */
#ifndef GETCH_H
#define GETCH_H
#if defined __cplusplus
extern "C" {
#endif
int getch(void);
int kbhit(void);
#if defined __cplusplus
}
#endif
#endif /* GETCH_H */

@ -0,0 +1,49 @@
/*
* Things needed to compile under linux.
*
* Should be reworked totally to use GNU's 'configure'
*/
#ifndef SCLINUX_H
#define SCLINUX_H
/* getchar() is not a 'cool' replacement for MSDOS getch: Linux/unix depends on the features activated or not about the
* controlling terminal's tty. This means that ioctl(2) calls must be performed, for instance to have the controlling
* terminal tty's in 'raw' mode, if we want to be able to fetch a single character. This also means that everything must
* be put back correctly when the function ends. See GETCH.C for an implementation.
*
* For interactive use of PawnRun/PawnDbg if would be much better to use GNU's readline package: the user would be able to
* have a complete emacs/vi like line editing system.
*/
#if !defined getch && !defined kbhit
#include "getch.h"
#endif
#define stricmp(a,b) strcasecmp(a,b)
#define strnicmp(a,b,c) strncasecmp(a,b,c)
/*
* WinWorld wants '\'. Unices do not.
*/
#define DIRECTORY_SEP_CHAR '/'
#define DIRECTORY_SEP_STR "/"
/*
* SC assumes that a computer is Little Endian unless told otherwise. It uses
* (and defines) the macros BYTE_ORDER and BIG_ENDIAN.
* For Linux, we must overrule these settings with those defined in glibc.
*/
#if !defined __BYTE_ORDER
# include <stdlib.h>
#endif
#if defined __OpenBSD__ || defined __FreeBSD__ || defined __APPLE__
# define __BYTE_ORDER BYTE_ORDER
# define __LITTLE_ENDIAN LITTLE_ENDIAN
# define __BIG_ENDIAN BIG_ENDIAN
#endif
#if !defined __BYTE_ORDER
# error "Can't figure computer byte order (__BYTE_ORDER macro not found)"
#endif
#endif /* SCLINUX_H */

@ -0,0 +1,31 @@
/* Glue functions for the minIni library, based on the C/C++ stdio library
*
* Or better said: this file contains macros that maps the function interface
* used by minIni to the standard C/C++ file I/O functions.
*
* By CompuPhase, 2008-2014
* This "glue file" is in the public domain. It is distributed without
* warranties or conditions of any kind, either express or implied.
*/
/* map required file I/O types and functions to the standard C library */
#include <stdio.h>
#define INI_FILETYPE FILE*
#define ini_openread(filename,file) ((*(file) = fopen((filename),"rb")) != NULL)
#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"wb")) != NULL)
#define ini_openrewrite(filename,file) ((*(file) = fopen((filename),"r+b")) != NULL)
#define ini_close(file) (fclose(*(file)) == 0)
#define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL)
#define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0)
#define ini_rename(source,dest) (rename((source), (dest)) == 0)
#define ini_remove(filename) (remove(filename) == 0)
#define INI_FILEPOS long int
#define ini_tell(file,pos) (*(pos) = ftell(*(file)))
#define ini_seek(file,pos) (fseek(*(file), *(pos), SEEK_SET) == 0)
/* for floating-point support, define additional types and functions */
#define INI_REAL float
#define ini_ftoa(string,value) sprintf((string),"%f",(value))
#define ini_atof(string) (INI_REAL)strtod((string),NULL)

@ -0,0 +1,877 @@
/* minIni - Multi-Platform INI file parser, suitable for embedded systems
*
* These routines are in part based on the article "Multiplatform .INI Files"
* by Joseph J. Graf in the March 1994 issue of Dr. Dobb's Journal.
*
* Copyright (c) CompuPhase, 2008-2015
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Version: $Id: minIni.c 5181 2015-01-21 09:44:28Z thiadmer $
*/
#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY
# if !defined UNICODE /* for Windows */
# define UNICODE
# endif
# if !defined _UNICODE /* for C library */
# define _UNICODE
# endif
#endif
#define MININI_IMPLEMENTATION
#include "minIni.h"
#if defined NDEBUG
#define assert(e)
#else
#include <assert.h>
#endif
#if !defined __T || defined INI_ANSIONLY
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define TCHAR char
#define __T(s) s
#define _tcscat strcat
#define _tcschr strchr
#define _tcscmp strcmp
#define _tcscpy strcpy
#define _tcsicmp stricmp
#define _tcslen strlen
#define _tcsncmp strncmp
#define _tcsnicmp strnicmp
#define _tcsrchr strrchr
#define _tcstol strtol
#define _tcstod strtod
#define _totupper toupper
#define _stprintf sprintf
#define _tfgets fgets
#define _tfputs fputs
#define _tfopen fopen
#define _tremove remove
#define _trename rename
#endif
#if defined __linux || defined __linux__
#define __LINUX__
#elif defined FREEBSD && !defined __FreeBSD__
#define __FreeBSD__
#elif defined(_MSC_VER)
#pragma warning(disable: 4996) /* for Microsoft Visual C/C++ */
#endif
#if !defined strnicmp && !defined PORTABLE_STRNICMP
#if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
#define strnicmp strncasecmp
#endif
#endif
#if !defined _totupper
#define _totupper toupper
#endif
#if !defined INI_LINETERM
#if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
#define INI_LINETERM __T("\n")
#else
#define INI_LINETERM __T("\r\n")
#endif
#endif
#if !defined INI_FILETYPE
#error Missing definition for INI_FILETYPE.
#endif
#if !defined sizearray
#define sizearray(a) (sizeof(a) / sizeof((a)[0]))
#endif
enum quote_option {
QUOTE_NONE,
QUOTE_ENQUOTE,
QUOTE_DEQUOTE,
};
#if defined PORTABLE_STRNICMP
int strnicmp(const TCHAR *s1, const TCHAR *s2, size_t n)
{
register int c1, c2;
while (n-- != 0 && (*s1 || *s2)) {
c1 = *s1++;
if ('a' <= c1 && c1 <= 'z')
c1 += ('A' - 'a');
c2 = *s2++;
if ('a' <= c2 && c2 <= 'z')
c2 += ('A' - 'a');
if (c1 != c2)
return c1 - c2;
} /* while */
return 0;
}
#endif /* PORTABLE_STRNICMP */
static TCHAR *skipleading(const TCHAR *str)
{
assert(str != NULL);
while ('\0' < *str && *str <= ' ')
str++;
return (TCHAR *)str;
}
static TCHAR *skiptrailing(const TCHAR *str, const TCHAR *base)
{
assert(str != NULL);
assert(base != NULL);
while (str > base && '\0' < *(str-1) && *(str-1) <= ' ')
str--;
return (TCHAR *)str;
}
static TCHAR *striptrailing(TCHAR *str)
{
TCHAR *ptr = skiptrailing(_tcschr(str, '\0'), str);
assert(ptr != NULL);
*ptr = '\0';
return str;
}
static TCHAR *save_strncpy(TCHAR *dest, const TCHAR *source, size_t maxlen, enum quote_option option)
{
size_t d, s;
assert(maxlen>0);
assert(dest <= source || dest >= source + maxlen);
if (option == QUOTE_ENQUOTE && maxlen < 3)
option = QUOTE_NONE; /* cannot store two quotes and a terminating zero in less than 3 characters */
switch (option) {
case QUOTE_NONE:
for (d = 0; d < maxlen - 1 && source[d] != '\0'; d++)
dest[d] = source[d];
assert(d < maxlen);
dest[d] = '\0';
break;
case QUOTE_ENQUOTE:
d = 0;
dest[d++] = '"';
for (s = 0; source[s] != '\0' && d < maxlen - 2; s++, d++) {
if (source[s] == '"') {
if (d >= maxlen - 3)
break; /* no space to store the escape character plus the one that follows it */
dest[d++] = '\\';
} /* if */
dest[d] = source[s];
} /* for */
dest[d++] = '"';
dest[d] = '\0';
break;
case QUOTE_DEQUOTE:
for (d = s = 0; source[s] != '\0' && d < maxlen - 1; s++, d++) {
if ((source[s] == '"' || source[s] == '\\') && source[s + 1] == '"')
s++;
dest[d] = source[s];
} /* for */
dest[d] = '\0';
break;
default:
assert(0);
} /* switch */
return dest;
}
static TCHAR *cleanstring(TCHAR *string, enum quote_option *quotes)
{
int isstring;
TCHAR *ep;
assert(string != NULL);
assert(quotes != NULL);
/* Remove a trailing comment */
isstring = 0;
for (ep = string; *ep != '\0' && ((*ep != ';' && *ep != '#') || isstring); ep++) {
if (*ep == '"') {
if (*(ep + 1) == '"')
ep++; /* skip "" (both quotes) */
else
isstring = !isstring; /* single quote, toggle isstring */
} else if (*ep == '\\' && *(ep + 1) == '"') {
ep++; /* skip \" (both quotes */
} /* if */
} /* for */
assert(ep != NULL && (*ep == '\0' || *ep == ';' || *ep == '#'));
*ep = '\0'; /* terminate at a comment */
striptrailing(string);
/* Remove double quotes surrounding a value */
*quotes = QUOTE_NONE;
if (*string == '"' && (ep = _tcschr(string, '\0')) != NULL && *(ep - 1) == '"') {
string++;
*--ep = '\0';
*quotes = QUOTE_DEQUOTE; /* this is a string, so remove escaped characters */
} /* if */
return string;
}
static int getkeystring(INI_FILETYPE *fp, const TCHAR *Section, const TCHAR *Key,
int idxSection, int idxKey, TCHAR *Buffer, int BufferSize,
INI_FILEPOS *mark)
{
TCHAR *sp, *ep;
int len, idx;
enum quote_option quotes;
TCHAR LocalBuffer[INI_BUFFERSIZE];
assert(fp != NULL);
/* Move through file 1 line at a time until a section is matched or EOF. If
* parameter Section is NULL, only look at keys above the first section. If
* idxSection is postive, copy the relevant section name.
*/
len = (Section != NULL) ? (int)_tcslen(Section) : 0;
if (len > 0 || idxSection >= 0) {
idx = -1;
do {
if (!ini_read(LocalBuffer, INI_BUFFERSIZE, fp))
return 0;
sp = skipleading(LocalBuffer);
ep = _tcschr(sp, ']');
} while (*sp != '[' || ep == NULL || (((int)(ep-sp-1) != len || _tcsnicmp(sp+1,Section,len) != 0) && ++idx != idxSection));
if (idxSection >= 0) {
if (idx == idxSection) {
assert(ep != NULL);
assert(*ep == ']');
*ep = '\0';
save_strncpy(Buffer, sp + 1, BufferSize, QUOTE_NONE);
return 1;
} /* if */
return 0; /* no more section found */
} /* if */
} /* if */
/* Now that the section has been found, find the entry.
* Stop searching upon leaving the section's area.
*/
assert(Key != NULL || idxKey >= 0);
len = (Key != NULL) ? (int)_tcslen(Key) : 0;
idx = -1;
do {
if (mark != NULL)
ini_tell(fp, mark); /* optionally keep the mark to the start of the line */
if (!ini_read(LocalBuffer,INI_BUFFERSIZE,fp) || *(sp = skipleading(LocalBuffer)) == '[')
return 0;
sp = skipleading(LocalBuffer);
ep = _tcschr(sp, '='); /* Parse out the equal sign */
if (ep == NULL)
ep = _tcschr(sp, ':');
} while (*sp == ';' || *sp == '#' || ep == NULL
|| ((len == 0 || (int)(skiptrailing(ep,sp)-sp) != len || _tcsnicmp(sp,Key,len) != 0) && ++idx != idxKey));
if (idxKey >= 0) {
if (idx == idxKey) {
assert(ep != NULL);
assert(*ep == '=' || *ep == ':');
*ep = '\0';
striptrailing(sp);
save_strncpy(Buffer, sp, BufferSize, QUOTE_NONE);
return 1;
} /* if */
return 0; /* no more key found (in this section) */
} /* if */
/* Copy up to BufferSize chars to buffer */
assert(ep != NULL);
assert(*ep == '=' || *ep == ':');
sp = skipleading(ep + 1);
sp = cleanstring(sp, &quotes); /* Remove a trailing comment */
save_strncpy(Buffer, sp, BufferSize, quotes);
return 1;
}
/** ini_gets()
* \param Section the name of the section to search for
* \param Key the name of the entry to find the value of
* \param DefValue default string in the event of a failed read
* \param Buffer a pointer to the buffer to copy into
* \param BufferSize the maximum number of characters to copy
* \param Filename the name and full path of the .ini file to read from
*
* \return the number of characters copied into the supplied buffer
*/
int ini_gets(const TCHAR *Section, const TCHAR *Key, const TCHAR *DefValue,
TCHAR *Buffer, int BufferSize, const TCHAR *Filename)
{
INI_FILETYPE fp;
int ok = 0;
if (Buffer == NULL || BufferSize <= 0 || Key == NULL)
return 0;
if (ini_openread(Filename, &fp)) {
ok = getkeystring(&fp, Section, Key, -1, -1, Buffer, BufferSize, NULL);
(void)ini_close(&fp);
} /* if */
if (!ok)
save_strncpy(Buffer, (DefValue != NULL) ? DefValue : __T(""), BufferSize, QUOTE_NONE);
return (int)_tcslen(Buffer);
}
/** ini_getl()
* \param Section the name of the section to search for
* \param Key the name of the entry to find the value of
* \param DefValue the default value in the event of a failed read
* \param Filename the name of the .ini file to read from
*
* \return the value located at Key
*/
long ini_getl(const TCHAR *Section, const TCHAR *Key, long DefValue, const TCHAR *Filename)
{
TCHAR LocalBuffer[64];
int len = ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename);
return (len == 0) ? DefValue
: ((len >= 2 && _totupper((int)LocalBuffer[1]) == 'X') ? _tcstol(LocalBuffer, NULL, 16)
: _tcstol(LocalBuffer, NULL, 10));
}
#if defined INI_REAL
/** ini_getf()
* \param Section the name of the section to search for
* \param Key the name of the entry to find the value of
* \param DefValue the default value in the event of a failed read
* \param Filename the name of the .ini file to read from
*
* \return the value located at Key
*/
INI_REAL ini_getf(const TCHAR *Section, const TCHAR *Key, INI_REAL DefValue, const TCHAR *Filename)
{
TCHAR LocalBuffer[64];
int len = ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename);
return (len == 0) ? DefValue : ini_atof(LocalBuffer);
}
#endif
/** ini_getbool()
* \param Section the name of the section to search for
* \param Key the name of the entry to find the value of
* \param DefValue default value in the event of a failed read; it should
* zero (0) or one (1).
* \param Buffer a pointer to the buffer to copy into
* \param BufferSize the maximum number of characters to copy
* \param Filename the name and full path of the .ini file to read from
*
* A true boolean is found if one of the following is matched:
* - A string starting with 'y' or 'Y'
* - A string starting with 't' or 'T'
* - A string starting with '1'
*
* A false boolean is found if one of the following is matched:
* - A string starting with 'n' or 'N'
* - A string starting with 'f' or 'F'
* - A string starting with '0'
*
* \return the true/false flag as interpreted at Key
*/
int ini_getbool(const TCHAR *Section, const TCHAR *Key, int DefValue, const TCHAR *Filename)
{
TCHAR LocalBuffer[2] = __T("");
int ret;
ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename);
LocalBuffer[0] = (TCHAR)_totupper((int)LocalBuffer[0]);
if (LocalBuffer[0] == 'Y' || LocalBuffer[0] == '1' || LocalBuffer[0] == 'T')
ret = 1;
else if (LocalBuffer[0] == 'N' || LocalBuffer[0] == '0' || LocalBuffer[0] == 'F')
ret = 0;
else
ret = DefValue;
return(ret);
}
/** ini_getsection()
* \param idx the zero-based sequence number of the section to return
* \param Buffer a pointer to the buffer to copy into
* \param BufferSize the maximum number of characters to copy
* \param Filename the name and full path of the .ini file to read from
*
* \return the number of characters copied into the supplied buffer
*/
int ini_getsection(int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filename)
{
INI_FILETYPE fp;
int ok = 0;
if (Buffer == NULL || BufferSize <= 0 || idx < 0)
return 0;
if (ini_openread(Filename, &fp)) {
ok = getkeystring(&fp, NULL, NULL, idx, -1, Buffer, BufferSize, NULL);
(void)ini_close(&fp);
} /* if */
if (!ok)
*Buffer = '\0';
return (int)_tcslen(Buffer);
}
/** ini_getkey()
* \param Section the name of the section to browse through, or NULL to
* browse through the keys outside any section
* \param idx the zero-based sequence number of the key to return
* \param Buffer a pointer to the buffer to copy into
* \param BufferSize the maximum number of characters to copy
* \param Filename the name and full path of the .ini file to read from
*
* \return the number of characters copied into the supplied buffer
*/
int ini_getkey(const TCHAR *Section, int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filename)
{
INI_FILETYPE fp;
int ok = 0;
if (Buffer == NULL || BufferSize <= 0 || idx < 0)
return 0;
if (ini_openread(Filename, &fp)) {
ok = getkeystring(&fp, Section, NULL, -1, idx, Buffer, BufferSize, NULL);
(void)ini_close(&fp);
} /* if */
if (!ok)
*Buffer = '\0';
return (int)_tcslen(Buffer);
}
#if !defined INI_NOBROWSE
/** ini_browse()
* \param Callback a pointer to a function that will be called for every
* setting in the INI file.
* \param UserData arbitrary data, which the function passes on the the
* \c Callback function
* \param Filename the name and full path of the .ini file to read from
*
* \return 1 on success, 0 on failure (INI file not found)
*
* \note The \c Callback function must return 1 to continue
* browsing through the INI file, or 0 to stop. Even when the
* callback stops the browsing, this function will return 1
* (for success).
*/
int ini_browse(INI_CALLBACK Callback, const void *UserData, const TCHAR *Filename)
{
TCHAR LocalBuffer[INI_BUFFERSIZE];
int lenSec, lenKey;
enum quote_option quotes;
INI_FILETYPE fp;
if (Callback == NULL)
return 0;
if (!ini_openread(Filename, &fp))
return 0;
LocalBuffer[0] = '\0'; /* copy an empty section in the buffer */
lenSec = (int)_tcslen(LocalBuffer) + 1;
for ( ;; ) {
TCHAR *sp, *ep;
if (!ini_read(LocalBuffer + lenSec, INI_BUFFERSIZE - lenSec, &fp))
break;
sp = skipleading(LocalBuffer + lenSec);
/* ignore empty strings and comments */
if (*sp == '\0' || *sp == ';' || *sp == '#')
continue;
/* see whether we reached a new section */
ep = _tcschr(sp, ']');
if (*sp == '[' && ep != NULL) {
*ep = '\0';
save_strncpy(LocalBuffer, sp + 1, INI_BUFFERSIZE, QUOTE_NONE);
lenSec = (int)_tcslen(LocalBuffer) + 1;
continue;
} /* if */
/* not a new section, test for a key/value pair */
ep = _tcschr(sp, '='); /* test for the equal sign or colon */
if (ep == NULL)
ep = _tcschr(sp, ':');
if (ep == NULL)
continue; /* invalid line, ignore */
*ep++ = '\0'; /* split the key from the value */
striptrailing(sp);
save_strncpy(LocalBuffer + lenSec, sp, INI_BUFFERSIZE - lenSec, QUOTE_NONE);
lenKey = (int)_tcslen(LocalBuffer + lenSec) + 1;
/* clean up the value */
sp = skipleading(ep);
sp = cleanstring(sp, &quotes); /* Remove a trailing comment */
save_strncpy(LocalBuffer + lenSec + lenKey, sp, INI_BUFFERSIZE - lenSec - lenKey, quotes);
/* call the callback */
if (!Callback(LocalBuffer, LocalBuffer + lenSec, LocalBuffer + lenSec + lenKey, UserData))
break;
} /* for */
(void)ini_close(&fp);
return 1;
}
#endif /* INI_NOBROWSE */
#if ! defined INI_READONLY
static void ini_tempname(TCHAR *dest, const TCHAR *source, int maxlength)
{
TCHAR *p;
save_strncpy(dest, source, maxlength, QUOTE_NONE);
p = _tcsrchr(dest, '\0');
assert(p != NULL);
*(p - 1) = '~';
}
static enum quote_option check_enquote(const TCHAR *Value)
{
const TCHAR *p;
/* run through the value, if it has trailing spaces, or '"', ';' or '#'
* characters, enquote it
*/
assert(Value != NULL);
for (p = Value; *p != '\0' && *p != '"' && *p != ';' && *p != '#'; p++)
/* nothing */;
return (*p != '\0' || (p > Value && *(p - 1) == ' ')) ? QUOTE_ENQUOTE : QUOTE_NONE;
}
static void writesection(TCHAR *LocalBuffer, const TCHAR *Section, INI_FILETYPE *fp)
{
if (Section != NULL && _tcslen(Section) > 0) {
TCHAR *p;
LocalBuffer[0] = '[';
save_strncpy(LocalBuffer + 1, Section, INI_BUFFERSIZE - 4, QUOTE_NONE); /* -1 for '[', -1 for ']', -2 for '\r\n' */
p = _tcsrchr(LocalBuffer, '\0');
assert(p != NULL);
*p++ = ']';
_tcscpy(p, INI_LINETERM); /* copy line terminator (typically "\n") */
if (fp != NULL)
(void)ini_write(LocalBuffer, fp);
} /* if */
}
static void writekey(TCHAR *LocalBuffer, const TCHAR *Key, const TCHAR *Value, INI_FILETYPE *fp)
{
TCHAR *p;
enum quote_option option = check_enquote(Value);
save_strncpy(LocalBuffer, Key, INI_BUFFERSIZE - 3, QUOTE_NONE); /* -1 for '=', -2 for '\r\n' */
p = _tcsrchr(LocalBuffer, '\0');
assert(p != NULL);
*p++ = '=';
save_strncpy(p, Value, INI_BUFFERSIZE - (p - LocalBuffer) - 2, option); /* -2 for '\r\n' */
p = _tcsrchr(LocalBuffer, '\0');
assert(p != NULL);
_tcscpy(p, INI_LINETERM); /* copy line terminator (typically "\n") */
if (fp != NULL)
(void)ini_write(LocalBuffer, fp);
}
static int cache_accum(const TCHAR *string, int *size, int max)
{
int len = (int)_tcslen(string);
if (*size + len >= max)
return 0;
*size += len;
return 1;
}
static int cache_flush(TCHAR *buffer, int *size,
INI_FILETYPE *rfp, INI_FILETYPE *wfp, INI_FILEPOS *mark)
{
int terminator_len = (int)_tcslen(INI_LINETERM);
int pos = 0;
(void)ini_seek(rfp, mark);
assert(buffer != NULL);
buffer[0] = '\0';
assert(size != NULL);
assert(*size <= INI_BUFFERSIZE);
while (pos < *size) {
(void)ini_read(buffer + pos, INI_BUFFERSIZE - pos, rfp);
while (pos < *size && buffer[pos] != '\0')
pos++; /* cannot use _tcslen() because buffer may not be zero-terminated */
} /* while */
if (buffer[0] != '\0') {
assert(pos > 0 && pos <= INI_BUFFERSIZE);
if (pos == INI_BUFFERSIZE)
pos--;
buffer[pos] = '\0'; /* force zero-termination (may be left unterminated in the above while loop) */
(void)ini_write(buffer, wfp);
}
ini_tell(rfp, mark); /* update mark */
*size = 0;
/* return whether the buffer ended with a line termination */
return (pos > terminator_len) && (_tcscmp(buffer + pos - terminator_len, INI_LINETERM) == 0);
}
static int close_rename(INI_FILETYPE *rfp, INI_FILETYPE *wfp, const TCHAR *filename, TCHAR *buffer)
{
(void)ini_close(rfp);
(void)ini_close(wfp);
(void)ini_remove(filename);
(void)ini_tempname(buffer, filename, INI_BUFFERSIZE);
(void)ini_rename(buffer, filename);
return 1;
}
/** ini_puts()
* \param Section the name of the section to write the string in
* \param Key the name of the entry to write, or NULL to erase all keys in the section
* \param Value a pointer to the buffer the string, or NULL to erase the key
* \param Filename the name and full path of the .ini file to write to
*
* \return 1 if successful, otherwise 0
*/
int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const TCHAR *Filename)
{
INI_FILETYPE rfp;
INI_FILETYPE wfp;
INI_FILEPOS mark;
INI_FILEPOS head, tail;
TCHAR *sp, *ep;
TCHAR LocalBuffer[INI_BUFFERSIZE];
int len, match, flag, cachelen;
assert(Filename != NULL);
if (!ini_openread(Filename, &rfp)) {
/* If the .ini file doesn't exist, make a new file */
if (Key != NULL && Value != NULL) {
if (!ini_openwrite(Filename, &wfp))
return 0;
writesection(LocalBuffer, Section, &wfp);
writekey(LocalBuffer, Key, Value, &wfp);
(void)ini_close(&wfp);
} /* if */
return 1;
} /* if */
/* If parameters Key and Value are valid (so this is not an "erase" request)
* and the setting already exists, there are two short-cuts to avoid rewriting
* the INI file.
*/
if (Key != NULL && Value != NULL) {
ini_tell(&rfp, &mark);
match = getkeystring(&rfp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer), &head);
if (match) {
/* if the current setting is identical to the one to write, there is
* nothing to do.
*/
if (_tcscmp(LocalBuffer,Value) == 0) {
(void)ini_close(&rfp);
return 1;
} /* if */
/* if the new setting has the same length as the current setting, and the
* glue file permits file read/write access, we can modify in place.
*/
#if defined ini_openrewrite
/* we already have the start of the (raw) line, get the end too */
ini_tell(&rfp, &tail);
/* create new buffer (without writing it to file) */
writekey(LocalBuffer, Key, Value, NULL);
if (_tcslen(LocalBuffer) == (size_t)(tail - head)) {
/* length matches, close the file & re-open for read/write, then
* write at the correct position
*/
(void)ini_close(&rfp);
if (!ini_openrewrite(Filename, &wfp))
return 0;
(void)ini_seek(&wfp, &head);
(void)ini_write(LocalBuffer, &wfp);
(void)ini_close(&wfp);
return 1;
} /* if */
#endif
} /* if */
/* key not found, or different value & length -> proceed (but rewind the
* input file first)
*/
(void)ini_seek(&rfp, &mark);
} /* if */
/* Get a temporary file name to copy to. Use the existing name, but with
* the last character set to a '~'.
*/
ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE);
if (!ini_openwrite(LocalBuffer, &wfp)) {
(void)ini_close(&rfp);
return 0;
} /* if */
ini_tell(&rfp, &mark);
cachelen = 0;
/* Move through the file one line at a time until a section is
* matched or until EOF. Copy to temp file as it is read.
*/
len = (Section != NULL) ? (int)_tcslen(Section) : 0;
if (len > 0) {
do {
if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) {
/* Failed to find section, so add one to the end */
flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
if (Key!=NULL && Value!=NULL) {
if (!flag)
(void)ini_write(INI_LINETERM, &wfp); /* force a new line behind the last line of the INI file */
writesection(LocalBuffer, Section, &wfp);
writekey(LocalBuffer, Key, Value, &wfp);
} /* if */
return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */
} /* if */
/* Copy the line from source to dest, but not if this is the section that
* we are looking for and this section must be removed
*/
sp = skipleading(LocalBuffer);
ep = _tcschr(sp, ']');
match = (*sp == '[' && ep != NULL && (int)(ep-sp-1) == len && _tcsnicmp(sp + 1,Section,len) == 0);
if (!match || Key != NULL) {
if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) {
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);
} /* if */
} /* if */
} while (!match);
} /* if */
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
/* when deleting a section, the section head that was just found has not been
* copied to the output file, but because this line was not "accumulated" in
* the cache, the position in the input file was reset to the point just
* before the section; this must now be skipped (again)
*/
if (Key == NULL) {
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
ini_tell(&rfp, &mark);
} /* if */
/* Now that the section has been found, find the entry. Stop searching
* upon leaving the section's area. Copy the file as it is read
* and create an entry if one is not found.
*/
len = (Key != NULL) ? (int)_tcslen(Key) : 0;
for( ;; ) {
if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) {
/* EOF without an entry so make one */
flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
if (Key!=NULL && Value!=NULL) {
if (!flag)
(void)ini_write(INI_LINETERM, &wfp); /* force a new line behind the last line of the INI file */
writekey(LocalBuffer, Key, Value, &wfp);
} /* if */
return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */
} /* if */
sp = skipleading(LocalBuffer);
ep = _tcschr(sp, '='); /* Parse out the equal sign */
if (ep == NULL)
ep = _tcschr(sp, ':');
match = (ep != NULL && len > 0 && (int)(skiptrailing(ep,sp)-sp) == len && _tcsnicmp(sp,Key,len) == 0);
if ((Key != NULL && match) || *sp == '[')
break; /* found the key, or found a new section */
/* copy other keys in the section */
if (Key == NULL) {
ini_tell(&rfp, &mark); /* we are deleting the entire section, so update the read position */
} else {
if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) {
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);
} /* if */
} /* if */
} /* for */
/* the key was found, or we just dropped on the next section (meaning that it
* wasn't found); in both cases we need to write the key, but in the latter
* case, we also need to write the line starting the new section after writing
* the key
*/
flag = (*sp == '[');
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
if (Key != NULL && Value != NULL)
writekey(LocalBuffer, Key, Value, &wfp);
/* cache_flush() reset the "read pointer" to the start of the line with the
* previous key or the new section; read it again (because writekey() destroyed
* the buffer)
*/
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
if (flag) {
/* the new section heading needs to be copied to the output file */
cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);
} else {
/* forget the old key line */
ini_tell(&rfp, &mark);
} /* if */
/* Copy the rest of the INI file */
while (ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) {
if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) {
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);
} /* if */
} /* while */
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */
}
/* Ansi C "itoa" based on Kernighan & Ritchie's "Ansi C" book. */
#define ABS(v) ((v) < 0 ? -(v) : (v))
static void strreverse(TCHAR *str)
{
int i, j;
for (i = 0, j = (int)_tcslen(str) - 1; i < j; i++, j--) {
TCHAR t = str[i];
str[i] = str[j];
str[j] = t;
} /* for */
}
static void long2str(long value, TCHAR *str)
{
int i = 0;
long sign = value;
int n;
/* generate digits in reverse order */
do {
n = (int)(value % 10); /* get next lowest digit */
str[i++] = (TCHAR)(ABS(n) + '0'); /* handle case of negative digit */
} while (value /= 10); /* delete the lowest digit */
if (sign < 0)
str[i++] = '-';
str[i] = '\0';
strreverse(str);
}
/** ini_putl()
* \param Section the name of the section to write the value in
* \param Key the name of the entry to write
* \param Value the value to write
* \param Filename the name and full path of the .ini file to write to
*
* \return 1 if successful, otherwise 0
*/
int ini_putl(const TCHAR *Section, const TCHAR *Key, long Value, const TCHAR *Filename)
{
TCHAR LocalBuffer[32];
long2str(Value, LocalBuffer);
return ini_puts(Section, Key, LocalBuffer, Filename);
}
#if defined INI_REAL
/** ini_putf()
* \param Section the name of the section to write the value in
* \param Key the name of the entry to write
* \param Value the value to write
* \param Filename the name and full path of the .ini file to write to
*
* \return 1 if successful, otherwise 0
*/
int ini_putf(const TCHAR *Section, const TCHAR *Key, INI_REAL Value, const TCHAR *Filename)
{
TCHAR LocalBuffer[64];
ini_ftoa(LocalBuffer, Value);
return ini_puts(Section, Key, LocalBuffer, Filename);
}
#endif /* INI_REAL */
#endif /* !INI_READONLY */

@ -0,0 +1,152 @@
/* minIni - Multi-Platform INI file parser, suitable for embedded systems
*
* Copyright (c) CompuPhase, 2008-2012
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Version: $Id: minIni.h 5181 2015-01-21 09:44:28Z thiadmer $
*/
#ifndef MININI_H
#define MININI_H
#include "minGlue.h"
#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY
#include <tchar.h>
#define mTCHAR TCHAR
#else
/* force TCHAR to be "char", but only for minIni */
#define mTCHAR char
#endif
#if !defined INI_BUFFERSIZE
#define INI_BUFFERSIZE 512
#endif
#if defined __cplusplus
extern "C" {
#endif
int ini_getbool(const mTCHAR *Section, const mTCHAR *Key, int DefValue, const mTCHAR *Filename);
long ini_getl(const mTCHAR *Section, const mTCHAR *Key, long DefValue, const mTCHAR *Filename);
int ini_gets(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *DefValue, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
int ini_getsection(int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
int ini_getkey(const mTCHAR *Section, int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
#if defined INI_REAL
INI_REAL ini_getf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL DefValue, const mTCHAR *Filename);
#endif
#if !defined INI_READONLY
int ini_putl(const mTCHAR *Section, const mTCHAR *Key, long Value, const mTCHAR *Filename);
int ini_puts(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const mTCHAR *Filename);
#if defined INI_REAL
int ini_putf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL Value, const mTCHAR *Filename);
#endif
#endif /* INI_READONLY */
#if !defined INI_NOBROWSE
typedef int (*INI_CALLBACK)(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const void *UserData);
int ini_browse(INI_CALLBACK Callback, const void *UserData, const mTCHAR *Filename);
#endif /* INI_NOBROWSE */
#if defined __cplusplus
}
#endif
#if defined __cplusplus
#if defined __WXWINDOWS__
#include "wxMinIni.h"
#else
#include <string>
/* The C++ class in minIni.h was contributed by Steven Van Ingelgem. */
class minIni
{
public:
minIni(const std::string& filename) : iniFilename(filename)
{ }
bool getbool(const std::string& Section, const std::string& Key, bool DefValue=false) const
{ return ini_getbool(Section.c_str(), Key.c_str(), int(DefValue), iniFilename.c_str()) != 0; }
long getl(const std::string& Section, const std::string& Key, long DefValue=0) const
{ return ini_getl(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); }
int geti(const std::string& Section, const std::string& Key, int DefValue=0) const
{ return static_cast<int>(this->getl(Section, Key, long(DefValue))); }
std::string gets(const std::string& Section, const std::string& Key, const std::string& DefValue="") const
{
char buffer[INI_BUFFERSIZE];
ini_gets(Section.c_str(), Key.c_str(), DefValue.c_str(), buffer, INI_BUFFERSIZE, iniFilename.c_str());
return buffer;
}
std::string getsection(int idx) const
{
char buffer[INI_BUFFERSIZE];
ini_getsection(idx, buffer, INI_BUFFERSIZE, iniFilename.c_str());
return buffer;
}
std::string getkey(const std::string& Section, int idx) const
{
char buffer[INI_BUFFERSIZE];
ini_getkey(Section.c_str(), idx, buffer, INI_BUFFERSIZE, iniFilename.c_str());
return buffer;
}
#if defined INI_REAL
INI_REAL getf(const std::string& Section, const std::string& Key, INI_REAL DefValue=0) const
{ return ini_getf(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); }
#endif
#if ! defined INI_READONLY
bool put(const std::string& Section, const std::string& Key, long Value) const
{ return ini_putl(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }
bool put(const std::string& Section, const std::string& Key, int Value) const
{ return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; }
bool put(const std::string& Section, const std::string& Key, bool Value) const
{ return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; }
bool put(const std::string& Section, const std::string& Key, const std::string& Value) const
{ return ini_puts(Section.c_str(), Key.c_str(), Value.c_str(), iniFilename.c_str()) != 0; }
bool put(const std::string& Section, const std::string& Key, const char* Value) const
{ return ini_puts(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }
#if defined INI_REAL
bool put(const std::string& Section, const std::string& Key, INI_REAL Value) const
{ return ini_putf(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }
#endif
bool del(const std::string& Section, const std::string& Key) const
{ return ini_puts(Section.c_str(), Key.c_str(), 0, iniFilename.c_str()) != 0; }
bool del(const std::string& Section) const
{ return ini_puts(Section.c_str(), 0, 0, iniFilename.c_str()) != 0; }
#endif
private:
std::string iniFilename;
};
#endif /* __WXWINDOWS__ */
#endif /* __cplusplus */
#endif /* MININI_H */

@ -0,0 +1,159 @@
/*
* Platform
* __MSDOS__ set when compiling for DOS (not Windows)
* _Windows set when compiling for any version of Microsoft Windows
* __WIN32__ set when compiling for Windows95 or WindowsNT (32 bit mode)
* __32BIT__ set when compiling in 32-bit "flat" mode (DOS, Windows, ARM)
* __64BIT__ set when compiling in 64-bit mode
* __ECOS__ set if Pawn was included with the eCos with configtool
* __LINUX__ set when compiling for Linux
*
* Copyright 1998-2011, ITB CompuPhase, The Netherlands.
* No usage restrictions, no warranties.
*/
#ifndef _OSDEFS_H
#define _OSDEFS_H
/* Every compiler uses different "default" macros to indicate the mode
* it is in. Throughout the source, we use the Borland C++ macros, so
* the macros of Watcom C/C++ and Microsoft Visual C/C++ are mapped to
* those of Borland C++.
*/
#if defined(__WATCOMC__)
#if defined(__WINDOWS__) || defined(__NT__)
#define _Windows 1
#endif
#if defined(__386__) || defined(__NT__)
#define __32BIT__ 1
#endif
#if defined(_Windows) && defined(__32BIT__)
#define __WIN32__ 1
#endif
#elif defined(_MSC_VER)
#if defined(_WINDOWS) || defined(_WIN32)
#define _Windows 1
#endif
#if defined(_WIN32)
#define __WIN32__ 1
#define __32BIT__ 1
#endif
#elif defined __arm__
#define __32BIT__ 1
#elif defined __AVR__
#define __16BIT__ 1
#endif
#if !defined __16BIT__ && !defined __32BIT__ && !defined __64BIT__
#define __32BIT__ 1
#endif
#if (defined __linux || defined __linux__) && !defined __LINUX__
#define __LINUX__
#endif
/* To be able to eventually set __ECOS__, we have to find a symbol
* defined in a common place (so including the header file won't break
* anything for other platforms). <sys/types.h> includes
* <pkgconf/system.h> and in this later file we can find CYGPKG_PAWN
* if the Pawn package was included with configtool and so we know
* that we are compiling for eCos.
*/
#if defined CCSINFO
#include <sys/types.h>
#endif
#if defined CYGPKG_PAWN
#define __ECOS__ 1
#define HAVE_ALLOCA_H 0
#endif
#if defined __FreeBSD__
#include <sys/endian.h>
#elif defined __LINUX__
#include <endian.h>
#elif defined __ECOS__
#include <cyg/hal/hal_endian.h>
#define BIG_ENDIAN 4321
#define LITTLE_ENDIAN 1234
#if (CYG_BYTEORDER == CYG_LSBFIRST)
#define BYTE_ORDER LITTLE_ENDIAN
#else
#define BYTE_ORDER BIG_ENDIAN
#endif
/*
* eCos option management.
*/
#include <pkgconf/pawn.h>
#if CYGPKG_PAWN_AMX_ANSIONLY==1
#define AMX_ANSIONLY
#endif
#define PAWN_CELL_SIZE CYGPKG_PAWN_AMX_CELLSIZE
#if CYGPKG_PAWN_CORE_RANDOM==0
#define AMX_NORANDOM
#endif
#if CYGPKG_PAWN_CORE_PROPERTY==0
#define AMX_NOPROPLIST
#endif
#if CYGPKG_PAWN_AMX_CONS_FIXEDPOINT==1
#define FIXEDPOINT
#endif
#if CYGPKG_PAWN_AMX_CONS_FLOATPOINT==1
#define FLOATPOINT
#endif
#endif
/* Linux now has these */
#if !defined BIG_ENDIAN
#define BIG_ENDIAN 4321
#endif
#if !defined LITTLE_ENDIAN
#define LITTLE_ENDIAN 1234
#endif
/* educated guess, BYTE_ORDER is undefined, i386 is common => little endian */
#if !defined BYTE_ORDER
#if defined UCLINUX
#define BYTE_ORDER BIG_ENDIAN
#else
#define BYTE_ORDER LITTLE_ENDIAN
#endif
#endif
#if defined __MSDOS__ || defined __WIN32__ || defined _Windows
#define DIRSEP_CHAR '\\'
#elif defined macintosh /* only the original Macintosh uses ':', OSX uses the '/' */
#define DIRSEP_CHAR ':'
#else
#define DIRSEP_CHAR '/'
#endif
/* _MAX_PATH is sometimes called differently and it may be in limits.h or
* stdlib.h instead of stdio.h.
*/
#if !defined _MAX_PATH
/* not defined, perhaps stdio.h was not included */
#if !defined PATH_MAX
#include <stdio.h>
#endif
#if !defined _MAX_PATH && !defined PATH_MAX
/* no _MAX_PATH and no MAX_PATH, perhaps it is in limits.h */
#include <limits.h>
#endif
#if !defined _MAX_PATH && !defined PATH_MAX
/* no _MAX_PATH and no MAX_PATH, perhaps it is in stdlib.h */
#include <stdlib.h>
#endif
/* if _MAX_PATH is undefined, try common alternative names */
#if !defined _MAX_PATH
#if defined MAX_PATH
#define _MAX_PATH MAX_PATH
#elif defined _POSIX_PATH_MAX
#define _MAX_PATH _POSIX_PATH_MAX
#else
/* everything failed, actually we have a problem here... */
#define _MAX_PATH 1024
#endif
#endif
#endif
#endif /* _OSDEFS_H */

@ -0,0 +1,136 @@
#include <RakPeerInterface.h>
#include <BitStream.h>
#include "Player.hpp"
#include "Networking.hpp"
#include <RakPeer.h>
#include <MessageIdentifiers.h>
#include <components/openmw-mp/NetworkMessages.hpp>
#include <apps/openmw-mp/Script/Script.hpp>
#include <iostream>
#include <components/files/configurationmanager.hpp>
#include <components/settings/settings.hpp>
using namespace std;
using namespace mwmp;
void printVersion(string version, int protocol)
{
cout << "TES3:MP dedicated server " << version;
cout << " (";
#ifdef __WIN32__
cout << "Windows";
#elif __linux
cout << "Linux";
#elif __APPLE__
cout << "OS X";
#else
cout << "Unknown OS";
#endif
cout << " ";
#ifdef __x86_64__
cout << "64-bit";
#elif defined __i386__ || defined _M_I86
cout << "32-bit";
#else
cout << "Unknown architecture";
#endif
cout << ")" << endl;
cout << "Protocol version: " << protocol << endl;
cout << "------------------------------------------------------------" << endl;
}
std::string loadSettings (Settings::Manager & settings)
{
Files::ConfigurationManager mCfgMgr;
// Create the settings manager and load default settings file
const std::string localdefault = (mCfgMgr.getLocalPath() / "tes3mp-server-default.cfg").string();
const std::string globaldefault = (mCfgMgr.getGlobalPath() / "tes3mp-server-default.cfg").string();
// prefer local
if (boost::filesystem::exists(localdefault))
settings.loadDefault(localdefault);
else if (boost::filesystem::exists(globaldefault))
settings.loadDefault(globaldefault);
else
throw std::runtime_error ("No default settings file found! Make sure the file \"tes3mp-server-default.cfg\" was properly installed.");
// load user settings if they exist
const std::string settingspath = (mCfgMgr.getUserConfigPath() / "tes3mp-server.cfg").string();
if (boost::filesystem::exists(settingspath))
settings.loadUser(settingspath);
return settingspath;
}
const vector<string> split(const string &str, int delimiter)
{
string buffer;
vector<string> result;
for (auto symb:str)
if (symb != delimiter)
buffer += symb;
else if (!buffer.empty())
{
result.push_back(move(buffer));
buffer.clear();
}
if (!buffer.empty())
result.push_back(move(buffer));
return result;
}
int main(int argc, char *argv[])
{
Settings::Manager mgr;
loadSettings(mgr);
//string plugin_home = "/home/koncord/ClionProjects/tes3mp-server/files";
int players = mgr.getInt("players", "General");
int port = mgr.getInt("port", "General");
std::string plugin_home = mgr.getString("home", "Plugins");
string moddir = plugin_home + "/files";
vector<string> plugins (split(mgr.getString("plugins", "Plugins"), ','));
cout << plugins[0] << endl;
printVersion("0.0.1b", 1);
setenv("AMXFILE", moddir.c_str(), 1);
setenv("MOD_DIR", moddir.c_str(), 1); // hack for lua
setenv("LUA_PATH", (plugin_home + "/scripts/?.lua" + ";" + plugin_home + "/scripts/?.t").c_str(), 1);
for(auto plugin : plugins)
Script::LoadScript(plugin.c_str(), plugin_home.c_str());
RakNet::RakPeerInterface *peer = RakNet::RakPeerInterface::GetInstance();
const char passw[8] = "1234567";
peer->SetIncomingPassword(passw, sizeof(passw));
RakNet::SocketDescriptor sd((unsigned short)port, 0);
if (peer->Startup((unsigned)players, &sd, 1) != RakNet::RAKNET_STARTED)
return 0;
peer->SetMaximumIncomingConnections((unsigned short)(players / 2));
Networking networking(peer);
int code = networking.MainLoop();
RakNet::RakPeerInterface::DestroyInstance(peer);
if (code == 0)
printf("Quitting peacefully.\n");
return code;
}

@ -95,7 +95,7 @@ add_openmw_dir (mwbase
inputmanager windowmanager statemanager
)
add_openmw_dir (mwmp Networking Player)
add_openmw_dir (mwmp DedicatedPlayer LocalPlayer Networking Main GUIChat GUILogin)
# Main executable
@ -139,6 +139,7 @@ target_link_libraries(openmw
"osg-ffmpeg-videoplayer"
"oics"
components
${RakNet_LIBRARY}
)
if (ANDROID)

@ -55,7 +55,7 @@
#include "mwstate/statemanagerimp.hpp"
#include "mwmp/Networking.hpp"
#include "mwmp/Main.hpp"
namespace
{
@ -112,7 +112,7 @@ void OMW::Engine::frame(float frametime)
// update game state
mEnvironment.getStateManager()->update (frametime);
bool guiActive = mEnvironment.getWindowManager()->isGuiMode();
bool guiActive = /*mEnvironment.getWindowManager()->isGuiMode()*/ false;
osg::Timer_t beforeScriptTick = osg::Timer::instance()->tick();
if (mEnvironment.getStateManager()->getState()==
@ -153,9 +153,9 @@ void OMW::Engine::frame(float frametime)
if (mEnvironment.getStateManager()->getState()==
MWBase::StateManager::State_Running)
{
MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr();
/*MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr();
if(!guiActive && player.getClass().getCreatureStats(player).isDead())
mEnvironment.getStateManager()->endGame();
mEnvironment.getStateManager()->endGame();*/
}
// update world
@ -688,7 +688,7 @@ void OMW::Engine::go()
frameTimer.setStartTick();
dt = std::min(dt, 0.2);
bool guiActive = mEnvironment.getWindowManager()->isGuiMode();
bool guiActive = /*mEnvironment.getWindowManager()->isGuiMode()*/ false;
if (!guiActive)
simulationTime += dt;

@ -7,6 +7,9 @@
#include <components/esm/loadmgef.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/esm/npcstate.hpp>
#include <apps/openmw/mwmp/DedicatedPlayer.hpp>
#include <apps/openmw/mwmp/Networking.hpp>
#include <apps/openmw/mwmp/Main.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -460,6 +463,9 @@ namespace MWClass
void Npc::hit(const MWWorld::Ptr& ptr, float attackStrength, int type) const
{
if(mwmp::Main::get().getNetworking()->isDedicatedPlayer(ptr))
return;
MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &store = world->getStore().get<ESM::GameSetting>();
@ -468,30 +474,29 @@ namespace MWClass
MWWorld::InventoryStore &inv = getInventoryStore(ptr);
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
MWWorld::Ptr weapon = ((weaponslot != inv.end()) ? *weaponslot : MWWorld::Ptr());
if(!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name())
if (!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name())
weapon = MWWorld::Ptr();
MWMechanics::applyFatigueLoss(ptr, weapon, attackStrength);
const float fCombatDistance = store.find("fCombatDistance")->getFloat();
float dist = fCombatDistance * (!weapon.isEmpty() ?
weapon.get<ESM::Weapon>()->mBase->mData.mReach :
store.find("fHandToHandReach")->getFloat());
weapon.get<ESM::Weapon>()->mBase->mData.mReach :
store.find("fHandToHandReach")->getFloat());
// TODO: Use second to work out the hit angle
std::pair<MWWorld::Ptr, osg::Vec3f> result = world->getHitContact(ptr, dist);
MWWorld::Ptr victim = result.first;
osg::Vec3f hitPosition (result.second);
if(victim.isEmpty()) // Didn't hit anything
osg::Vec3f hitPosition(result.second);
if (victim.isEmpty()) // Didn't hit anything
return;
const MWWorld::Class &othercls = victim.getClass();
if(!othercls.isActor()) // Can't hit non-actors
if (!othercls.isActor()) // Can't hit non-actors
return;
MWMechanics::CreatureStats &otherstats = othercls.getCreatureStats(victim);
if(otherstats.isDead()) // Can't hit dead actors
if (otherstats.isDead()) // Can't hit dead actors
return;
if(ptr == MWMechanics::getPlayer())
MWBase::Environment::get().getWindowManager()->setEnemy(victim);
@ -501,8 +506,21 @@ namespace MWClass
float hitchance = MWMechanics::getHitChance(ptr, victim, ptr.getClass().getSkill(ptr, weapskill));
if (Misc::Rng::roll0to99() >= hitchance)
if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
{
mwmp::Main::get().getLocalPlayer()->GetAttack()->success = true;
if(mwmp::Main::get().getNetworking()->isDedicatedPlayer(victim))
mwmp::Main::get().getLocalPlayer()->GetAttack()->target =mwmp::Players::GetPlayer(victim)->guid;
}
if(Misc::Rng::roll0to99() >= hitchance)
{
if(ptr == MWBase::Environment::get().getWorld()->getPlayerPtr())
{
mwmp::Main::get().getLocalPlayer()->GetAttack()->success = false;
mwmp::Main::get().getLocalPlayer()->SendAttack(0);
}
othercls.onHit(victim, 0.0f, false, weapon, ptr, false);
MWMechanics::reduceWeaponCondition(0.f, false, weapon, ptr);
return;
@ -640,10 +658,15 @@ namespace MWClass
float agilityTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified() * gmst.fKnockDownMult->getFloat();
float knockdownTerm = getCreatureStats(ptr).getAttribute(ESM::Attribute::Agility).getModified()
* gmst.iKnockDownOddsMult->getInt() * 0.01f + gmst.iKnockDownOddsBase->getInt();
if (ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99())
bool isDedicated = mwmp::Main::get().getNetworking()->isDedicatedPlayer(attacker);
bool _knockdown = false;
if(isDedicated)
_knockdown = mwmp::Players::GetPlayer(attacker)->GetAttack()->knockdown;
if ((!isDedicated && ishealth && agilityTerm <= damage && knockdownTerm <= Misc::Rng::roll0to99()) || _knockdown)
{
getCreatureStats(ptr).setKnockedDown(true);
}
else
getCreatureStats(ptr).setHitRecovery(true); // Is this supposed to always occur?
@ -742,11 +765,30 @@ namespace MWClass
MWBase::Environment::get().getMechanicsManager()->actorKilled(ptr, attacker);
}
if(attacker == MWMechanics::getPlayer() && mwmp::Main::get().getNetworking()->isDedicatedPlayer(ptr))
{
mwmp::Attack *_atk = mwmp::Main::get().getLocalPlayer()->GetAttack();
_atk->damage = damage;
_atk->attacker = mwmp::Main::get().getLocalPlayer()->guid;
_atk->target = mwmp::Players::GetPlayer(ptr)->guid;
_atk->knockdown = getCreatureStats(ptr).getKnockedDown();
mwmp::Main::get().getLocalPlayer()->SendAttack(0); // todo : нужна чуствительность к виду
}
if(ptr == MWMechanics::getPlayer())
{
mwmp::Main::get().getLocalPlayer()->updateBaseStats(true);
mwmp::Main::get().getLocalPlayer()->updatePosition(true); // fix position after get damage;
}
}
boost::shared_ptr<MWWorld::Action> Npc::activate (const MWWorld::Ptr& ptr,
const MWWorld::Ptr& actor) const
{
if(actor == MWMechanics::getPlayer() && mwmp::Main::get().getNetworking()->isDedicatedPlayer(ptr))
return boost::shared_ptr<MWWorld::Action>(new MWWorld::FailedAction("Not implemented."));
// player got activated by another NPC
if(ptr == MWMechanics::getPlayer())
return boost::shared_ptr<MWWorld::Action>(new MWWorld::ActionTalk(actor));

@ -16,6 +16,7 @@
#include <components/sdlutil/sdlinputwrapper.hpp>
#include <components/sdlutil/sdlvideowrapper.hpp>
#include <apps/openmw/mwmp/Main.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/windowmanager.hpp"
@ -658,6 +659,7 @@ namespace MWInput
void InputManager::keyPressed( const SDL_KeyboardEvent &arg )
{
mwmp::Main::PressedKey(arg.keysym.sym);
// HACK: to make Morrowind's default keybinding for the console work without printing an extra "^" upon closing
// This assumes that SDL_TextInput events always come *after* the key event
// (which is somewhat reasonable, and hopefully true for all SDL platforms)

@ -7,6 +7,9 @@
#include <components/esm/esmwriter.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <apps/openmw/mwmp/Main.hpp>
#include <apps/openmw/mwmp/DedicatedPlayer.hpp>
#include "../mwworld/esmstore.hpp"
#include "../mwworld/class.hpp"
@ -991,7 +994,15 @@ namespace MWMechanics
iter->second->getCharacterController()->setActive(inProcessingRange);
if (iter->first == player)
iter->second->getCharacterController()->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell());
{
bool state = MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell();
iter->second->getCharacterController()->setAttackingOrSpell(state);
mwmp::Main::get().getLocalPlayer()->PrepareAttack(2, state);
}
if(mwmp::Main::get().getNetworking()->isDedicatedPlayer(iter->first))
iter->second->getCharacterController()->setAttackingOrSpell(mwmp::Main::get().getNetworking()->Attack(iter->first));
if (!iter->first.getClass().getCreatureStats(iter->first).isDead())
{

@ -1980,11 +1980,11 @@ bool CharacterController::kill()
{
if( isDead() )
{
if( mPtr == getPlayer() && !isAnimPlaying(mCurrentDeath) )
/*if( mPtr == getPlayer() && !isAnimPlaying(mCurrentDeath) )
{
//player's death animation is over
MWBase::Environment::get().getStateManager()->askLoadRecent();
}
}*/
return false;
}

@ -3,6 +3,9 @@
#include <components/misc/rng.hpp>
#include <components/sceneutil/positionattitudetransform.hpp>
#include <apps/openmw/mwmp/Networking.hpp>
#include <apps/openmw/mwmp/Main.hpp>
#include <apps/openmw/mwmp/DedicatedPlayer.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
@ -113,8 +116,17 @@ namespace MWMechanics
int iBlockMinChance = gmst.find("iBlockMinChance")->getInt();
x = std::min(iBlockMaxChance, std::max(iBlockMinChance, x));
if (Misc::Rng::roll0to99() < x)
bool isDedicated = mwmp::Main::get().getNetworking()->isDedicatedPlayer(blocker);
if(attacker == MWMechanics::getPlayer())
mwmp::Main::get().getLocalPlayer()->GetAttack()->block = false;
if((!isDedicated && Misc::Rng::roll0to99() < x) ||
(isDedicated && mwmp::Players::GetPlayer(blocker)->GetAttack()->block == 1))
{
if(attacker == MWMechanics::getPlayer())
mwmp::Main::get().getLocalPlayer()->GetAttack()->block = true;
// Reduce shield durability by incoming damage
int shieldhealth = shield->getClass().getItemHealth(*shield);
@ -169,6 +181,8 @@ namespace MWMechanics
void projectileHit(const MWWorld::Ptr &attacker, const MWWorld::Ptr &victim, MWWorld::Ptr weapon, const MWWorld::Ptr &projectile,
const osg::Vec3f& hitPosition, float attackStrength)
{
if(mwmp::Main::get().getNetworking()->isDedicatedPlayer(attacker))
return;
MWBase::World *world = MWBase::Environment::get().getWorld();
const MWWorld::Store<ESM::GameSetting> &gmst = world->getStore().get<ESM::GameSetting>();
@ -189,8 +203,13 @@ namespace MWMechanics
int skillValue = attacker.getClass().getSkill(attacker,
weapon.getClass().getEquipmentSkill(weapon));
if(attacker == MWBase::Environment::get().getWorld()->getPlayerPtr())
mwmp::Main::get().getLocalPlayer()->GetAttack()->success = true;
if (Misc::Rng::roll0to99() >= getHitChance(attacker, victim, skillValue))
{
if(attacker == getPlayer())
mwmp::Main::get().getLocalPlayer()->GetAttack()->success = false;
victim.getClass().onHit(victim, 0.0f, false, projectile, attacker, false);
MWMechanics::reduceWeaponCondition(0.f, false, weapon, attacker);
return;

@ -6,6 +6,8 @@
#include <boost/format.hpp>
#include <components/misc/rng.hpp>
#include <apps/openmw/mwmp/Main.hpp>
#include <apps/openmw/mwmp/DedicatedPlayer.hpp>
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/soundmanager.hpp"
@ -808,13 +810,38 @@ namespace MWMechanics
// Check success
float successChance = getSpellSuccessChance(spell, mCaster);
if (Misc::Rng::roll0to99() >= successChance)
bool isDedicated = mwmp::Main::get().getNetworking()->isDedicatedPlayer(mCaster);
if(mCaster == getPlayer())
{
mwmp::Main::get().getLocalPlayer()->GetAttack()->success = true;
mwmp::Main::get().getLocalPlayer()->GetAttack()->pressed = true;
}
if(isDedicated)
{
mwmp::Players::GetPlayer(mCaster)->GetAttack()->pressed = false;
}
if ((!isDedicated && Misc::Rng::roll0to99() >= successChance) ||
(isDedicated && mwmp::Players::GetPlayer(mCaster)->GetAttack()->success == 0))
{
if (mCaster == getPlayer())
{
mwmp::Main::get().getLocalPlayer()->GetAttack()->success = false;
MWBase::Environment::get().getWindowManager()->messageBox("#{sMagicSkillFail}");
}
fail = true;
}
if(mCaster == getPlayer())
{
mwmp::Main::get().getLocalPlayer()->SendAttack(1);
mwmp::Main::get().getLocalPlayer()->GetAttack()->pressed = false;
mwmp::Main::get().getLocalPlayer()->SendAttack(1);
}
if (fail)
{
// Failure sound

@ -0,0 +1,404 @@
//
// Created by koncord on 02.01.16.
//
#include "DedicatedPlayer.hpp"
#include <apps/openmw/mwmechanics/aitravel.hpp>
#include "../mwbase/environment.hpp"
#include "../mwstate/statemanagerimp.hpp"
#include "../mwinput/inputmanagerimp.hpp"
#include "../mwgui/windowmanagerimp.hpp"
#include "../mwworld/worldimp.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/customdata.hpp"
#include "../mwclass/npc.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwmechanics/mechanicsmanagerimp.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwworld/action.hpp"
#include <apps/openmw/mwworld/inventorystore.hpp>
#include <boost/algorithm/clamp.hpp>
using namespace mwmp;
using namespace std;
std::map<RakNet::RakNetGUID, DedicatedPlayer *> Players::players;
DedicatedPlayer::DedicatedPlayer(RakNet::RakNetGUID guid) : BasePlayer(guid)
{
GetAttack()->pressed = 0;
CreatureStats()->mDead = false;
movementFlags = 0;
}
DedicatedPlayer::~DedicatedPlayer()
{
}
MWWorld::Ptr DedicatedPlayer::getPtr()
{
return ptr;
}
void Players::CreatePlayer(RakNet::RakNetGUID id)
{
MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
ESM::NPC dedic_pl = *player.get<ESM::NPC>()->mBase;
DedicatedPlayer *_player = players[id];
dedic_pl.mRace = _player->Npc()->mRace;
dedic_pl.mHead = _player->Npc()->mHead;
dedic_pl.mHair = _player->Npc()->mHair;
dedic_pl.mName = _player->Npc()->mName;
dedic_pl.mFlags = _player->Npc()->mFlags;
if (_player->state == 0)
{
dedic_pl.mId = "Dedicated Player";
std::string recid = world->createRecord(dedic_pl)->mId;
_player->reference = new MWWorld::ManualRef(world->getStore(), recid, 1);
// temporary spawn character in ToddTest cell
ESM::Position _pos;
world->findInteriorPosition("ToddTest", _pos);
MWWorld::CellStore *store = world->getInterior("ToddTest");
MWWorld::Ptr tmp = world->safePlaceObject(_player->reference->getPtr(), store, _pos);
_player->ptr.mCell = tmp.mCell;
_player->ptr.mRef = tmp.mRef;
}
else
{
dedic_pl.mId = players[id]->ptr.get<ESM::NPC>()->mBase->mId;
MWWorld::ESMStore *store = const_cast<MWWorld::ESMStore *>(&world->getStore());
MWWorld::Store<ESM::NPC> *esm_store = const_cast<MWWorld::Store<ESM::NPC> *> (&store->get<ESM::NPC>());
esm_store->insert(dedic_pl);
}
_player->guid = id;
_player->state = 2;
_player->cell = *_player->ptr.getCell()->getCell();
_player->pos = _player->ptr.getRefData().getPosition();
world->enable(players[id]->ptr);
}
void Players::CleanUp()
{
for(std::map <RakNet::RakNetGUID, DedicatedPlayer *>::iterator it = players.begin(); it != players.end(); it++)
delete it->second;
}
void Players::DisconnectPlayer(RakNet::RakNetGUID id)
{
if (players[id]->state > 1)
{
players[id]->state = 1;
MWBase::World *world = MWBase::Environment::get().getWorld();
world->disable(players[id]->getPtr());
//move player to toddTest
ESM::Position _pos;
world->findInteriorPosition("ToddTest", _pos);
MWWorld::CellStore *store = world->getInterior("ToddTest");
world->moveObject(players[id]->getPtr(), store, _pos.pos[0], _pos.pos[1], _pos.pos[2]);
}
}
DedicatedPlayer *Players::GetPlayer(RakNet::RakNetGUID id)
{
return players[id];
}
MWWorld::Ptr DedicatedPlayer::getLiveCellPtr()
{
return reference->getPtr();
}
MWWorld::ManualRef *DedicatedPlayer::getRef()
{
return reference;
}
ESM::Position Slerp(ESM::Position start, ESM::Position end, float percent)
{
// dot product - the cosine of the angle between 2 vectors.
float dot = start.asVec3() * end.asVec3();
// clamp it to be in the range of Acos()
// This may be unnecessary, but floating point
// precision can be a fickle mistress.
dot = boost::algorithm::clamp(dot, -1.0f, 1.0f);
// acos(dot) returns the angle between start and end,
// And multiplying that by percent returns the angle between
// start and the final result.
float theta = acos(dot) * percent;
osg::Vec3f relativeVec = end.asVec3() - start.asVec3() * dot;
relativeVec.normalize(); // Orthonormal basis
// result
osg::Vec3f tmp ((start.asVec3() * cos(theta)) + (relativeVec * sin(theta)));
ESM::Position result;
result.pos[0] = tmp.x();
result.pos[1] = tmp.y();
result.pos[2] = tmp.z();
result.rot[0] = start.rot[0];
result.rot[1] = start.rot[1];
result.rot[2] = result.rot[2];
return result;
}
osg::Vec3f Lerp(osg::Vec3f start, osg::Vec3f end, float percent)
{
osg::Vec3f p(percent, percent, percent);
return (start + osg::componentMultiply(p, (end - start)));
}
void DedicatedPlayer::Move(float dt)
{
if (state != 2) return;
ESM::Position ref_pos = ptr.getRefData().getPosition();
MWBase::World *world = MWBase::Environment::get().getWorld();
{
osg::Vec3f lerp = Lerp(ref_pos.asVec3(), pos.asVec3(), dt * 15);
ref_pos.pos[0] = lerp.x();
ref_pos.pos[1] = lerp.y();
ref_pos.pos[2] = lerp.z();
ptr.getRefData().setPosition(ref_pos);
}
MWMechanics::Movement *move = &ptr.getClass().getMovementSettings(ptr);
move->mPosition[0] = dir.pos[0];
move->mPosition[1] = dir.pos[1];
move->mPosition[2] = dir.pos[2];
world->rotateObject(ptr, pos.rot[0], pos.rot[1], pos.rot[2]);
}
void Players::Update(float dt)
{
for(std::map <RakNet::RakNetGUID, DedicatedPlayer *>::iterator it = players.begin(); it != players.end(); it++)
{
DedicatedPlayer *pl = it->second;
if(pl == 0) continue;
MWMechanics::NpcStats *npcStats = &pl->ptr.getClass().getNpcStats(pl->getPtr());
MWMechanics::DynamicStat<float> value;
if(pl->CreatureStats()->mDead)
{
value.readState(pl->CreatureStats()->mDynamic[0]);
npcStats->setHealth(value);
continue;
}
value.readState(pl->CreatureStats()->mDynamic[0]);
npcStats->setHealth(value);
value.readState(pl->CreatureStats()->mDynamic[1]);
npcStats->setMagicka(value);
value.readState(pl->CreatureStats()->mDynamic[2]);
npcStats->setFatigue(value);
if(npcStats->isDead())
npcStats->resurrect();
npcStats->setAttacked(false);
npcStats->getAiSequence().stopCombat();
npcStats->setAlarmed(false);
npcStats->setAiSetting(MWMechanics::CreatureStats::AI_Alarm, 0);
npcStats->setAiSetting(MWMechanics::CreatureStats::AI_Fight, 0);
npcStats->setAiSetting(MWMechanics::CreatureStats::AI_Flee, 0);
npcStats->setAiSetting(MWMechanics::CreatureStats::AI_Hello, 0);
npcStats->setBaseDisposition(255);
pl->Move(dt);
pl->UpdateDrawState();
}
}
void DedicatedPlayer::UpdatePtr(MWWorld::Ptr newPtr)
{
ptr.mCell = newPtr.mCell;
ptr.mRef = newPtr.mRef;
ptr.mContainerStore = newPtr.mContainerStore;
}
DedicatedPlayer *Players::NewPlayer(RakNet::RakNetGUID guid)
{
players[guid] = new DedicatedPlayer(guid);
players[guid]->state = 0;
return players[guid];
}
void DedicatedPlayer::UpdateInventory()
{
MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr);
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
MWWorld::ContainerStoreIterator it = invStore.getSlot(slot);
const string &dedicItem = EquipedItem(slot)->refid;
std::string item = "";
bool equal = false;
if(it != invStore.end())
{
item = it->getCellRef().getRefId();
if(!Misc::StringUtils::ciEqual(item, dedicItem)) // if other item equiped
{
MWWorld::ContainerStore &store = ptr.getClass().getContainerStore(ptr);
store.remove(item, store.count(item), ptr);
}
else
equal = true;
}
if(dedicItem.empty() || equal)
continue;
const int count = EquipedItem(slot)->count;
ptr.getClass().getContainerStore(ptr).add(dedicItem, count, ptr);
for (MWWorld::ContainerStoreIterator it2 = invStore.begin(); it2 != invStore.end(); ++it2)
{
if (::Misc::StringUtils::ciEqual(it2->getCellRef().getRefId(), dedicItem)) // equip item
{
boost::shared_ptr<MWWorld::Action> action = it2->getClass().use(*it2);
action->execute(ptr);
break;
}
}
}
}
const std::string DedicatedPlayer::GetAnim()
{
static string anim;
static string anim_dir;
static string anim_weap;
MWMechanics::NpcStats *npcStats = &ptr.getClass().getNpcStats(ptr);
if (movementFlags & MWMechanics::CreatureStats::Flag_Run)
anim = "run";
else if (movementFlags & MWMechanics::CreatureStats::Flag_Sneak)
anim = "sneak";
else
anim = "walk";
if(movementAnim != 0)
{
if (movementAnim == 3)
anim_dir = "forward";
else if (movementAnim == 4)
anim_dir = "back";
else if (movementAnim == 2)
anim_dir = "left";
else if (movementAnim == 1)
anim_dir = "right";
}
else
{
anim = "idle";
anim_dir = "";
}
if (npcStats->getDrawState() == MWMechanics::DrawState_Weapon)
{
MWWorld::InventoryStore& invStore = ptr.getClass().getInventoryStore(ptr);
MWWorld::ContainerStoreIterator weaponSlot = invStore.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if (weaponSlot != invStore.end() && weaponSlot->getTypeName() == typeid(ESM::Weapon).name())
{
int type = weaponSlot->get<ESM::Weapon>()->mBase->mData.mType;
if (type == ESM::Weapon::ShortBladeOneHand ||
type == ESM::Weapon::LongBladeOneHand ||
type == ESM::Weapon::BluntOneHand ||
type == ESM::Weapon::AxeOneHand /*||
type == ESM::Weapon::MarksmanThrown ||
type == ESM::Weapon::MarksmanCrossbow ||
type == ESM::Weapon::MarksmanBow*/)
anim_weap = "1h";
else if(type == ESM::Weapon::LongBladeTwoHand ||
type == ESM::Weapon::BluntTwoClose ||
type == ESM::Weapon::AxeTwoHand)
anim_weap = "2c";
else if(type == ESM::Weapon::BluntTwoWide ||
type == ESM::Weapon::SpearTwoWide)
anim_weap = "2w";
}
else
anim_weap = "hh";
}
else if (movementAnim == 0 && npcStats->getDrawState() == MWMechanics::DrawState_Spell)
anim_weap = "spell";
else
anim_weap = "";
return (anim + anim_dir + anim_weap);
}
DedicatedPlayer *Players::GetPlayer(const MWWorld::Ptr &ptr)
{
std::map <RakNet::RakNetGUID, DedicatedPlayer *>::iterator it = players.begin();
for(; it != players.end(); it++)
{
if(it->second == 0 || it->second->getPtr().mRef == 0)
continue;
string refid = ptr.getCellRef().getRefId();
if(it->second->getPtr().getCellRef().getRefId() == refid)
return it->second;
}
return 0;
}
void DedicatedPlayer::UpdateDrawState()
{
using namespace MWMechanics;
if (drawState == 0)
ptr.getClass().getNpcStats(ptr).setDrawState(DrawState_Nothing);
else if(drawState == 1)
ptr.getClass().getNpcStats(ptr).setDrawState(DrawState_Weapon);
else if(drawState == 2)
ptr.getClass().getNpcStats(ptr).setDrawState(DrawState_Spell);
MWMechanics::NpcStats *npcStats = &ptr.getClass().getNpcStats(ptr);
npcStats->setMovementFlag(CreatureStats::Flag_Run, (movementFlags & CreatureStats::Flag_Run) != 0);
npcStats->setMovementFlag(CreatureStats::Flag_Sneak, (movementFlags & CreatureStats::Flag_Sneak) != 0);
npcStats->setMovementFlag(CreatureStats::Flag_ForceJump, (movementFlags & CreatureStats::Flag_ForceJump) != 0);
npcStats->setMovementFlag(CreatureStats::Flag_ForceMoveJump, (movementFlags & CreatureStats::Flag_ForceMoveJump) != 0);
}
void DedicatedPlayer::updateCell()
{
MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::CellStore *cellStore;
if (cell.isExterior() == 1)
cellStore = world->getExterior(cell.mCellId.mIndex.mX, cell.mCellId.mIndex.mY);
else
cellStore = world->getInterior(cell.mName);
UpdatePtr(world->moveObject(ptr, cellStore, pos.pos[0], pos.pos[1], pos.pos[2]));
}

@ -0,0 +1,60 @@
//
// Created by koncord on 02.01.16.
//
#ifndef OPENMW_PLAYER_HPP
#define OPENMW_PLAYER_HPP
#include <components/esm/loadnpc.hpp>
#include <apps/openmw/mwworld/manualref.hpp>
#include <map>
#include <apps/openmw/mwmechanics/aisequence.hpp>
#include <RakNetTypes.h>
#include <components/openmw-mp/Base/BasePlayer.hpp>
namespace mwmp
{
struct DedicatedPlayer;
class Players
{
public:
static DedicatedPlayer *NewPlayer(RakNet::RakNetGUID guid);
static void CreatePlayer(RakNet::RakNetGUID guid);
static void DisconnectPlayer(RakNet::RakNetGUID guid);
static void CleanUp();
static DedicatedPlayer *GetPlayer(RakNet::RakNetGUID guid);
static DedicatedPlayer *GetPlayer(const MWWorld::Ptr &ptr);
static void Update(float dt);
private:
static std::map<RakNet::RakNetGUID, DedicatedPlayer *> players;
};
class DedicatedPlayer : public BasePlayer
{
friend class Players;
public:
MWWorld::Ptr getPtr();
MWWorld::Ptr getLiveCellPtr();
MWWorld::ManualRef* getRef();
void Move(float dt);
void UpdateDrawState();
void UpdateInventory();
void updateCell();
private:
DedicatedPlayer(RakNet::RakNetGUID guid);
virtual ~DedicatedPlayer();
void UpdatePtr(MWWorld::Ptr newPtr);
const std::string GetAnim();
int state;
MWWorld::ManualRef* reference;
MWWorld::Ptr ptr;
};
}
#endif //OPENMW_PLAYER_HPP

@ -0,0 +1,237 @@
//
// Created by koncord on 04.03.16.
//
#include "GUIChat.hpp"
#include <MyGUI_EditBox.h>
#include <apps/openmw/mwbase/environment.hpp>
#include <apps/openmw/mwgui/windowmanagerimp.hpp>
#include <apps/openmw/mwinput/inputmanagerimp.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwworld/worldimp.hpp"
#include "../mwworld/player.hpp"
#include "Networking.hpp"
#include "Main.hpp"
namespace mwmp
{
GUIChat::GUIChat(int x, int y, int w, int h)
: WindowBase("openmw_console.layout")
{
setCoord(x, y, w, h);
getWidget(mCommandLine, "edit_Command");
getWidget(mHistory, "list_History");
// Set up the command line box
mCommandLine->eventEditSelectAccept +=
newDelegate(this, &GUIChat::acceptCommand);
mCommandLine->eventKeyButtonPressed +=
newDelegate(this, &GUIChat::keyPress);
setTitle("Chat");
mHistory->setOverflowToTheLeft(true);
windowState = 0;
mCommandLine->setVisible(0);
delay = 3; // 3 sec.
}
void GUIChat::open()
{
// Give keyboard focus to the combo box whenever the console is
// turned on
SetEditState(0);
windowState = CHAT_ENABLED;
}
void GUIChat::close()
{
// Apparently, hidden widgets can retain key focus
// Remove for MyGUI 3.2.2
windowState = CHAT_DISABLED;
SetEditState(0);
}
void GUIChat::exit()
{
//WindowBase::exit();
}
void GUIChat::resetReference()
{
ReferenceInterface::resetReference();
//setSelectedObject(MWWorld::Ptr());
}
void GUIChat::onReferenceUnavailable()
{
//setSelectedObject(MWWorld::Ptr());
}
void GUIChat::acceptCommand(MyGUI::EditBox *_sender)
{
const std::string &cm = mCommandLine->getOnlyText();
if(cm.empty()) return;
// Add the command to the history, and set the current pointer to
// the end of the list
if (mCommandHistory.empty() || mCommandHistory.back() != cm)
mCommandHistory.push_back(cm);
mCurrent = mCommandHistory.end();
mEditString.clear();
// Reset the command line before the command execution.
// It prevents the re-triggering of the acceptCommand() event for the same command
// during the actual command execution
mCommandLine->setCaption("");
SetEditState(0);
send (cm);
}
void GUIChat::onResChange(int width, int height)
{
setCoord(10,10, width-10, height/2);
}
void GUIChat::setFont(const std::string &fntName)
{
mHistory->setFontName(fntName);
mCommandLine->setFontName(fntName);
}
void GUIChat::print(const std::string &msg, const std::string &color)
{
if(windowState == 2 && !isVisible())
{
setVisible(true);
}
mHistory->addText(color + MyGUI::TextIterator::toTagsString(msg));
}
void GUIChat::printOK(const std::string &msg)
{
print(msg + "\n", "#FF00FF");
}
void GUIChat::printError(const std::string &msg)
{
print(msg + "\n", "#FF2222");
}
void GUIChat::send(const std::string &str)
{
LocalPlayer *localPlayer = Main::get().getLocalPlayer();
Networking *networking = Main::get().getNetworking();
*localPlayer->ChatMessage() = str;
RakNet::BitStream bs;
networking->GetPacket(ID_CHAT_MESSAGE)->Packet(&bs, localPlayer, true);
networking->SendData(&bs);
}
void GUIChat::clean()
{
mHistory->clearUserStrings();
}
void GUIChat::PressedChatMode()
{
windowState++;
if(windowState == 3) windowState = 0;
switch(windowState)
{
case CHAT_DISABLED:
this->mMainWidget->setVisible(false);
SetEditState(0);
break;
case CHAT_ENABLED:
this->mMainWidget->setVisible(true);
break;
default: //CHAT_HIDDENMODE
this->mMainWidget->setVisible(true);
curTime = 0;
}
}
void GUIChat::SetEditState(bool state)
{
editState = state;
mCommandLine->setVisible(editState);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(editState ? mCommandLine : nullptr);
}
void GUIChat::PressedSay()
{
if (windowState == CHAT_DISABLED)
return;
else if(windowState == CHAT_HIDDENMODE)
{
setVisible(true);
curTime = 0;
editState = true;
}
else // CHAT_ENABLED
editState = !editState;
SetEditState(editState);
}
void GUIChat::keyPress(MyGUI::Widget *_sender, MyGUI::KeyCode key, MyGUI::Char _char)
{
if(mCommandHistory.empty()) return;
// Traverse history with up and down arrows
if(key == MyGUI::KeyCode::ArrowUp)
{
// If the user was editing a string, store it for later
if(mCurrent == mCommandHistory.end())
mEditString = mCommandLine->getOnlyText();
if(mCurrent != mCommandHistory.begin())
{
--mCurrent;
mCommandLine->setCaption(*mCurrent);
}
}
else if(key == MyGUI::KeyCode::ArrowDown)
{
if(mCurrent != mCommandHistory.end())
{
++mCurrent;
if(mCurrent != mCommandHistory.end())
mCommandLine->setCaption(*mCurrent);
else
// Restore the edit string
mCommandLine->setCaption(mEditString);
}
}
}
void GUIChat::Update(float dt)
{
if(windowState == CHAT_HIDDENMODE && !editState && isVisible())
{
curTime += dt;
if(curTime >= delay)
{
SetEditState(false);
this->mMainWidget->setVisible(false);
}
}
}
void GUIChat::SetDelay(float delay)
{
this->delay = delay;
}
}

@ -0,0 +1,101 @@
//
// Created by koncord on 04.03.16.
//
#ifndef OPENMW_GUICHAT_HPP
#define OPENMW_GUICHAT_HPP
#include <list>
#include <string>
#include <vector>
#include <components/compiler/errorhandler.hpp>
#include <components/compiler/lineparser.hpp>
#include <components/compiler/scanner.hpp>
#include <components/compiler/locals.hpp>
#include <components/compiler/output.hpp>
#include <components/compiler/extensions.hpp>
#include <components/interpreter/interpreter.hpp>
#include "../mwgui/referenceinterface.hpp"
#include "../mwgui/windowbase.hpp"
namespace mwmp
{
class GUIChat : public MWGui::WindowBase, public MWGui::ReferenceInterface
{
public:
enum
{
CHAT_DISABLED = 0,
CHAT_ENABLED,
CHAT_HIDDENMODE
} CHAT_WIN_STATE;
MyGUI::EditBox* mCommandLine;
MyGUI::EditBox* mHistory;
typedef std::list<std::string> StringList;
// History of previous entered commands
StringList mCommandHistory;
StringList::iterator mCurrent;
std::string mEditString;
GUIChat(int x, int y, int w, int h);
void PressedChatMode(); //switch chat mode
void PressedSay(); // switch chat focus (if chat mode != CHAT_DISABLED)
void SetDelay(float delay);
void Update(float dt);
virtual void open();
virtual void close();
virtual void exit();
void setFont(const std::string &fntName);
void onResChange(int width, int height);
// Print a message to the console, in specified color.
void print(const std::string &msg, const std::string& color = "#FFFFFF");
// Clean chat
void clean();
// These are pre-colored versions that you should use.
/// Output from successful console command
void printOK(const std::string &msg);
/// Error message
void printError(const std::string &msg);
virtual void resetReference ();
void send(const std::string &str);
protected:
virtual void onReferenceUnavailable();
private:
void keyPress(MyGUI::Widget* _sender,
MyGUI::KeyCode key,
MyGUI::Char _char);
void acceptCommand(MyGUI::EditBox* _sender);
void SetEditState(bool state);
int windowState;
bool editState;
float delay;
float curTime;
};
}
#endif //OPENMW_GUICHAT_HPP

@ -0,0 +1,22 @@
//
// Created by koncord on 19.05.16.
//
#include "GUILogin.hpp"
#include <MyGUI_EditBox.h>
#include <MyGUI_Button.h>
GUILogin::GUILogin() : WindowModal("tes3mp_login.layout")
{
center(); // center window
setVisible(false);
getWidget(mLogin, "EditLogin");
getWidget(mServer, "EditServer");
getWidget(mPort, "EditPort");
getWidget(mConnect, "ButtonConnect");
}

@ -0,0 +1,23 @@
//
// Created by koncord on 19.05.16.
//
#ifndef OPENMW_GUILOGIN_HPP
#define OPENMW_GUILOGIN_HPP
#include "../mwgui/windowbase.hpp"
class GUILogin : public MWGui::WindowModal
{
public:
GUILogin();
MyGUI::EditBox* mLogin;
MyGUI::EditBox* mServer;
MyGUI::EditBox* mPort;
protected:
MyGUI::Button* mConnect;
};
#endif //OPENMW_GUILOGIN_HPP

@ -0,0 +1,453 @@
//
// Created by koncord on 14.01.16.
//
#include <apps/openmw/mwworld/manualref.hpp>
#include <apps/openmw/mwmechanics/aitravel.hpp>
#include <components/esm/esmwriter.hpp>
#include "../mwbase/environment.hpp"
#include "../mwstate/statemanagerimp.hpp"
#include "../mwinput/inputmanagerimp.hpp"
#include "../mwscript/scriptmanagerimp.hpp"
#include "../mwgui/windowmanagerimp.hpp"
#include "../mwworld/worldimp.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/customdata.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwclass/npc.hpp"
#include "../mwclass/creature.hpp"
#include "../mwmechanics/mechanicsmanagerimp.hpp"
#include "../mwworld/cellstore.hpp"
#include <apps/openmw/mwdialogue/dialoguemanagerimp.hpp>
#include <apps/openmw/mwworld/inventorystore.hpp>
#include <apps/openmw/mwmechanics/spellcasting.hpp>
#include <apps/openmw/mwgui/inventorywindow.hpp>
#include "LocalPlayer.hpp"
#include "Main.hpp"
using namespace mwmp;
using namespace std;
LocalPlayer::LocalPlayer()
{
CharGenStage()->current = 0;
CharGenStage()->end = 1;
}
LocalPlayer::~LocalPlayer()
{
}
void LocalPlayer::Update()
{
updateCell();
updatePosition();
updateDrawStateAndFlags();
updateAttackState();
updateDeadState();
updateInventory();
updateBaseStats();
}
MWWorld::Ptr LocalPlayer::GetPlayerPtr()
{
return MWBase::Environment::get().getWorld()->getPlayerPtr();
}
void LocalPlayer::updateBaseStats(bool forceUpdate)
{
MWWorld::Ptr player = GetPlayerPtr();
MWMechanics::CreatureStats *creatureClass = &player.getClass().getCreatureStats(player);
MWMechanics::DynamicStat<float> health(creatureClass->getHealth());
MWMechanics::DynamicStat<float> magicka(creatureClass->getMagicka());
MWMechanics::DynamicStat<float> fatigue(creatureClass->getFatigue());
static MWMechanics::DynamicStat<float> oldHealth(creatureClass->getHealth());
static MWMechanics::DynamicStat<float> oldMagicka(creatureClass->getMagicka());
static MWMechanics::DynamicStat<float> oldFatigue(creatureClass->getFatigue());
static float timer = 0;
if(((oldHealth != health || oldMagicka != magicka || oldFatigue != fatigue) &&
(timer += MWBase::Environment::get().getFrameDuration()) >= 0.5 ) || forceUpdate)
{
oldHealth = health;
oldMagicka = magicka;
oldFatigue = fatigue;
health.writeState(CreatureStats()->mDynamic[0]);
magicka.writeState(CreatureStats()->mDynamic[1]);
fatigue.writeState(CreatureStats()->mDynamic[2]);
timer = 0;
GetNetworking()->GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(this);
}
}
void LocalPlayer::updatePosition(bool forceUpdate)
{
MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
const MWMechanics::Movement &move = player.getClass().getMovementSettings(player);
static bool posChanged = false;
ESM::Position _pos = player.getRefData().getPosition();
const bool isChangedPos = (move.mPosition[0] != 0 || move.mPosition[1] != 0 || move.mPosition[2] != 0
|| move.mRotation[0] != 0 || move.mRotation[1] != 0 || move.mRotation[2] != 0);
if (isChangedPos || posChanged || forceUpdate)
{
posChanged = isChangedPos;
(*Position()) = _pos;
Dir()->pos[0] = move.mPosition[0];
Dir()->pos[1] = move.mPosition[1];
Dir()->pos[2] = move.mPosition[2];
GetNetworking()->GetPacket(ID_GAME_UPDATE_POS)->Send(this);
}
}
void LocalPlayer::updateInventory(bool forceUpdate)
{
MWWorld::Ptr player = GetPlayerPtr();
static bool invChanged = false;
if (forceUpdate)
invChanged = true;
MWWorld::InventoryStore &invStore = player.getClass().getInventoryStore(player);
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; ++slot)
{
MWWorld::ContainerStoreIterator it = invStore.getSlot(slot);
if(it != invStore.end() && !::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), EquipedItem(slot)->refid))
{
invChanged = true;
EquipedItem(slot)->refid = it->getCellRef().getRefId();
if(slot == MWWorld::InventoryStore::Slot_CarriedRight)
{
MWMechanics::WeaponType weaptype;
MWMechanics::getActiveWeapon(player.getClass().getCreatureStats(player), player.getClass().getInventoryStore(player), &weaptype);
if(weaptype != MWMechanics::WeapType_Thrown)
EquipedItem(slot)->count = 1;
}
else
EquipedItem(slot)->count = invStore.count(it->getCellRef().getRefId());
}
else if (it == invStore.end() && !EquipedItem(slot)->refid.empty())
{
invChanged = true;
EquipedItem(slot)->refid = "";
EquipedItem(slot)->count = 0;
}
}
if (invChanged)
{
RakNet::BitStream bs;
bs.ResetWritePointer();
GetNetworking()->GetPacket((RakNet::MessageID) ID_GAME_UPDATE_EQUIPED)->Packet(&bs, this, true);
GetNetworking()->SendData(&bs);
invChanged = false;
}
}
void LocalPlayer::updateAttackState(bool forceUpdate)
{
MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = GetPlayerPtr();
using namespace MWMechanics;
static bool attackPressed = false; // prevent flood
MWMechanics::DrawState_ state = player.getClass().getNpcStats(player).getDrawState();
//player.getClass().hit(player, 1, ESM::Weapon::AT_Chop);
if(world->getPlayer().getAttackingOrSpell() && !attackPressed)
{
MWWorld::Ptr weapon = MWWorld::Ptr(); // hand-to-hand
//player.getClass().onHit(player, 0.5, true, weapon, 0, 1);
if(state == MWMechanics::DrawState_Spell)
{
//cout << "getAttackingOrSpell" << endl;
const string &spell = MWBase::Environment::get().getWindowManager()->getSelectedSpell();
GetAttack()->attacker = guid;
GetAttack()->type = 1;
GetAttack()->pressed = true;
GetAttack()->refid = spell;
/*RakNet::BitStream bs;
GetNetworking()->GetPacket((RakNet::MessageID) ID_GAME_ATTACK)->Packet(&bs, this, true);
GetNetworking()->SendData(&bs);*/
}
else if(state == MWMechanics::DrawState_Weapon)
{
//PrepareAttack(2);
}
attackPressed = true;
}
else if(!world->getPlayer().getAttackingOrSpell() && attackPressed)
{
if(/*state == MWMechanics::DrawState_Spell ||*/ state == MWMechanics::DrawState_Weapon)
{
//localNetPlayer->GetAttack()->success = false;
//SendAttack(0);
}
attackPressed = false;
}
}
void LocalPlayer::updateDeadState(bool forceUpdate)
{
MWWorld::Ptr player = GetPlayerPtr();
MWMechanics::NpcStats *playerStats = &player.getClass().getNpcStats(player);
static bool isDead = false;
if(playerStats->isDead() && !isDead)
{
CreatureStats()->mDead = true;
RakNet::BitStream bs;
GetNetworking()->GetPacket((RakNet::MessageID)ID_GAME_DIE)->Packet(&bs, this, true);
GetNetworking()->SendData(&bs);
isDead = true;
}
else if(playerStats->getHealth().getCurrent() > 0 && isDead)
isDead = false;
}
void LocalPlayer::updateAttributesAndSkills(bool forceUpdate)
{
MWWorld::Ptr player = GetPlayerPtr();
const MWMechanics::NpcStats &_npcStats = player.getClass().getNpcStats(player);
for(int i = 0; i < PacketAttributesAndStats::StatsCount; ++i)
_npcStats.getSkill(i).writeState( NpcStats()->mSkills[i]);
for(int i = 0; i < PacketAttributesAndStats::AttributesCount; ++i)
_npcStats.getAttribute(i).writeState(CreatureStats()->mAttributes[i]);
}
Networking *LocalPlayer::GetNetworking()
{
return mwmp::Main::get().getNetworking();
}
void LocalPlayer::PrepareAttack(char type, bool state)
{
if(GetAttack()->pressed == state)
return;
MWMechanics::DrawState_ dstate = GetPlayerPtr().getClass().getNpcStats(GetPlayerPtr()).getDrawState();
if(dstate == MWMechanics::DrawState_Spell)
{
const string &spell = MWBase::Environment::get().getWindowManager()->getSelectedSpell();
GetAttack()->refid = spell;
}
else
{
}
GetAttack()->pressed = state;
GetAttack()->type = type;
GetAttack()->knockdown = false;
GetAttack()->success = false;
GetAttack()->block = false;
GetAttack()->target = RakNet::RakNetGUID();
GetAttack()->attacker = guid;
RakNet::BitStream bs;
GetNetworking()->GetPacket((RakNet::MessageID) ID_GAME_ATTACK)->Packet(&bs, this, true);
GetNetworking()->SendData(&bs);
}
void LocalPlayer::SendAttack(char type)
{
MWMechanics::DrawState_ state = GetPlayerPtr().getClass().getNpcStats(GetPlayerPtr()).getDrawState();
if(state == MWMechanics::DrawState_Spell)
{
}
else
{
}
GetAttack()->type = type;
GetAttack()->pressed = false;
RakNet::BitStream bs;
GetNetworking()->GetPacket((RakNet::MessageID) ID_GAME_ATTACK)->Packet(&bs, this, true);
GetNetworking()->SendData(&bs);
}
void LocalPlayer::updateCell(bool forceUpdate)
{
const ESM::Cell *_cell = MWBase::Environment::get().getWorld()->getPlayerPtr().getCell()->getCell();
static bool isExterior = !_cell->isExterior();
if(isExterior != _cell->isExterior() || !Misc::StringUtils::ciEqual(_cell->mName, GetCell()->mName) || forceUpdate)
{
(*GetCell()) = *_cell;
isExterior = _cell->isExterior();
RakNet::BitStream bs;
GetNetworking()->GetPacket((RakNet::MessageID) ID_GAME_CELL)->Packet(&bs, this, true);
GetNetworking()->SendData(&bs);
}
}
void LocalPlayer::updateDrawStateAndFlags(bool forceUpdate)
{
MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
MWMechanics::NpcStats npcStats = player.getClass().getNpcStats(player);
using namespace MWMechanics;
static bool oldRun = npcStats.getMovementFlag(CreatureStats::Flag_Run);
static bool oldSneak = npcStats.getMovementFlag(CreatureStats::Flag_Sneak);
static bool oldForceJump = npcStats.getMovementFlag(CreatureStats::Flag_ForceJump);
static bool oldForceMoveJump = npcStats.getMovementFlag(CreatureStats::Flag_ForceMoveJump);
bool run = npcStats.getMovementFlag(CreatureStats::Flag_Run);
bool sneak = npcStats.getMovementFlag(CreatureStats::Flag_Sneak);
bool forceJump = npcStats.getMovementFlag(CreatureStats::Flag_ForceJump);
bool forceMoveJump = npcStats.getMovementFlag(CreatureStats::Flag_ForceMoveJump);
bool jump = !world->isOnGround(player) && !world->isFlying(player);
static bool onJump = false;
MWMechanics::DrawState_ state = player.getClass().getNpcStats(player).getDrawState();
static MWMechanics::DrawState_ oldState = player.getClass().getNpcStats(player).getDrawState();
//static float timer = 0;
if(oldRun != run
|| oldSneak != sneak || oldForceJump != forceJump
|| oldForceMoveJump != forceMoveJump || oldState != state ||
((jump || onJump)/* && (timer += MWBase::Environment::get().getFrameDuration() )> 0.5*/)
|| forceUpdate)
{
oldSneak = sneak;
oldRun = run;
oldForceJump = forceJump;
oldForceMoveJump = forceMoveJump;
oldState = state;
onJump = jump;
movementFlags = 0;
#define __SETFLAG(flag, value) (value) ? (movementFlags | flag) : (movementFlags & ~flag)
movementFlags = __SETFLAG(CreatureStats::Flag_Sneak, sneak);
movementFlags = __SETFLAG(CreatureStats::Flag_Run, run);
movementFlags = __SETFLAG(CreatureStats::Flag_ForceJump, forceJump);
movementFlags = __SETFLAG(CreatureStats::Flag_ForceJump, jump);
movementFlags = __SETFLAG(CreatureStats::Flag_ForceMoveJump, forceMoveJump);
#undef __SETFLAG
if (state == MWMechanics::DrawState_Nothing)
(*DrawState()) = 0;
else if (state == MWMechanics::DrawState_Weapon)
(*DrawState()) = 1;
else if (state == MWMechanics::DrawState_Spell)
(*DrawState()) = 2;
if(jump)
mwmp::Main::get().getLocalPlayer()->updatePosition(true); // fix position after jump;
RakNet::BitStream bs;
GetNetworking()->GetPacket((RakNet::MessageID) ID_GAME_DRAWSTATE)->Packet(&bs, this, true);
GetNetworking()->SendData(&bs);
//timer = 0;
}
}
void LocalPlayer::CharGen(int stageFirst, int stageEnd)
{
CharGenStage()->current = stageFirst;
CharGenStage()->end = stageEnd;
}
bool LocalPlayer::CharGenThread() // ToDo: need fix
{
MWBase::WindowManager *windowManager = MWBase::Environment::get().getWindowManager();
if(windowManager->isGuiMode())
return false;
if(CharGenStage()->current >= CharGenStage()->end)
{
if (GetNetworking()->isConnected() && CharGenStage()->current == CharGenStage()->end &&
CharGenStage()->end != 0)
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
(*Npc()) = *player.get<ESM::NPC>()->mBase;
GetNetworking()->GetPacket(ID_GAME_BASE_INFO)->Send(this);
if(CharGenStage()->end != 1)
{
updateBaseStats(true);
updateAttributesAndSkills(true);
GetNetworking()->GetPacket(ID_GAME_UPDATE_SKILLS)->Send(this);
GetNetworking()->GetPacket(ID_GAME_CHARGEN)->Send(this);
}
CharGenStage()->end = 0;
/*RakNet::BitStream bs;
GetNetworking()->GetPacket(ID_GAME_BASE_INFO)->Packet(&bs, this, true);
GetNetworking()->SendData(&bs);*/
}
return true;
}
switch (CharGenStage()->current)
{
case 0:
windowManager->pushGuiMode(MWGui::GM_Name);
break;
case 1:
windowManager->pushGuiMode(MWGui::GM_Race);
break;
case 2:
windowManager->pushGuiMode(MWGui::GM_Class);
break;
case 3:
windowManager->pushGuiMode(MWGui::GM_Birth);
break;
default:
windowManager->pushGuiMode(MWGui::GM_Review);
break;
}
GetNetworking()->GetPacket(ID_GAME_CHARGEN)->Send(this);
CharGenStage()->current++;
return false;
}
void LocalPlayer::updateChar()
{
MWBase::Environment::get().getMechanicsManager()->setPlayerRace(
Npc()->mRace,
Npc()->isMale(),
Npc()->mHead,
Npc()->mHair
);
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar();
}

@ -0,0 +1,48 @@
//
// Created by koncord on 14.01.16.
//
#ifndef OPENMW_LOCALPLAYER_HPP
#define OPENMW_LOCALPLAYER_HPP
#include <components/openmw-mp/Base/BasePlayer.hpp>
#include <RakNetTypes.h>
#include <apps/openmw/mwmp/Networking.hpp>
namespace mwmp
{
class LocalPlayer : public BasePlayer
{
public:
LocalPlayer();
virtual ~LocalPlayer();
void Update();
void updateBaseStats(bool forceUpdate = false);
void updatePosition(bool forceUpdate = false);
void updateInventory(bool forceUpdate = false);
void updateAttackState(bool forceUpdate = false);
void updateDeadState(bool forceUpdate = false);
void updateAttributesAndSkills(bool forceUpdate = false);
void updateCell(bool forceUpdate = false);
void updateDrawStateAndFlags(bool forceUpdate = false);
void CharGen(int stageFirst, int stageEnd);
bool CharGenThread(); // return true if CGStage::current == CGStage::end
void updateChar();
void SendAttack(char type);
void PrepareAttack(char type, bool state);
private:
MWWorld::Ptr GetPlayerPtr();
Networking *GetNetworking();
};
}
#endif //OPENMW_LOCALPLAYER_HPP

@ -0,0 +1,203 @@
//
// Created by koncord on 01.01.16.
//
#include "Main.hpp"
#include <apps/openmw/mwworld/manualref.hpp>
#include <apps/openmw/mwmechanics/aitravel.hpp>
#include <components/esm/esmwriter.hpp>
#include "../mwbase/environment.hpp"
#include "../mwstate/statemanagerimp.hpp"
#include "../mwinput/inputmanagerimp.hpp"
#include "../mwscript/scriptmanagerimp.hpp"
#include "../mwgui/windowmanagerimp.hpp"
#include "../mwworld/worldimp.hpp"
#include "../mwworld/ptr.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/customdata.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwclass/npc.hpp"
#include "../mwclass/creature.hpp"
#include "../mwmechanics/mechanicsmanagerimp.hpp"
#include "../mwworld/cellstore.hpp"
#include <apps/openmw/mwdialogue/dialoguemanagerimp.hpp>
#include <apps/openmw/mwworld/inventorystore.hpp>
#include <apps/openmw/mwmechanics/spellcasting.hpp>
#include "DedicatedPlayer.hpp"
#include "LocalPlayer.hpp"
#include "GUIChat.hpp"
using namespace mwmp;
using namespace std;
Main *Main::pMain = 0;
std::string loadSettings (Settings::Manager & settings)
{
Files::ConfigurationManager mCfgMgr;
// Create the settings manager and load default settings file
const std::string localdefault = (mCfgMgr.getLocalPath() / "tes3mp-client-default.cfg").string();
const std::string globaldefault = (mCfgMgr.getGlobalPath() / "tes3mp-client-default.cfg").string();
// prefer local
if (boost::filesystem::exists(localdefault))
settings.loadDefault(localdefault);
else if (boost::filesystem::exists(globaldefault))
settings.loadDefault(globaldefault);
else
throw std::runtime_error ("No default settings file found! Make sure the file \"tes3mp-client-default.cfg\" was properly installed.");
// load user settings if they exist
const std::string settingspath = (mCfgMgr.getUserConfigPath() / "tes3mp-client.cfg").string();
if (boost::filesystem::exists(settingspath))
settings.loadUser(settingspath);
return settingspath;
}
Main::Main()
{
std::cout << "Main::Main" << std::endl;
mNetworking = new Networking();
mLocalPlayer = new LocalPlayer();
//mLocalPlayer->CharGen(0, 4);
server = "mp.tes3mp.com";
port = 25565;
keySay = SDLK_y;
keyChatMode = SDLK_F2;
}
Main::~Main()
{
std::cout << "Main::~Main" << std::endl;
delete mNetworking;
delete mLocalPlayer;
Players::CleanUp();
}
void Main::Create()
{
assert(!pMain);
pMain = new Main();
Settings::Manager mgr;
Settings::CategorySettingValueMap saveUserSettings = mgr.mUserSettings;
Settings::CategorySettingValueMap saveDefaultSettings = mgr.mDefaultSettings;
Settings::CategorySettingVector saveChangedSettings = mgr.mChangedSettings;
mgr.mUserSettings.clear();
mgr.mDefaultSettings.clear();
mgr.mChangedSettings.clear();
loadSettings(mgr);
pMain->server = mgr.getString("server", "General");
pMain->port = (unsigned short)mgr.getInt("port", "General");
float chatDelay = mgr.getFloat("delay", "Chat");
int chatY = mgr.getInt("y", "Chat");
int chatX = mgr.getInt("x", "Chat");
int chatW = mgr.getInt("w", "Chat");
int chatH = mgr.getInt("h", "Chat");
pMain->keySay = SDL_GetKeyFromName(mgr.getString("keySay", "Chat").c_str());
pMain->keyChatMode = SDL_GetKeyFromName(mgr.getString("keyChatMode", "Chat").c_str());
pMain->mChat = new GUIChat(chatX, chatY, chatW, chatH);
pMain->getChatBox()->SetDelay(chatDelay);
mgr.mUserSettings = saveUserSettings;
mgr.mDefaultSettings = saveDefaultSettings;
mgr.mChangedSettings = saveChangedSettings;
//pMain->mGUILogin = new GUILogin();
const MWBase::Environment &environment = MWBase::Environment::get();
environment.getStateManager()->newGame(true);
}
void Main::Destroy()
{
assert(pMain);
delete pMain->mChat;
delete pMain;
pMain = 0;
}
void Main::Frame(float dt)
{
const MWBase::Environment &environment = MWBase::Environment::get();
if (environment.getWindowManager()->containsMode(MWGui::GM_MainMenu))
{
//environment.getWindowManager()->exitCurrentGuiMode();
}
get().getNetworking()->Update();
Players::Update(dt);
get().UpdateWorld(dt);
get().getChatBox()->Update(dt);
}
void Main::UpdateWorld(float dt) const
{
if(!mLocalPlayer->CharGenThread())
return;
if(!mNetworking->isConnected())
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWBase::Environment::get().getMechanicsManager()->toggleAI();
(*mLocalPlayer->Npc()) = *player.get<ESM::NPC>()->mBase;
mLocalPlayer->updateAttributesAndSkills();
mNetworking->Connect(server, port);
player.getClass().getCreatureStats(player).getSpells().add("fireball");
mLocalPlayer->updateBaseStats(true);
mChat->setVisible(true);
}
else
mLocalPlayer->Update();
}
const Main &Main::get()
{
return *pMain;
}
Networking *Main::getNetworking() const
{
return mNetworking;
}
LocalPlayer *Main::getLocalPlayer() const
{
return mLocalPlayer;
}
GUIChat *Main::getChatBox() const
{
return mChat;
}
GUILogin *Main::getGUILogin() const
{
return mGUILogin;
}
void Main::PressedKey(int key)
{
if(pMain == nullptr || get().getChatBox() == nullptr) return;
if(key == get().keyChatMode)
get().getChatBox()->PressedChatMode();
else if(key == get().keySay)
get().getChatBox()->PressedSay();
}

@ -0,0 +1,46 @@
#include <apps/openmw/mwworld/ptr.hpp>
#include "Networking.hpp"
#include "LocalPlayer.hpp"
#include "GUIChat.hpp"
#include "GUILogin.hpp"
namespace mwmp
{
class Main
{
public:
Main();
~Main();
static void Create();
static void Destroy();
static const Main &get();
static void Frame(float dt);
static void PressedKey(int key);
Networking *getNetworking() const;
LocalPlayer *getLocalPlayer() const;
GUIChat *getChatBox() const;
GUILogin *getGUILogin() const;
void UpdateWorld(float dt) const;
private:
Main (const Main&);
///< not implemented
Main& operator= (const Main&);
///< not implemented
static Main *pMain;
Networking *mNetworking;
LocalPlayer *mLocalPlayer;
GUIChat *mChat;
GUILogin *mGUILogin;
std::string server;
unsigned short port;
int keySay;
int keyChatMode;
};
}

@ -1,117 +1,561 @@
//
// Created by koncord on 01.01.16.
// Created by koncord on 04.01.16.
//
#include <stdexcept>
#include <iostream>
#include <string>
#include <components/esm/cellid.hpp>
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwbase/environment.hpp>
#include <apps/openmw/mwworld/cellstore.hpp>
#include <apps/openmw/mwclass/npc.hpp>
#include <apps/openmw/mwmechanics/npcstats.hpp>
#include <apps/openmw/mwworld/inventorystore.hpp>
#include <apps/openmw/mwmechanics/combat.hpp>
#include "Networking.hpp"
#include <cassert>
#include <apps/openmw/mwworld/manualref.hpp>
#include <apps/openmw/mwmechanics/aitravel.hpp>
#include "../mwbase/environment.hpp"
#include "../mwstate/statemanagerimp.hpp"
#include "../mwinput/inputmanagerimp.hpp"
#include "../mwscript/scriptmanagerimp.hpp"
#include "../mwgui/windowmanagerimp.hpp"
#include "../mwworld/worldimp.hpp"
#include "../mwworld/ptr.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/customdata.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwclass/npc.hpp"
#include "../mwclass/creature.hpp"
#include "../mwmechanics/mechanicsmanagerimp.hpp"
#include "../mwmechanics/aistate.hpp"
#include "Player.hpp"
#include "DedicatedPlayer.hpp"
#include "Main.hpp"
using namespace mwmp;
using namespace std;
using namespace mwmp;
Main *Main::pMain = 0;
Main::Main()
Networking::Networking(): peer(RakNet::RakPeerInterface::GetInstance()), controller(peer)
{
std::cout << "Main::Main" << std::endl;
RakNet::SocketDescriptor sd;
sd.port=0;
RakNet::StartupResult b = peer->Startup(1,&sd, 1);
RakAssert(b==RAKNET_STARTED);
controller.SetStream(0, &bsOut);
connected = 0;
}
Main::~Main()
Networking::~Networking()
{
std::cout << "Main::~Main" << std::endl;
peer->Shutdown(100);
peer->CloseConnection(peer->GetSystemAddressFromIndex(0), true, 0);
RakNet::RakPeerInterface::DestroyInstance(peer);
}
void Main::Create()
void Networking::Update()
{
assert(!pMain);
pMain = new Main();
const MWBase::Environment &environment = MWBase::Environment::get();
environment.getStateManager()->newGame(true);
RakNet::Packet *packet;
for (packet=peer->Receive(); packet; peer->DeallocatePacket(packet), packet=peer->Receive())
{
switch (packet->data[0])
{
case ID_REMOTE_DISCONNECTION_NOTIFICATION:
printf("Another client has disconnected.\n");
break;
case ID_REMOTE_CONNECTION_LOST:
printf("Another client has lost the connection.\n");
break;
case ID_REMOTE_NEW_INCOMING_CONNECTION:
printf("Another client has connected.\n");
break;
case ID_CONNECTION_REQUEST_ACCEPTED:
printf("Our connection request has been accepted.\n");
break;
case ID_NEW_INCOMING_CONNECTION:
printf("A connection is incoming.\n");
break;
case ID_NO_FREE_INCOMING_CONNECTIONS:
printf("The server is full.\n");
MWBase::Environment::get().getStateManager()->requestQuit();
break;
case ID_DISCONNECTION_NOTIFICATION:
printf("We have been disconnected.\n");
MWBase::Environment::get().getStateManager()->requestQuit();
break;
case ID_CONNECTION_LOST:
printf("Connection lost.\n");
MWBase::Environment::get().getStateManager()->requestQuit();
break;
case ID_CUSTOM_MESSAGE:
ReciveMessage(packet);
break;
default:
printf("Message with identifier %i has arrived.\n", packet->data[0]);
break;
}
}
}
void Main::Destroy()
void Networking::SendData(RakNet::BitStream *bs)
{
Player::CleanUp();
delete pMain;
peer->Send(bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, serverAddr, false);
}
void Main::Frame(float dt)
void Networking::Connect(const std::string &ip, unsigned short port)
{
const MWBase::Environment &environment = MWBase::Environment::get();
if (environment.getWindowManager()->containsMode(MWGui::GM_MainMenu))
RakNet::SystemAddress master;
master.SetBinaryAddress(ip.c_str());
master.SetPortHostOrder(port);
const char passw[8] = "1234567";
if (peer->Connect(master.ToString(false), master.GetPort(), passw, sizeof(passw), 0, 0, 3, 500, 0) != RakNet::CONNECTION_ATTEMPT_STARTED)
{
//environment.getWindowManager()->exitCurrentGuiMode();
cout << "Connection attempt failed." << endl;
MWBase::Environment::get().getStateManager()->requestQuit();
}
MWBase::World *world = MWBase::Environment::get().getWorld();
MWBase::ScriptManager *script = MWBase::Environment::get().getScriptManager();
MWWorld::Ptr player = world->getPlayerPtr();
float x = player.getRefData().getPosition().pos[0];
float y = player.getRefData().getPosition().pos[1];
float z = player.getRefData().getPosition().pos[2];
float rot_x = player.getRefData().getPosition().rot[0];
float rot_y = player.getRefData().getPosition().rot[1];
float rot_z = player.getRefData().getPosition().rot[2];
static bool connected = true;
if (connected)
bool queue = true;
while(queue)
{
connected = false;
world->toggleGodMode();
// create item
MWWorld::CellStore* store = player.getCell();
for (RakNet::Packet *packet = peer->Receive(); packet; peer->DeallocatePacket(
packet), packet = peer->Receive())
{
switch (packet->data[0])
{
case ID_CONNECTION_ATTEMPT_FAILED:
{
cerr << "Connection failed." << endl;
MWBase::Environment::get().getStateManager()->requestQuit();
queue = false;
break;
}
case ID_INVALID_PASSWORD:
{
cerr << "Connection failed. Different versions of client or server." << endl
<< "Ask your server administrator for resolve this problem." << endl;
MWBase::Environment::get().getStateManager()->requestQuit();
queue = false;
break;
}
case ID_CONNECTION_REQUEST_ACCEPTED:
{
serverAddr = packet->systemAddress;
connected = true;
queue = false;
Player::CreatePlayer(1, "Ashot the Orc", "Orc", "b_n_orc_m_head_01", "b_n_orc_m_hair_01");
Player *ref = Player::GetPlayer(1);
GetPacket(ID_GAME_BASE_INFO)->Send(getLocalPlayer());
ref->getPtr().getCellRef().setPosition(player.getRefData().getPosition());
world->moveObject(ref->getPtr(),player.getCell(), x, y, z); // move to player
break;
}
case ID_DISCONNECTION_NOTIFICATION:
throw runtime_error("ID_DISCONNECTION_NOTIFICATION.\n");
case ID_CONNECTION_BANNED:
throw runtime_error("ID_CONNECTION_BANNED.\n");
case ID_CONNECTION_LOST:
throw runtime_error("ID_CONNECTION_LOST.\n");
default:
printf("Connection message with identifier %i has arrived in initialization.\n", packet->data[0]);
}
}
}
Player *ref = Player::GetPlayer(1);
}
void Networking::ReciveMessage(RakNet::Packet *packet)
{
RakNet::RakNetGUID id;
ref->Move(player.getRefData().getPosition(), player.getCell());
if(packet->length < 3)
return;
//cout << "x:\t" << x << "\ty:\t" << y << "\tz:\t" << z<< endl;
RakNet::BitStream bsIn(&packet->data[2], packet->length, false);
bsIn.Read(id);
//ref->getPtr().getRefData().
//loc.getRefData().setPosition(player.getRefData().getPosition());
MWMechanics::NpcStats *npcStats = &ref->getPtr().getClass().getNpcStats(ref->getPtr());
npcStats->setHealth(1000);
npcStats->setMagicka(1000);
npcStats->setFatigue(1000);
if(npcStats->isDead())
npcStats->resurrect();
npcStats->setAttacked(false);
DedicatedPlayer *pl = 0;
static RakNet::RakNetGUID myid = getLocalPlayer()->guid;
if(id != myid)
pl = Players::GetPlayer(id);
npcStats->setBaseDisposition(255);
BasePacket *myPacket = controller.GetPacket(packet->data[1]);
if(player.getClass().getNpcStats(ref->getPtr()).getHealth().getCurrent() <= 0)
switch(packet->data[1])
{
case ID_HANDSHAKE:
{
(*getLocalPlayer()->GetPassw()) = "SuperPassword";
myPacket->Send(getLocalPlayer(), serverAddr);
break;
}
case ID_GAME_BASE_INFO:
{
if(id == myid)
{
cout << "TEST: " << packet->length << endl;
if(packet->length == myPacket->headerSize())
{
cout << "ID_GAME_BASE_INFO request only" << endl;
myPacket->Send(getLocalPlayer(), serverAddr);
}
else
{
myPacket->Packet(&bsIn, getLocalPlayer(), false);
cout << "ID_GAME_BASE_INFO" << endl;
getLocalPlayer()->updateChar();
}
}
else
{
if(pl == 0)
pl = Players::NewPlayer(id);
myPacket->Packet(&bsIn, pl, false);
Players::CreatePlayer(id);
}
break;
}
case ID_GAME_UPDATE_POS:
{
if(id == myid)
getLocalPlayer()->updatePosition(true);
else if(pl != 0)
myPacket->Packet(&bsIn, pl, false);
break;
}
case ID_USER_MYID:
{
cout << "ID_USER_MYID" << endl;
myid = id;
getLocalPlayer()->guid = id;
break;
}
case ID_USER_DISCONNECTED:
{
if(id == myid)
MWBase::Environment::get().getStateManager()->requestQuit();
else if(pl != 0)
Players::DisconnectPlayer(id);
}
case ID_GAME_UPDATE_EQUIPED:
{
if(id == myid)
{
getLocalPlayer()->updateInventory(true);
myPacket->Send(getLocalPlayer(), serverAddr);
}
else if (pl != 0)
{
myPacket->Packet(&bsIn, pl, false);
pl->UpdateInventory();
}
break;
}
case ID_GAME_UPDATE_SKILLS:
{
if(id == myid)
{
getLocalPlayer()->updateAttributesAndSkills(true);
myPacket->Send(getLocalPlayer(), serverAddr);
}
else if (pl != 0)
{
myPacket->Packet(&bsIn, pl, false);
MWMechanics::SkillValue skillValue;
MWMechanics::AttributeValue attributeValue;
for (int i = 0; i < PacketAttributesAndStats::StatsCount; ++i)
{
skillValue.readState(pl->NpcStats()->mSkills[i]);
pl->getPtr().getClass().getNpcStats(pl->getPtr()).setSkill(i, skillValue);
}
for (int i = 0; i < PacketAttributesAndStats::AttributesCount; ++i)
{
attributeValue.readState(pl->CreatureStats()->mAttributes[i]);
pl->getPtr().getClass().getCreatureStats(pl->getPtr()).setAttribute(i, attributeValue);
}
}
break;
}
case ID_GAME_ATTACK:
{
if(pl != 0)
{
myPacket->Packet(&bsIn, pl, false);
cout << "Player: " << pl->Npc()->mName << " pressed: " << (pl->GetAttack()->pressed == 1) << endl;
if(pl->GetAttack()->pressed == 0)
{
cout << "success: " << (pl->GetAttack()->success == 1);
if(pl->GetAttack()->success == 1)
cout << " damage: " << pl->GetAttack()->damage;
cout << endl;
}
MWMechanics::CreatureStats &stats = pl->getPtr().getClass().getNpcStats(pl->getPtr());
stats.getSpells().setSelectedSpell(pl->GetAttack()->refid);
MWWorld::Ptr victim;
if(pl->GetAttack()->target == getLocalPlayer()->guid)
victim = MWBase::Environment::get().getWorld()->getPlayerPtr();
else if(Players::GetPlayer(pl->GetAttack()->target) != 0)
victim = Players::GetPlayer(pl->GetAttack()->target)->getPtr();
MWWorld::Ptr attacker;
attacker = pl->getPtr();
// Get the weapon used (if hand-to-hand, weapon = inv.end())
if(*pl->DrawState() == 1)
{
MWWorld::InventoryStore &inv = attacker.getClass().getInventoryStore(attacker);
MWWorld::ContainerStoreIterator weaponslot = inv.getSlot(
MWWorld::InventoryStore::Slot_CarriedRight);
MWWorld::Ptr weapon = ((weaponslot != inv.end()) ? *weaponslot : MWWorld::Ptr());
if (!weapon.isEmpty() && weapon.getTypeName() != typeid(ESM::Weapon).name())
weapon = MWWorld::Ptr();
bool healthdmg;
if (!weapon.isEmpty())
healthdmg = true;
else
{
MWMechanics::CreatureStats &otherstats = victim.getClass().getCreatureStats(victim);
healthdmg = otherstats.isParalyzed() || otherstats.getKnockedDown();
}
if (victim.mRef != 0)
{
if (!weapon.isEmpty())
MWMechanics::blockMeleeAttack(attacker, victim, weapon, pl->GetAttack()->damage, 1);
pl->getPtr().getClass().onHit(victim, pl->GetAttack()->damage, healthdmg, weapon, attacker,
pl->GetAttack()->success);
}
}
else
{
cout << "SpellId: " << pl->GetAttack()->refid << endl;
}
}
break;
}
case ID_GAME_UPDATE_BASESTATS:
{
if(id == myid)
{
getLocalPlayer()->updateBaseStats(true);
myPacket->Send(getLocalPlayer(), serverAddr);
}
else if (pl != 0)
{
myPacket->Packet(&bsIn, pl, false);
MWMechanics::DynamicStat<float> value;
value.readState(pl->CreatureStats()->mDynamic[0]);
pl->getPtr().getClass().getCreatureStats(pl->getPtr()).setHealth(value);
value.readState(pl->CreatureStats()->mDynamic[1]);
pl->getPtr().getClass().getCreatureStats(pl->getPtr()).setMagicka(value);
value.readState(pl->CreatureStats()->mDynamic[2]);
pl->getPtr().getClass().getCreatureStats(pl->getPtr()).setFatigue(value);
}
break;
}
case ID_GAME_DIE:
{
printf("ID_GAME_DIE\n");
if(id == myid)
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWMechanics::DynamicStat<float> health = player.getClass().getCreatureStats(player).getHealth();
health.setCurrent(0);
player.getClass().getCreatureStats(player).setHealth(health);
myPacket->Send(getLocalPlayer(), serverAddr);
}
else if(pl != 0)
{
printf("attempt to kill %s\n", pl->Npc()->mName.c_str());
MWMechanics::DynamicStat<float> health;
pl->CreatureStats()->mDead = true;
health.readState(pl->CreatureStats()->mDynamic[0]);
health.setCurrent(0);
health.writeState(pl->CreatureStats()->mDynamic[0]);
pl->getPtr().getClass().getCreatureStats(pl->getPtr()).setHealth(health);
}
break;
}
case ID_GAME_RESURRECT:
{
if (id == myid)
{
MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
player.getClass().getCreatureStats(player).resurrect();
ESM::Position pos;
MWBase::Environment::get().getWorld()->findInteriorPosition("ToddTest", pos);
MWBase::Environment::get().getWorld()->changeToInteriorCell("ToddTest", pos);
(*getLocalPlayer()->Position()) = pos;
(*getLocalPlayer()->GetCell()) = *player.getCell()->getCell();
myPacket->Send(getLocalPlayer(), serverAddr);
getLocalPlayer()->updateBaseStats(true);
controller.GetPacket(ID_GAME_UPDATE_BASESTATS)->Send(getLocalPlayer(), serverAddr);
}
else if (pl != 0)
{
pl->CreatureStats()->mDead = false;
if (pl->CreatureStats()->mDynamic[0].mMod < 1)
pl->CreatureStats()->mDynamic[0].mMod = 1;
pl->CreatureStats()->mDynamic[0].mCurrent = pl->CreatureStats()->mDynamic[0].mMod;
pl->getPtr().getClass().getCreatureStats(pl->getPtr()).resurrect();
MWMechanics::DynamicStat<float> health;
health.readState(pl->CreatureStats()->mDynamic[0]);
pl->getPtr().getClass().getCreatureStats(pl->getPtr()).setHealth(health);
}
break;
}
case ID_GAME_CELL:
{
if(id == myid)
{
myPacket->Packet(&bsIn, getLocalPlayer(), false);
if(!getLocalPlayer()->GetCell()->isExterior())
{
cout << "location: " << getLocalPlayer()->GetCell()->mName << endl;
MWBase::World *world = MWBase::Environment::get().getWorld();
ESM::Position pos;
world->findInteriorPosition(getLocalPlayer()->GetCell()->mName, pos);
world->changeToInteriorCell(getLocalPlayer()->GetCell()->mName, pos);
}
getLocalPlayer()->updateCell(true);
}
else if(pl != 0)
{
myPacket->Packet(&bsIn, pl, false);
pl->updateCell();
}
break;
}
case ID_GAME_DRAWSTATE:
{
if(id == myid)
getLocalPlayer()->updateDrawStateAndFlags(true);
else if(pl != 0)
{
myPacket->Packet(&bsIn, pl, false);
pl->UpdateDrawState();
}
break;
}
case ID_CHAT_MESSAGE:
{
std::string message;
if(id == myid)
{
myPacket->Packet(&bsIn, getLocalPlayer(), false);
message = *getLocalPlayer()->ChatMessage();
}
else if(pl != 0)
{
myPacket->Packet(&bsIn, pl, false);
message = *pl->ChatMessage();
}
Main::get().getChatBox()->print(message);
break;
}
case ID_GAME_CHARGEN:
{
if(id == myid)
{
myPacket->Packet(&bsIn, getLocalPlayer(), false);
}
break;
}
case ID_GAME_ATTRIBUTE:
{
BasePlayer *__pl = nullptr;
MWWorld::Ptr __pl_ptr;
if (id == myid)
{
__pl = getLocalPlayer();
__pl_ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
}
else if (pl != 0)
{
__pl = pl;
__pl_ptr = pl->getPtr();
}
else
return;
MWMechanics::AttributeValue attributeValue;
myPacket->Packet(&bsIn, __pl, false);
for (int i = 0; i < PacketAttributesAndStats::AttributesCount; ++i)
{
attributeValue.readState(__pl->CreatureStats()->mAttributes[i]);
__pl_ptr.getClass().getCreatureStats(__pl_ptr).setAttribute(i, attributeValue);
}
break;
}
case ID_GAME_SKILL:
{
BasePlayer *__pl = nullptr;
MWWorld::Ptr __pl_ptr;
if (id == myid)
{
__pl = getLocalPlayer();
__pl_ptr = MWBase::Environment::get().getWorld()->getPlayerPtr();
}
else if (pl != 0)
{
__pl = pl;
__pl_ptr = pl->getPtr();
}
else
return;
MWMechanics::SkillValue skillValue;
myPacket->Packet(&bsIn, __pl, false);
for (int i = 0; i < PacketAttributesAndStats::StatsCount; ++i)
{
skillValue.readState(__pl->NpcStats()->mSkills[i]);
__pl_ptr.getClass().getNpcStats(__pl_ptr).setSkill(i, skillValue);
printf("skill %d, value %d\n", i, skillValue.getBase());
}
break;
}
default:
printf("Custom message with identifier %i has arrived in initialization.\n", packet->data[1]);
}
}
BasePacket *Networking::GetPacket(RakNet::MessageID id)
{
return controller.GetPacket(id);
}
void Main::UpdateWorld(float dt)
LocalPlayer *Networking::getLocalPlayer()
{
return mwmp::Main::get().getLocalPlayer();
}
bool Networking::isDedicatedPlayer(const MWWorld::Ptr &ptr)
{
if(ptr.mRef == 0)
return 0;
DedicatedPlayer *pl = Players::GetPlayer(ptr);
return pl != 0;
}
bool Networking::Attack(const MWWorld::Ptr &ptr)
{
DedicatedPlayer *pl = Players::GetPlayer(ptr);
if(pl == 0)
return false;
return pl->GetAttack()->pressed;
}
bool Networking::isConnected()
{
return connected;
}

@ -1,17 +1,63 @@
//
// Created by koncord on 04.01.16.
//
#ifndef OPENMW_NETWORKING_HPP
#define OPENMW_NETWORKING_HPP
#include <RakPeerInterface.h>
#include <BitStream.h>
#include <string>
#include <components/openmw-mp/NetworkMessages.hpp>
#include <components/openmw-mp/Packets/PacketPosition.hpp>
#include <components/openmw-mp/Packets/PacketBaseInfo.hpp>
#include <components/openmw-mp/Packets/PacketEquiped.hpp>
#include <components/openmw-mp/Packets/PacketAttributesAndStats.hpp>
#include <components/openmw-mp/Packets/PacketAttack.hpp>
#include <components/openmw-mp/Packets/PacketMainStats.hpp>
#include <components/openmw-mp/Packets/PacketResurrect.hpp>
#include <components/openmw-mp/Packets/PacketDie.hpp>
#include <components/openmw-mp/Packets/PacketCell.hpp>
#include <components/openmw-mp/Packets/PacketDrawState.hpp>
#include <components/openmw-mp/PacketsController.hpp>
namespace mwmp
{
class Main
class LocalPlayer;
class Networking
{
public:
Main();
~Main();
Networking();
~Networking();
void Connect(const std::string& ip, unsigned short port);
void Update();
void SendData(RakNet::BitStream *bitStream);
BasePacket *GetPacket(RakNet::MessageID id);
bool isDedicatedPlayer(const MWWorld::Ptr &ptr);
bool Attack(const MWWorld::Ptr &ptr);
RakNet::SystemAddress serverAddress()
{
return serverAddr;
}
bool isConnected();
static void Create();
static void Destroy();
static void Frame(float dt);
static void UpdateWorld(float dt);
private:
static Main *pMain;
bool connected;
RakNet::RakPeerInterface *peer;
RakNet::SystemAddress serverAddr;
RakNet::BitStream bsOut;
PacketsController controller;
void ReciveMessage(RakNet::Packet *packet);
LocalPlayer *getLocalPlayer();
};
}
#endif //OPENMW_NETWORKING_HPP

@ -1,152 +0,0 @@
//
// Created by koncord on 02.01.16.
//
#include <bits/stringfwd.h>
#include <apps/openmw/mwmechanics/aitravel.hpp>
#include "../mwbase/environment.hpp"
#include "../mwstate/statemanagerimp.hpp"
#include "../mwinput/inputmanagerimp.hpp"
#include "../mwgui/windowmanagerimp.hpp"
#include "../mwworld/worldimp.hpp"
#include "../mwworld/ptr.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/customdata.hpp"
#include "../mwclass/npc.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "Player.hpp"
using namespace mwmp;
std::map<int, Player *> Player::players;
Player::~Player()
{
delete reference;
}
MWWorld::Ptr Player::getPtr()
{
MWBase::World *world = MWBase::Environment::get().getWorld();
return world->getPtr(reference->getPtr().get<ESM::NPC>()->mBase->mId, false);
}
Player::Player()
{
}
void Player::CreatePlayer(int id, const std::string &name, const std::string &race, const std::string &head,
const std::string &hair)
{
MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
ESM::NPC dedic_pl = *player.get<ESM::NPC>()->mBase;
dedic_pl.mRace = race;
dedic_pl.mHead = head;
dedic_pl.mHair = hair;
dedic_pl.mName = name;
if (players[id] == 0)
{
dedic_pl.mId = "Dedicated Player";
std::string recid = world->createRecord(dedic_pl)->mId;
players[id] = new Player();
Player *_player = players[id];
_player->reference = new MWWorld::ManualRef(world->getStore(), recid, 1);
// temporary spawn character in ToddTest cell
ESM::Position pos;
world->findInteriorPosition("ToddTest", pos);
MWWorld::CellStore *store = world->getInterior("ToddTest");
MWWorld::Ptr tmp = world->safePlaceObject(_player->reference->getPtr(), store, pos);
_player->ptr = world->getPtr(tmp.get<ESM::NPC>()->mBase->mId, false);
}
else
{
dedic_pl.mId = players[id]->reference->getPtr().get<ESM::NPC>()->mBase->mId;
MWWorld::ESMStore *store = const_cast<MWWorld::ESMStore *>(&world->getStore());
MWWorld::Store<ESM::NPC> *esm_store = const_cast<MWWorld::Store<ESM::NPC> *> (&store->get<ESM::NPC>());
esm_store->insert(dedic_pl);
}
players[id]->active = true;
world->enable(players[id]->reference->getPtr());
}
void Player::CleanUp()
{
for(std::map <int, Player*>::iterator it = players.begin(); it != players.end(); it++)
delete it->second;
}
void Player::DestroyPlayer(int id)
{
if (players[id]->active)
{
players[id]->active = false;
MWBase::World *world = MWBase::Environment::get().getWorld();
world->disable(players[id]->getPtr());
//move player to toddTest
ESM::Position pos;
world->findInteriorPosition("ToddTest", pos);
MWWorld::CellStore *store = world->getInterior("ToddTest");
players[id]->ptr = world->moveObject(players[id]->getPtr(), store, pos.pos[0], pos.pos[1], pos.pos[2]);
}
}
Player *Player::GetPlayer(int id)
{
return players[id];
}
MWWorld::Ptr Player::getLiveCellPtr()
{
return reference->getPtr();
}
MWWorld::ManualRef *Player::getRef()
{
return reference;
}
void Player::Move(ESM::Position pos, MWWorld::CellStore *cell)
{
if (!active) return;
MWWorld::Ptr myPtr = getPtr();
ESM::Position ref_pos = myPtr.getRefData().getPosition();
MWBase::World *world = MWBase::Environment::get().getWorld();
float xx = pos.pos[0] - ref_pos.pos[0];
float yy = pos.pos[1] - ref_pos.pos[1];
double d = sqrt((xx * xx) + (yy * yy));
MWMechanics::AiSequence *aiSequence = &myPtr.getClass().getCreatureStats(myPtr).getAiSequence();
if (d > 10.0 && d < 150.0)
{
MWMechanics::AiTravel travelPackage(pos.pos[0], pos.pos[1], pos.pos[2]);
aiSequence->clear();
aiSequence->stack(travelPackage, myPtr);
}
else if (d == 0.0)
aiSequence->clear();
else if (d >= 150.0)
world->moveObject(myPtr, cell, pos.pos[0], pos.pos[1], pos.pos[2]);
world->rotateObject(myPtr, pos.rot[0], pos.rot[1], pos.rot[2]);
}

@ -1,40 +0,0 @@
//
// Created by koncord on 02.01.16.
//
#ifndef OPENMW_PLAYER_HPP
#define OPENMW_PLAYER_HPP
#include <components/esm/loadnpc.hpp>
#include <apps/openmw/mwworld/manualref.hpp>
#include <map>
#include <apps/openmw/mwmechanics/aisequence.hpp>
namespace mwmp
{
class Player
{
public:
MWWorld::Ptr getPtr();
MWWorld::Ptr getLiveCellPtr();
MWWorld::ManualRef* getRef();
void Move(ESM::Position pos, MWWorld::CellStore* cell);
static void CreatePlayer(int id, const std::string& name, const std::string &race, const std::string &head, const std::string &hair);
static void DestroyPlayer(int id);
static void CleanUp();
static Player *GetPlayer(int id);
private:
Player();
~Player();
int id;
bool active;
MWWorld::ManualRef* reference;
MWWorld::Ptr ptr;
private:
static std::map <int, Player*> players;
};
}
#endif //OPENMW_PLAYER_HPP

@ -0,0 +1,79 @@
# - Try to find Terra
# Once done this will define
#
# Terra_FOUND - system has Terra
# Terra_INCLUDES - the Terra include directory
# Terra_LIBRARY - Link these to use Terra
if(Win32)
SET(Terra_LIBRARY_Name terra.so)
else(Win32)
SET(Terra_LIBRARY_Name terra)
endif(Win32)
FIND_LIBRARY (Terra_LIBRARY_RELEASE NAMES ${Terra_LIBRARY_Name}
PATHS
ENV LD_LIBRARY_PATH
ENV LIBRARY_PATH
/usr/lib64
/usr/lib
/usr/local/lib64
/usr/local/lib
/opt/local/lib
${Terra_ROOT}/lib
${Terra_DIR}/lib
)
FIND_LIBRARY (Terra_LIBRARY_DEBUG NAMES ${Terra_LIBRARY_Name_Debug}
PATHS
ENV LD_LIBRARY_PATH
ENV LIBRARY_PATH
/usr/lib64
/usr/lib
/usr/local/lib64
/usr/local/lib
/opt/local/lib
${Terra_ROOT}/lib
${Terra_DIR}/lib
)
FIND_PATH (Terra_INCLUDES terra/terra.h
ENV CPATH
/usr/include
/usr/local/include
/opt/local/include
${Terra_ROOT}/include
${Terra_DIR}/include
)
IF(Terra_INCLUDES AND Terra_LIBRARY_RELEASE)
SET(Terra_FOUND TRUE)
ENDIF(Terra_INCLUDES AND Terra_LIBRARY_RELEASE)
IF(NOT Terra_LIBRARY_DEBUG)
SET(Terra_LIBRARY_DEBUG ${Terra_LIBRARY_RELEASE})
ENDIF()
IF(Terra_FOUND)
SET(Terra_INCLUDES ${Terra_INCLUDES})
find_package(ZLIB REQUIRED)
IF (CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE)
SET(Terra_LIBRARY optimized ${Terra_LIBRARY_RELEASE} debug ${Terra_LIBRARY_DEBUG} ${ZLIB_LIBRARIES} dl tinfo)
ELSE()
# if there are no configuration types and CMAKE_BUILD_TYPE has no value
# then just use the release libraries
SET(Terra_LIBRARY ${Terra_LIBRARY_RELEASE} ${ZLIB_LIBRARIES} dl tinfo)
ENDIF()
IF(NOT Terra_FIND_QUIETLY)
MESSAGE(STATUS "Found Terra: ${Terra_LIBRARIES}")
ENDIF(NOT Terra_FIND_QUIETLY)
ELSE(Terra_FOUND)
IF(Terra_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find Terra")
ENDIF(Terra_FIND_REQUIRED)
ENDIF(Terra_FOUND)

@ -138,6 +138,12 @@ add_component_dir (version
version
)
add_component_dir (openmw-mp
PacketsController
Packets/BasePacket Packets/PacketBaseInfo Packets/PacketPosition Packets/PacketEquiped Packets/PacketAttributesAndStats
Packets/PacketAttack Packets/PacketMainStats Packets/PacketCell Packets/PacketDrawState Packets/PacketChatMessage
Packets/PacketCharGen Packets/PacketAttribute Packets/PacketSkill Packets/PacketHandshake)
set (ESM_UI ${CMAKE_SOURCE_DIR}/files/ui/contentselector.ui
)

@ -0,0 +1,148 @@
//
// Created by koncord on 07.01.16.
//
#ifndef OPENMW_BASEPLAYER_HPP
#define OPENMW_BASEPLAYER_HPP
#include <components/esm/npcstats.hpp>
#include <components/esm/loadcell.hpp>
#include <components/esm/loadnpc.hpp>
#include <components/esm/creaturestats.hpp>
#include <RakNetTypes.h>
namespace mwmp
{
class Attack
{
public:
RakNet::RakNetGUID target;
RakNet::RakNetGUID attacker;
char type; // 0 - melee, 1 - magic, 2 - throwable
std::string refid; // id of spell (e.g. "fireball")
char success;
char block;
float damage;
char pressed;
char knockdown;
};
struct Item
{
std::string refid;
int count;
};
class BasePlayer
{
public:
struct CGStage
{
int current, end;
};
BasePlayer(RakNet::RakNetGUID guid) : guid(guid)
{
}
BasePlayer()
{
}
virtual ESM::Position *Position()
{
return &pos;
}
virtual ESM::NPC *Npc()
{
return &npc;
}
virtual ESM::NpcStats *NpcStats()
{
return &npcStats;
}
virtual ESM::CreatureStats *CreatureStats()
{
return &creatureStats;
}
virtual unsigned int *MovementFlags()
{
return &movementFlags;
}
virtual ESM::Cell *GetCell()
{
return &cell;
}
virtual Item *EquipedItem(int id)
{
if(id >= 18) return &equipedItems[18];
return &equipedItems[id];
}
virtual char *MovementAnim()
{
return &movementAnim;
}
virtual char *DrawState()
{
return &drawState;
}
virtual ESM::Position *Dir()
{
return &dir;
}
virtual Attack *GetAttack()
{
return &attack;
}
virtual std::string *BirthSign()
{
return &birthSign;
}
virtual std::string *ChatMessage()
{
return &chatMessage;
}
virtual CGStage *CharGenStage()
{
return &stage;
}
virtual std::string *GetPassw()
{
return &passw;
}
RakNet::RakNetGUID guid;
protected:
ESM::Position pos;
ESM::Position dir;
ESM::Cell cell;
ESM::NPC npc;
ESM::NpcStats npcStats;
ESM::CreatureStats creatureStats;
Item equipedItems[19];
unsigned int movementFlags;
char movementAnim;
char drawState;
Attack attack;
std::string birthSign;
std::string chatMessage;
CGStage stage;
std::string passw;
};
}
#endif //OPENMW_BASEPLAYER_HPP

@ -0,0 +1,43 @@
//
// Created by koncord on 05.01.16.
//
#ifndef OPENMW_NETWORKMESSAGES_HPP
#define OPENMW_NETWORKMESSAGES_HPP
#include <MessageIdentifiers.h>
enum GameMessages
{
ID_CUSTOM_MESSAGE = ID_USER_PACKET_ENUM+1
};
enum MyGameMesages
{
ID_GAME_BASE_INFO = 0,
ID_GAME_CHARGEN,
ID_GAME_UPDATE_POS,
ID_GAME_UPDATE_BASESTATS,
ID_GAME_UPDATE_SKILLS,
ID_GAME_ATTACK,
ID_USER_MYID,
ID_GAME_UPDATE_EQUIPED,
ID_USER_DISCONNECTED,
ID_GAME_CREATE_PROJECTILE,
ID_GAME_CAST,
ID_GAME_DIE,
ID_GAME_RESURRECT,
ID_CHAT_MESSAGE,
ID_GAME_CELL,
ID_GAME_DRAWSTATE,
ID_GAME_STATS,
ID_GAME_ATTRIBUTE,
ID_GAME_SKILL,
ID_GAME_CHARCLASS,
ID_GAME_SKILLPRIORITY,
ID_HANDSHAKE
};
#endif //OPENMW_NETWORKMESSAGES_HPP

@ -0,0 +1,82 @@
//
// Created by koncord on 05.01.16.
//
#include <components/openmw-mp/NetworkMessages.hpp>
#include <PacketPriority.h>
#include <RakPeer.h>
#include "BasePacket.hpp"
using namespace mwmp;
void BasePacket::Packet(RakNet::BitStream *bs, BasePlayer *player, bool send)
{
this->player = player;
this->bs = bs;
if(send)
{
bs->Write((RakNet::MessageID) ID_CUSTOM_MESSAGE);
bs->Write((RakNet::MessageID) packetID);
bs->Write(player->guid);
}
}
BasePacket::BasePacket(RakNet::RakPeerInterface *peer)
{
packetID = 0;
priority = HIGH_PRIORITY;
reliability = RELIABLE_ORDERED;
this->peer = peer;
}
BasePacket::~BasePacket()
{
}
void BasePacket::Send(BasePlayer *player, RakNet::AddressOrGUID destination)
{
bsSend->ResetWritePointer();
Packet(bsSend, player, true);
peer->Send(bsSend, priority, reliability, 0, destination, false);
}
void BasePacket::Send(BasePlayer *player, bool toOther)
{
bsSend->ResetWritePointer();
Packet(bsSend, player, true);
peer->Send(bsSend, priority, reliability, 0, player->guid, toOther);
}
void BasePacket::Read(BasePlayer *player)
{
Packet(bsRead, player, false);
}
void BasePacket::SetReadStream(RakNet::BitStream *bitStream)
{
bsRead = bitStream;
}
void BasePacket::SetSendStream(RakNet::BitStream *bitStream)
{
bsSend = bitStream;
}
void BasePacket::RequestData(RakNet::RakNetGUID player)
{
bsSend->ResetWritePointer();
bsSend->Write((RakNet::MessageID) ID_CUSTOM_MESSAGE);
bsSend->Write((RakNet::MessageID) packetID);
bsSend->Write(player);
peer->Send(bsSend, HIGH_PRIORITY, RELIABLE_ORDERED, 0, player, false);
}
void BasePacket::SetStreams(RakNet::BitStream *inStream, RakNet::BitStream *outStream)
{
if(inStream != 0)
bsRead = inStream;
if(outStream != 0)
bsSend = outStream;
}

@ -0,0 +1,101 @@
//
// Created by koncord on 05.01.16.
//
#ifndef OPENMW_BASEPACKET_HPP
#define OPENMW_BASEPACKET_HPP
#include <string>
#include <RakNetTypes.h>
#include <BitStream.h>
#include <PacketPriority.h>
#include <components/openmw-mp/Base/BasePlayer.hpp>
namespace mwmp
{
class BasePacket
{
public:
BasePacket(RakNet::RakPeerInterface *peer);
~BasePacket();
virtual void Packet(RakNet::BitStream *bs, BasePlayer *player, bool send);
virtual void Send(BasePlayer *player, bool toOtherPlayers = true);
virtual void Send(BasePlayer *player, RakNet::AddressOrGUID destination);
virtual void Read(BasePlayer *player);
virtual void RequestData(RakNet::RakNetGUID player);
void SetReadStream(RakNet::BitStream *bitStream);
void SetSendStream(RakNet::BitStream *bitStream);
void SetStreams(RakNet::BitStream *inStream, RakNet::BitStream *outStream);
size_t headerSize()
{
return 10; // 10 == char + char + RakNetGUID (uint64_t)
}
protected:
template<class templateType>
void RW(templateType &data, unsigned int size, bool write)
{
if (write)
bs->Write(data, size);
else
bs->Read(data, size);
}
template<class templateType>
void RW(templateType &data, bool write)
{
if (write)
bs->Write(data);
else
bs->Read(data);
}
void RW(bool &data, bool write)
{
char _data;
if (write)
{
_data = data;
bs->Write(_data);
}
else
{
bs->Read(_data);
data = _data;
}
}
void RW(std::string &str, bool write)
{
if (write)
bs->Write(str.c_str());
else
{
char cstr[256];
bs->Read(cstr);
str = cstr;
}
}
protected:
BasePlayer *player;
unsigned char packetID;
PacketReliability reliability;
PacketPriority priority;
private:
RakNet::BitStream *bsRead, *bsSend, *bs;
RakNet::RakPeerInterface *peer;
};
}
#endif //OPENMW_BASEPACKET_HPP

@ -0,0 +1,29 @@
//
// Created by koncord on 13.01.16.
//
#include <components/openmw-mp/NetworkMessages.hpp>
#include "PacketAttack.hpp"
using namespace mwmp;
PacketAttack::PacketAttack(RakNet::RakPeerInterface *peer) : BasePacket(peer)
{
packetID = ID_GAME_ATTACK;
}
void PacketAttack::Packet(RakNet::BitStream *bs, mwmp::BasePlayer *player, bool send)
{
BasePacket::Packet(bs, player, send);
RW(player->GetAttack()->attacker, send);
RW(player->GetAttack()->target, send);
RW(player->GetAttack()->refid, send);
RW(player->GetAttack()->type, send);
RW(player->GetAttack()->success, send);
RW(player->GetAttack()->damage, send);
//
RW(player->GetAttack()->pressed, send);
RW(player->GetAttack()->knockdown, send);
RW(player->GetAttack()->block, send);
}

@ -0,0 +1,22 @@
//
// Created by koncord on 13.01.16.
//
#ifndef OPENMW_PACKETATTACK_HPP
#define OPENMW_PACKETATTACK_HPP
#include <components/openmw-mp/Packets/BasePacket.hpp>
namespace mwmp
{
class PacketAttack : public BasePacket
{
public:
PacketAttack(RakNet::RakPeerInterface *peer);
virtual void Packet(RakNet::BitStream *bs, BasePlayer *player, bool send);
};
}
#endif //OPENMW_PACKETATTACK_HPP

@ -0,0 +1,21 @@
//
// Created by koncord on 08.03.16.
//
#include "PacketAttribute.hpp"
#include <components/openmw-mp/NetworkMessages.hpp>
using namespace mwmp;
PacketAttribute::PacketAttribute(RakNet::RakPeerInterface *peer) : BasePacket(peer)
{
packetID = ID_GAME_ATTRIBUTE;
}
void PacketAttribute::Packet(RakNet::BitStream *bs, BasePlayer *player, bool send)
{
BasePacket::Packet(bs, player, send);
for(int i = 0; i < AttributesCount; ++i)
RW(player->CreatureStats()->mAttributes[i], send);
}

@ -0,0 +1,22 @@
//
// Created by koncord on 08.03.16.
//
#ifndef OPENMW_PACKETATTRIBUTE_HPP
#define OPENMW_PACKETATTRIBUTE_HPP
#include <components/openmw-mp/Packets/BasePacket.hpp>
namespace mwmp
{
class PacketAttribute : public BasePacket
{
public:
const static int AttributesCount = 8;
PacketAttribute(RakNet::RakPeerInterface *peer);
virtual void Packet(RakNet::BitStream *bs, BasePlayer *player, bool send);
};
}
#endif //OPENMW_PACKETATTRIBUTE_HPP

@ -0,0 +1,25 @@
//
// Created by koncord on 11.01.16.
//
#include <components/openmw-mp/NetworkMessages.hpp>
#include <components/esm/creaturestats.hpp>
#include "PacketAttributesAndStats.hpp"
using namespace mwmp;
PacketAttributesAndStats::PacketAttributesAndStats(RakNet::RakPeerInterface *peer) : BasePacket(peer)
{
packetID = ID_GAME_UPDATE_SKILLS;
}
void PacketAttributesAndStats::Packet(RakNet::BitStream *bs, BasePlayer *player, bool send)
{
BasePacket::Packet(bs, player, send);
for(int i = 0; i < AttributesCount; ++i)
RW(player->CreatureStats()->mAttributes[i], send);
for (int i = 0; i < StatsCount; ++i)
RW(player->NpcStats()->mSkills[i], send);
}

@ -0,0 +1,23 @@
//
// Created by koncord on 11.01.16.
//
#ifndef OPENMW_PacketAttributesAndStats_HPP
#define OPENMW_PacketAttributesAndStats_HPP
#include <components/openmw-mp/Packets/BasePacket.hpp>
namespace mwmp
{
class PacketAttributesAndStats : public BasePacket
{
public:
const static int AttributesCount = 8;
const static int StatsCount = 27;
PacketAttributesAndStats(RakNet::RakPeerInterface *peer);
virtual void Packet(RakNet::BitStream *bs, BasePlayer *player, bool send);
};
}
#endif //OPENMW_PacketAttributesAndStats_HPP

@ -0,0 +1,29 @@
//
// Created by koncord on 07.01.16.
//
#include "PacketBaseInfo.hpp"
#include <components/openmw-mp/NetworkMessages.hpp>
using namespace mwmp;
PacketBaseInfo::PacketBaseInfo(RakNet::RakPeerInterface *peer) : BasePacket(peer)
{
packetID = ID_GAME_BASE_INFO;
}
void PacketBaseInfo::Packet(RakNet::BitStream *bs, BasePlayer *player, bool send)
{
BasePacket::Packet(bs, player, send);
RW(player->Npc()->mName, send);
RW(player->Npc()->mModel, send);
RW(player->Npc()->mRace, send);
RW(player->Npc()->mClass, send);
RW(player->Npc()->mHair, send);
RW(player->Npc()->mHead, send);
RW(player->Npc()->mFlags, send);
RW(*player->BirthSign(), send);
}

@ -0,0 +1,21 @@
//
// Created by koncord on 07.01.16.
//
#ifndef OPENMW_PACKETBASEINFO_HPP
#define OPENMW_PACKETBASEINFO_HPP
#include <components/openmw-mp/Packets/BasePacket.hpp>
namespace mwmp
{
class PacketBaseInfo : public BasePacket
{
public:
PacketBaseInfo(RakNet::RakPeerInterface *peer);
virtual void Packet(RakNet::BitStream *bs, BasePlayer *player, bool send);
};
}
#endif //OPENMW_PACKETBASEINFO_HPP

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save