Merge remote-tracking branch 'yar/master' into Even

# Conflicts:
#	CMakeLists.txt
#	apps/openmw/mwdialogue/filter.cpp
#	apps/openmw/mwmechanics/character.cpp
#	apps/openmw/mwworld/localscripts.cpp
#	components/CMakeLists.txt
#	components/compiler/exprparser.cpp
#	components/sceneutil/workqueue.cpp
pull/1/head
Aesylwinn 8 years ago
commit b4a000913c

@ -65,6 +65,7 @@ option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time"
# Apps and tools
option(BUILD_OPENMW "build OpenMW" ON)
option(BUILD_OPENMW_MP "build OpenMW-MP" ON)
option(BUILD_BSATOOL "build BSA extractor" ON)
option(BUILD_ESMTOOL "build ESM inspector" ON)
option(BUILD_LAUNCHER "build Launcher" ON)
@ -116,6 +117,9 @@ if (WIN32)
option(USE_DEBUG_CONSOLE "whether a debug console should be enabled for debug builds, if false debug output is redirected to Visual Studio output" ON)
endif()
find_package(RakNet REQUIRED)
include_directories(${RakNet_INCLUDES})
if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD)
set(USE_QT FALSE)
else()
@ -328,6 +332,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")
@ -433,6 +443,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)
@ -452,6 +467,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 ".")
@ -555,6 +571,10 @@ add_subdirectory (components)
#endif()
# Apps and tools
if (BUILD_OPENMW_MP)
add_subdirectory( apps/openmw-mp )
endif()
if (BUILD_OPENMW)
add_subdirectory( apps/openmw )
endif()

@ -0,0 +1,51 @@
0.0.1b
Fixed NPC attack segfault
Movement interpolation
Lua-scripting
Chat
0.0.1a
Combat animation
Synchronization of melee and ranged (bow, crossbow, throwable weapons) combat
Synchronization of health, mana, stamina (sic) and death
Synchronization of attributes and skills
0.0.1
Synchronization of racial features
Synchronization of position
Synchronization of the state (nothing/weapon/spell)
Synchronization of movement and jump animations
To do:
0.0.1b
Finish combat package (knockout, knockdown, spells and enchantments)
Improve position synchronization while being knocked out, knocked down or dying
Partial (unbreakable) items synchronization
Spells synchronization
0.0.2
Vampirism
Lycanthropy
Items synchronization
Locks synchronization
Opening doors
Opening locks
Activators interaction (hook?)
0.0.2b
Code cleanup
0.0.3
Containers synchronization
Loot
Stealing from other players
Dropping/picking up items
Future
Disableable console (~)
Client-side script functions for synchronization
Weather sync
Time sync
NPC sync
Trading

@ -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,394 @@
//
// 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);
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,415 @@
//
// 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);
}
void ScriptFunctions::Resurrect(unsigned short pid)
{
Player *player;
GET_PLAYER(pid, player,);
mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_RESURRECT)->RequestData(player->guid);
}

@ -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,154 @@
//
// 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];
}
double ScriptFunctions::GetPosX(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0.0f);
return player->Position()->pos[0];
}
double ScriptFunctions::GetPosY(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0.0f);
return player->Position()->pos[1];
}
double ScriptFunctions::GetPosZ(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0.0f);
return player->Position()->pos[2];
}
void ScriptFunctions::SetPos(unsigned short pid, double x, double y, double 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];
}
double ScriptFunctions::GetAngleX(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0.0f);
return player->Position()->rot[0];
}
double ScriptFunctions::GetAngleY(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0.0f);
return player->Position()->rot[1];
}
double ScriptFunctions::GetAngleZ(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0.0f);
return player->Position()->rot[2];
}
void ScriptFunctions::SetAngle(unsigned short pid, double x, double y, double 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,241 @@
//
// 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 double GetPosX(unsigned short pid) noexcept;
static double GetPosY(unsigned short pid) noexcept;
static double GetPosZ(unsigned short pid) noexcept;
static void SetPos(unsigned short pid, double x, double y, double z) noexcept;
static void GetAngle(unsigned short pid, float *x, float *y, float *z) noexcept;
static double GetAngleX(unsigned short pid) noexcept;
static double GetAngleY(unsigned short pid) noexcept;
static double GetAngleZ(unsigned short pid) noexcept;
static void SetAngle(unsigned short pid, double x, double y, double 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 Resurrect(unsigned short pid);
//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},
{"GetPosX", ScriptFunctions::GetPosX},
{"GetPosY", ScriptFunctions::GetPosY},
{"GetPosZ", ScriptFunctions::GetPosZ},
{"SetPos", ScriptFunctions::SetPos},
{"GetAngle", ScriptFunctions::GetAngle},
{"GetAngleX", ScriptFunctions::GetAngleX},
{"GetAngleY", ScriptFunctions::GetAngleY},
{"GetAngleZ", ScriptFunctions::GetAngleZ},
{"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},
{"Resurrect", ScriptFunctions::Resurrect},
{"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));
Networking networking(peer);
int code = networking.MainLoop();
RakNet::RakPeerInterface::DestroyInstance(peer);
if (code == 0)
printf("Quitting peacefully.\n");
return code;
}

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

@ -55,6 +55,8 @@
#include "mwstate/statemanagerimp.hpp"
#include "mwmp/Main.hpp"
namespace
{
void checkSDLError(int ret)
@ -98,13 +100,15 @@ void OMW::Engine::frame(float frametime)
if (mUseSound)
mEnvironment.getSoundManager()->update(frametime);
mwmp::Main::Frame(frametime);
// Main menu opened? Then scripts are also paused.
bool paused = mEnvironment.getWindowManager()->containsMode(MWGui::GM_MainMenu);
// 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()==
@ -145,9 +149,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
@ -640,7 +644,10 @@ void OMW::Engine::go()
ToUTF8::Utf8Encoder encoder (mEncoding);
mEncoder = &encoder;
prepareEngine (settings);
mwmp::Main::Create();
mSkipMenu = true;
if (!mSaveGameFile.empty())
{
@ -678,7 +685,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;
@ -712,6 +719,7 @@ void OMW::Engine::go()
// Save user settings
settings.saveUser(settingspath);
mwmp::Main::Destroy();
std::cout << "Quitting peacefully." << std::endl;
}

@ -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"
@ -548,6 +551,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>();
@ -556,30 +562,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);
@ -589,8 +594,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;
@ -717,10 +735,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?
@ -819,11 +842,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)

@ -8,6 +8,9 @@
#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"
@ -1030,7 +1033,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())
{

@ -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"
@ -112,8 +115,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);
@ -168,6 +180,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>();
@ -188,8 +202,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"
@ -809,13 +811,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,238 @@
//
// 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 <MyGUI_InputManager.h>
#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 = true;
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,489 @@
//
// 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::setPosition()
{
MWBase::World *world = MWBase::Environment::get().getWorld();
MWWorld::Ptr player = world->getPlayerPtr();
world->getPlayer().setTeleported(true);
world->moveObject(player, Position()->pos[0], Position()->pos[1], Position()->pos[2]);
world->rotateObject(player, Position()->rot[0], Position()->rot[1], Position()->rot[2]);
}
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();
bool shouldUpdate = false;
// Send a packet to server to update this LocalPlayer's cell if:
// 1) forceUpdate is true
// 2) The LocalPlayer's cell name does not equal the World Player's cell name
// 3) The LocalPlayer's exterior cell coordinates do not equal the World Player's
// exterior cell coordinates
if (forceUpdate) {
shouldUpdate = true;
}
else if (!Misc::StringUtils::ciEqual(_cell->mName, GetCell()->mName)) {
shouldUpdate = true;
}
else if (_cell->isExterior()) {
if (_cell->mCellId.mIndex.mX != GetCell()->mCellId.mIndex.mX) {
shouldUpdate = true;
}
else if (_cell->mCellId.mIndex.mY != GetCell()->mCellId.mIndex.mY) {
shouldUpdate = true;
}
}
if (shouldUpdate)
{
(*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,50 @@
//
// 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 setPosition();
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;
};
}

@ -0,0 +1,570 @@
//
// 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 "../mwstate/statemanagerimp.hpp"
#include "DedicatedPlayer.hpp"
#include "Main.hpp"
using namespace std;
using namespace mwmp;
Networking::Networking(): peer(RakNet::RakPeerInterface::GetInstance()), controller(peer)
{
RakNet::SocketDescriptor sd;
sd.port=0;
RakNet::StartupResult b = peer->Startup(1,&sd, 1);
RakAssert(b==RAKNET_STARTED);
controller.SetStream(0, &bsOut);
connected = 0;
}
Networking::~Networking()
{
peer->Shutdown(100);
peer->CloseConnection(peer->GetSystemAddressFromIndex(0), true, 0);
RakNet::RakPeerInterface::DestroyInstance(peer);
}
void Networking::Update()
{
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 Networking::SendData(RakNet::BitStream *bs)
{
peer->Send(bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, serverAddr, false);
}
void Networking::Connect(const std::string &ip, unsigned short port)
{
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)
{
cout << "Connection attempt failed." << endl;
MWBase::Environment::get().getStateManager()->requestQuit();
}
bool queue = true;
while(queue)
{
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;
GetPacket(ID_GAME_BASE_INFO)->Send(getLocalPlayer());
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]);
}
}
}
}
void Networking::ReciveMessage(RakNet::Packet *packet)
{
RakNet::RakNetGUID id;
if(packet->length < 3)
return;
RakNet::BitStream bsIn(&packet->data[2], packet->length, false);
bsIn.Read(id);
DedicatedPlayer *pl = 0;
static RakNet::RakNetGUID myid = getLocalPlayer()->guid;
if(id != myid)
pl = Players::GetPlayer(id);
BasePacket *myPacket = controller.GetPacket(packet->data[1]);
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)
{
if (packet->length != myPacket->headerSize())
{
cout << "ID_GAME_UPDATE_POS changed by server" << endl;
myPacket->Packet(&bsIn, getLocalPlayer(), false);
getLocalPlayer()->setPosition();
}
else
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);
}
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;
}

@ -0,0 +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 LocalPlayer;
class Networking
{
public:
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();
private:
bool connected;
RakNet::RakPeerInterface *peer;
RakNet::SystemAddress serverAddr;
RakNet::BitStream bsOut;
PacketsController controller;
void ReciveMessage(RakNet::Packet *packet);
LocalPlayer *getLocalPlayer();
};
}
#endif //OPENMW_NETWORKING_HPP

@ -242,6 +242,10 @@ namespace MWWorld
// Objects with no refnum can't be handled correctly in the merging process that happens
// on a save/load, so do a simple copy & delete for these objects.
// The code below is disabled for TES3MP for as long as player objects lack refnums,
// because it will break exterior cell transitions for them
/*
if (!object.getCellRef().getRefNum().hasContentFile())
{
MWWorld::Ptr copied = object.getClass().copyToCell(object, *cellToMoveTo, object.getRefData().getCount());
@ -249,6 +253,7 @@ namespace MWWorld
object.getRefData().setBaseNode(NULL);
return copied;
}
*/
MovedRefTracker::iterator found = mMovedHere.find(object.getBase());
if (found != mMovedHere.end())

@ -0,0 +1,66 @@
# Comes form project edunetgames
# - Try to find RakNet
# Once done this will define
#
# RakNet_FOUND - system has RakNet
# RakNet_INCLUDES - the RakNet include directory
# RakNet_LIBRARY - Link these to use RakNet
FIND_LIBRARY (RakNet_LIBRARY_RELEASE NAMES RakNetLibStatic
PATHS
ENV LD_LIBRARY_PATH
ENV LIBRARY_PATH
/usr/lib64
/usr/lib
/usr/local/lib64
/usr/local/lib
/opt/local/lib
$ENV{RAKNET_ROOT}/lib
)
FIND_LIBRARY (RakNet_LIBRARY_DEBUG NAMES RakNetLibStatic
PATHS
ENV LD_LIBRARY_PATH
ENV LIBRARY_PATH
/usr/lib64
/usr/lib
/usr/local/lib64
/usr/local/lib
/opt/local/lib
$ENV{RAKNET_ROOT}/lib
)
FIND_PATH (RakNet_INCLUDES raknet/RakPeer.h
ENV CPATH
/usr/include
/usr/local/include
/opt/local/include
$ENV{RAKNET_ROOT}/include
)
IF(RakNet_INCLUDES AND RakNet_LIBRARY_RELEASE)
SET(RakNet_FOUND TRUE)
ENDIF(RakNet_INCLUDES AND RakNet_LIBRARY_RELEASE)
IF(RakNet_FOUND)
SET(RakNet_INCLUDES ${RakNet_INCLUDES})
IF (CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE)
SET(RakNet_LIBRARY optimized ${RakNet_LIBRARY_RELEASE} debug ${RakNet_LIBRARY_DEBUG})
ELSE()
# if there are no configuration types and CMAKE_BUILD_TYPE has no value
# then just use the release libraries
SET(RakNet_LIBRARY ${RakNet_LIBRARY_RELEASE} )
ENDIF()
IF(NOT RakNet_FIND_QUIETLY)
MESSAGE(STATUS "Found RakNet: ${RakNet_LIBRARIES}")
ENDIF(NOT RakNet_FIND_QUIETLY)
ELSE(RakNet_FOUND)
IF(RakNet_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find RakNet")
ENDIF(RakNet_FIND_REQUIRED)
ENDIF(RakNet_FOUND)

@ -0,0 +1,70 @@
# - 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
FIND_LIBRARY (Terra_LIBRARY_RELEASE NAMES terra
PATHS
ENV LD_LIBRARY_PATH
ENV LIBRARY_PATH
/usr/lib64
/usr/lib
/usr/local/lib64
/usr/local/lib
/opt/local/lib
$ENV{Terra_ROOT}/lib
)
FIND_LIBRARY (Terra_LIBRARY_DEBUG NAMES terra
PATHS
ENV LD_LIBRARY_PATH
ENV LIBRARY_PATH
/usr/lib64
/usr/lib
/usr/local/lib64
/usr/local/lib
/opt/local/lib
$ENV{Terra_ROOT}/lib
)
FIND_PATH (Terra_INCLUDES terra/terra.h
ENV CPATH
/usr/include
/usr/local/include
/opt/local/include
$ENV{Terra_ROOT}/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)

@ -141,10 +141,17 @@ 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)
add_component_dir (fallback
fallback validate
)
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

@ -0,0 +1,29 @@
//
// Created by koncord on 15.01.16.
//
#include <components/openmw-mp/NetworkMessages.hpp>
#include "PacketCell.hpp"
mwmp::PacketCell::PacketCell(RakNet::RakPeerInterface *peer) : BasePacket(peer)
{
packetID = ID_GAME_CELL;
priority = IMMEDIATE_PRIORITY;
reliability = RELIABLE_ORDERED;
}
void mwmp::PacketCell::Packet(RakNet::BitStream *bs, mwmp::BasePlayer *player, bool send)
{
BasePacket::Packet(bs, player, send);
RW(player->GetCell()->mData.mFlags, send);
if(player->GetCell()->isExterior())
{
RW(player->GetCell()->mCellId.mIndex.mX, send);
RW(player->GetCell()->mCellId.mIndex.mY, send);
}
else
RW(player->GetCell()->mName, send);
}

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

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

Loading…
Cancel
Save