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.cpppull/1/head
commit
b4a000913c
@ -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 *&¶ms) 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> ¶ms, 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> ¶ms, 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(<ime)));
|
||||
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(>m);
|
||||
#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(>m);
|
||||
#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, "es); /* 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, "es); /* 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;
|
||||
}
|
@ -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
|
@ -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)
|
||||
|
@ -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…
Reference in New Issue