feat: casually rewrite in C++
This commit is contained in:
parent
120894a992
commit
162bd4f953
25 changed files with 368 additions and 255 deletions
|
@ -1,4 +0,0 @@
|
||||||
# Used by "mix format"
|
|
||||||
[
|
|
||||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
|
||||||
]
|
|
31
.gitignore
vendored
31
.gitignore
vendored
|
@ -1,29 +1,2 @@
|
||||||
# The directory Mix will write compiled artifacts to.
|
build
|
||||||
_build/
|
.cache
|
||||||
|
|
||||||
# If you run "mix test --cover", coverage assets end up here.
|
|
||||||
cover/
|
|
||||||
|
|
||||||
# The directory Mix downloads your dependencies sources to.
|
|
||||||
deps/
|
|
||||||
|
|
||||||
# Where third-party dependencies like ExDoc output generated docs.
|
|
||||||
doc/
|
|
||||||
|
|
||||||
# Ignore .fetch files in case you like to edit your project deps locally.
|
|
||||||
.fetch
|
|
||||||
|
|
||||||
# If the VM crashes, it generates a dump, let's ignore it too.
|
|
||||||
erl_crash.dump
|
|
||||||
|
|
||||||
# Also ignore archive artifacts (built via "mix archive.build").
|
|
||||||
*.ez
|
|
||||||
|
|
||||||
# Ignore package tarball (built via "mix hex.build").
|
|
||||||
portingtools-*.tar
|
|
||||||
|
|
||||||
# Temporary files, for example, from tests.
|
|
||||||
tmp/
|
|
||||||
|
|
||||||
# Language Server
|
|
||||||
.elixir_ls/
|
|
||||||
|
|
12
CMakeLists.txt
Normal file
12
CMakeLists.txt
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8.11)
|
||||||
|
project(PORTINGTOOLS)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE sources src/*)
|
||||||
|
|
||||||
|
find_package(Boost 1.80 COMPONENTS log filesystem REQUIRED)
|
||||||
|
|
||||||
|
include_directories(${Boost_INCLUDE_DIR})
|
||||||
|
|
||||||
|
add_executable(portingtools ${sources})
|
||||||
|
|
||||||
|
target_link_libraries(portingtools LINK_PUBLIC ${Boost_LIBRARIES})
|
11
README.md
11
README.md
|
@ -2,11 +2,12 @@
|
||||||
|
|
||||||
This tool is meant to make porting mods easier for MineteckReloaded.
|
This tool is meant to make porting mods easier for MineteckReloaded.
|
||||||
|
|
||||||
Also, it helped me learn some elixir, so don't expect good code.
|
Also, it helped me learn some c++, so don't expect good code.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
- `MIX_ENV=prod mix release`
|
- `cmake -S. -Bbuild`
|
||||||
- start the server with `_build/prod/rel/portingtools/bin/portingtools start`
|
- `cmake --build build`
|
||||||
- map stuff with `./client.sh map`
|
- start the server with `build/portingtools serve`
|
||||||
- resolve ResourceLocations with `./client.sh resourceloc`
|
- map stuff with `build/portingtools map`
|
||||||
|
- resolve ResourceLocations with `build/portingtools resourceloc`
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/usr/bin/sh
|
|
||||||
exec "$(dirname "$(realpath "$0")")"/_build/prod/rel/portingtools/bin/portingtools rpc "Cli.call(~s<$1>)"
|
|
31
lib/cli.ex
31
lib/cli.ex
|
@ -1,31 +0,0 @@
|
||||||
defmodule Cli do
|
|
||||||
def call(command) do
|
|
||||||
case command do
|
|
||||||
"map" ->
|
|
||||||
input()
|
|
||||||
|> PortingTools.Mappings.map()
|
|
||||||
|> output(:map)
|
|
||||||
|
|
||||||
"resourceloc" ->
|
|
||||||
input()
|
|
||||||
|> PortingTools.ResourceLoc.resolve()
|
|
||||||
|> output(:map)
|
|
||||||
|
|
||||||
_ ->
|
|
||||||
raise "Invalid command!"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def input() do
|
|
||||||
IO.gets(nil) |> String.trim()
|
|
||||||
end
|
|
||||||
|
|
||||||
def output(response, type) do
|
|
||||||
case {response, type} do
|
|
||||||
{s, _} when is_binary(s) -> s
|
|
||||||
{nil, :map} -> "<unknown>"
|
|
||||||
{nil, :resourceloc} -> "<invalid>"
|
|
||||||
end
|
|
||||||
|> IO.puts()
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,18 +0,0 @@
|
||||||
defmodule PortingTools.Application do
|
|
||||||
use Application
|
|
||||||
|
|
||||||
@impl true
|
|
||||||
def start(_type, _args) do
|
|
||||||
#{:ok, _} = Node.start(:"portingtools@localhost", :shortnames)
|
|
||||||
#Node.set_cookie(Node.self(), :ptools)
|
|
||||||
|
|
||||||
children = [
|
|
||||||
PortingTools.ResourceLoc,
|
|
||||||
PortingTools.Mappings,
|
|
||||||
PortingTools.Mappings.Agent,
|
|
||||||
]
|
|
||||||
|
|
||||||
opts = [strategy: :one_for_one, name: PortingTools.Supervisor]
|
|
||||||
Supervisor.start_link(children, opts)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,22 +0,0 @@
|
||||||
defmodule PortingTools.Mappings do
|
|
||||||
use GenServer, restart: :transient
|
|
||||||
require Logger
|
|
||||||
|
|
||||||
def start_link(_) do
|
|
||||||
GenServer.start_link(__MODULE__, nil, name: __MODULE__)
|
|
||||||
end
|
|
||||||
|
|
||||||
def init(_init_arg) do
|
|
||||||
Logger.info("Initilizing mappings server @ #{__MODULE__}")
|
|
||||||
{:ok, nil}
|
|
||||||
end
|
|
||||||
|
|
||||||
def map(str) do
|
|
||||||
GenServer.call(__MODULE__, {:map, str})
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_call({:map, str}, _from, state) do
|
|
||||||
Logger.info("Got map request to map #{str}")
|
|
||||||
{:reply, PortingTools.Mappings.Agent.map(str), state}
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,74 +0,0 @@
|
||||||
defmodule PortingTools.Mappings.Agent do
|
|
||||||
@moduledoc """
|
|
||||||
This module manages and loads the mappings
|
|
||||||
and renames.
|
|
||||||
"""
|
|
||||||
|
|
||||||
use Agent, restart: :transient
|
|
||||||
require Logger
|
|
||||||
|
|
||||||
def start_link(_) do
|
|
||||||
Agent.start_link(&init/0, name: __MODULE__)
|
|
||||||
end
|
|
||||||
|
|
||||||
defmodule PortingTools.Mappings.Agent.State do
|
|
||||||
defstruct [:mappings, :renames]
|
|
||||||
end
|
|
||||||
|
|
||||||
def init() do
|
|
||||||
%PortingTools.Mappings.Agent.State{
|
|
||||||
mappings: load_mappings(),
|
|
||||||
renames: load_renames()
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_mappings() do
|
|
||||||
Logger.info("reading mappings")
|
|
||||||
|
|
||||||
mappings =
|
|
||||||
File.ls!("mappings")
|
|
||||||
|> Stream.flat_map(&File.stream!("mappings/#{&1}"))
|
|
||||||
|> Stream.map(&String.split(&1, ","))
|
|
||||||
|> Enum.reduce(%{}, fn [remapped, orig | _], map ->
|
|
||||||
Map.put(map, String.trim(remapped), String.trim(orig))
|
|
||||||
end)
|
|
||||||
|
|
||||||
Logger.info("read #{map_size(mappings)} mappings")
|
|
||||||
mappings
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_renames() do
|
|
||||||
Logger.info("reading renames")
|
|
||||||
|
|
||||||
renames =
|
|
||||||
File.stream!("renames.csv")
|
|
||||||
|> Stream.map(&String.split(&1, ","))
|
|
||||||
|> Enum.reduce(%{}, fn [old, new | _], map ->
|
|
||||||
Map.put(map, String.trim(old), String.trim(new))
|
|
||||||
end)
|
|
||||||
|
|
||||||
Logger.info("read #{map_size(renames)} renames")
|
|
||||||
|
|
||||||
renames
|
|
||||||
end
|
|
||||||
|
|
||||||
def map(key) do
|
|
||||||
mapping = Agent.get(__MODULE__, &Map.get(&1.mappings, key))
|
|
||||||
|
|
||||||
case mapping do
|
|
||||||
nil ->
|
|
||||||
Logger.warn("tried to map unknown symbol")
|
|
||||||
nil
|
|
||||||
|
|
||||||
m ->
|
|
||||||
case Agent.get(__MODULE__, &Map.get(&1.renames, m)) do
|
|
||||||
nil ->
|
|
||||||
m
|
|
||||||
|
|
||||||
r ->
|
|
||||||
Logger.info("found rename for #{m} -> #{r}")
|
|
||||||
r
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,32 +0,0 @@
|
||||||
defmodule PortingTools.ResourceLoc do
|
|
||||||
use GenServer, restart: :transient
|
|
||||||
require Logger
|
|
||||||
|
|
||||||
def start_link(_) do
|
|
||||||
GenServer.start_link(__MODULE__, nil, name: __MODULE__)
|
|
||||||
end
|
|
||||||
|
|
||||||
def init(_init_arg) do
|
|
||||||
Logger.info("initializing Resourceloc server @ #{__MODULE__}")
|
|
||||||
{:ok, nil}
|
|
||||||
end
|
|
||||||
|
|
||||||
def resolve(str) do
|
|
||||||
GenServer.call(__MODULE__, {:resolve, str})
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle_call({:resolve, str}, _from, state) do
|
|
||||||
Logger.info("got ResourceLoc resolve request")
|
|
||||||
|
|
||||||
try do
|
|
||||||
["mods", mod | rest] =
|
|
||||||
String.trim(str)
|
|
||||||
|> String.trim(<<?">>)
|
|
||||||
|> String.split("/", trim: true)
|
|
||||||
|
|
||||||
{:reply, ~s<new ResourceLocation("#{mod}", "#{Enum.join(rest, "/")}")>, state}
|
|
||||||
rescue
|
|
||||||
MatchError -> {:reply, nil, state}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
29
mix.exs
29
mix.exs
|
@ -1,29 +0,0 @@
|
||||||
defmodule PortingTools.MixProject do
|
|
||||||
use Mix.Project
|
|
||||||
|
|
||||||
def project do
|
|
||||||
[
|
|
||||||
app: :portingtools,
|
|
||||||
version: "0.1.0",
|
|
||||||
elixir: "~> 1.14",
|
|
||||||
start_permanent: Mix.env() == :prod,
|
|
||||||
deps: deps()
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run "mix help compile.app" to learn about applications.
|
|
||||||
def application do
|
|
||||||
[
|
|
||||||
extra_applications: [:logger],
|
|
||||||
mod: {PortingTools.Application, []}
|
|
||||||
]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Run "mix help deps" to learn about dependencies.
|
|
||||||
defp deps do
|
|
||||||
[
|
|
||||||
# {:dep_from_hexpm, "~> 0.3.0"},
|
|
||||||
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -10,3 +10,7 @@ getLastAttackingEntity,getLastAttacker
|
||||||
getBlockId,getBlock
|
getBlockId,getBlock
|
||||||
markBlockForRenderUpdate,markBlockRangeForRenderUpdate
|
markBlockForRenderUpdate,markBlockRangeForRenderUpdate
|
||||||
setCompoundTag,setTag
|
setCompoundTag,setTag
|
||||||
|
getEntityName,getCommandSenderName
|
||||||
|
textureList,framesTextureData
|
||||||
|
bucketWater,water_bucket
|
||||||
|
ingotIron,iron_ingot
|
||||||
|
|
|
69
src/client.cpp
Normal file
69
src/client.cpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#include "data.hpp"
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <sys/msg.h>
|
||||||
|
|
||||||
|
namespace client {
|
||||||
|
void sendMsg(int msqid, data::RequestMsg *msg) {
|
||||||
|
if (msgsnd(msqid, msg, sizeof(data::RequestMsg) - sizeof(long), 0) < 0) {
|
||||||
|
BOOST_LOG_TRIVIAL(fatal) << "send error " << strerror(errno);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string recvMsg(int msqid) {
|
||||||
|
data::ResponseMsg msg;
|
||||||
|
if (msgrcv(msqid, &msg, sizeof(data::ResponseMsg) - sizeof(long),
|
||||||
|
data::clientbound_msg, 0) < 0) {
|
||||||
|
BOOST_LOG_TRIVIAL(fatal) << "receive error " << strerror(errno);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string(&msg.data[0], msg.datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void map(key_t key) {
|
||||||
|
std::string inp;
|
||||||
|
std::cin >> inp;
|
||||||
|
|
||||||
|
auto msqid = msgget(key, 0664);
|
||||||
|
|
||||||
|
if (msqid < 0) {
|
||||||
|
BOOST_LOG_TRIVIAL(fatal) << "msgget fail";
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
data::RequestMsg req;
|
||||||
|
req.msgtype = data::serverbound_msg;
|
||||||
|
req.type = data::map;
|
||||||
|
req.datalen = inp.size();
|
||||||
|
std::copy(inp.begin(), inp.end(), req.data);
|
||||||
|
|
||||||
|
sendMsg(msqid, &req);
|
||||||
|
std::cout << recvMsg(msqid) << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resolveResourceLoc(key_t key) {
|
||||||
|
std::string inp;
|
||||||
|
std::cin >> inp;
|
||||||
|
|
||||||
|
auto msqid = msgget(key, 0664);
|
||||||
|
|
||||||
|
if (msqid < 0) {
|
||||||
|
BOOST_LOG_TRIVIAL(fatal) << "msgget fail";
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
data::RequestMsg req;
|
||||||
|
req.msgtype = data::serverbound_msg;
|
||||||
|
req.type = data::resolve_resource_loc;
|
||||||
|
req.datalen = inp.size();
|
||||||
|
std::copy(inp.begin(), inp.end(), req.data);
|
||||||
|
|
||||||
|
sendMsg(msqid, &req);
|
||||||
|
std::cout << recvMsg(msqid) << std::endl;
|
||||||
|
}
|
||||||
|
} // namespace client
|
6
src/client.hpp
Normal file
6
src/client.hpp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
namespace client {
|
||||||
|
void map(key_t key);
|
||||||
|
void resolveResourceLoc(key_t key);
|
||||||
|
} // namespace client
|
17
src/data.cpp
Normal file
17
src/data.cpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include "data.hpp"
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <sys/ipc.h>
|
||||||
|
|
||||||
|
namespace data {
|
||||||
|
key_t getIpcKeyFromExeName(char *argv0) {
|
||||||
|
auto k = ftok(argv0, 'X');
|
||||||
|
|
||||||
|
if (k < 0) {
|
||||||
|
BOOST_LOG_TRIVIAL(fatal) << "failed to get IPC key";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
} // namespace data
|
29
src/data.hpp
Normal file
29
src/data.hpp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
namespace data {
|
||||||
|
const int serverbound_msg = 1;
|
||||||
|
const int clientbound_msg = 2;
|
||||||
|
|
||||||
|
key_t getIpcKeyFromExeName(char *argv0);
|
||||||
|
|
||||||
|
enum RequestType {
|
||||||
|
map,
|
||||||
|
resolve_resource_loc,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RequestMsg {
|
||||||
|
long msgtype;
|
||||||
|
|
||||||
|
RequestType type;
|
||||||
|
|
||||||
|
unsigned int datalen;
|
||||||
|
char data[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ResponseMsg {
|
||||||
|
long msgtype;
|
||||||
|
|
||||||
|
unsigned int datalen;
|
||||||
|
char data[128];
|
||||||
|
};
|
||||||
|
} // namespace data
|
25
src/main.cpp
Normal file
25
src/main.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include "client.hpp"
|
||||||
|
#include "data.hpp"
|
||||||
|
#include "server.hpp"
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc < 2) {
|
||||||
|
BOOST_LOG_TRIVIAL(fatal) << "not enough arguments!";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(argv[1], "serve") == 0) {
|
||||||
|
server::run(data::getIpcKeyFromExeName(argv[0]));
|
||||||
|
} else if (strcmp(argv[1], "map") == 0) {
|
||||||
|
client::map(data::getIpcKeyFromExeName(argv[0]));
|
||||||
|
} else if (strcmp(argv[1], "resourceloc") == 0) {
|
||||||
|
client::resolveResourceLoc(data::getIpcKeyFromExeName(argv[0]));
|
||||||
|
} else {
|
||||||
|
BOOST_LOG_TRIVIAL(fatal) << "unknown command!";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
67
src/mappings.cpp
Normal file
67
src/mappings.cpp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
#include "mappings.hpp"
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/algorithm/string/classification.hpp>
|
||||||
|
#include <boost/algorithm/string/split.hpp>
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
#include <boost/filesystem/directory.hpp>
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
|
namespace mappings {
|
||||||
|
void loadFile(std::string path, std::map<std::string, std::string> *map) {
|
||||||
|
std::ifstream file(path);
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(file, line)) {
|
||||||
|
std::vector<std::string> splits;
|
||||||
|
boost::algorithm::split(splits, line, boost::is_any_of(",\t|"));
|
||||||
|
|
||||||
|
if (splits.size() < 2) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "found invalid mapping '" << line << "'";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*map)[splits[0]] = splits[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Mappings Mappings::load() {
|
||||||
|
std::map<std::string, std::string> mappings;
|
||||||
|
std::map<std::string, std::string> renames;
|
||||||
|
|
||||||
|
// load mappings
|
||||||
|
fs::directory_iterator end_itr;
|
||||||
|
for (fs::directory_iterator itr("mappings"); itr != end_itr; ++itr) {
|
||||||
|
if (fs::is_directory(itr->status()) ||
|
||||||
|
!boost::algorithm::ends_with(itr->path().string(), ".csv"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
loadFile(itr->path().string(), &mappings);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs::is_regular_file("renames.csv")) {
|
||||||
|
loadFile("renames.csv", &renames);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "loaded " << mappings.size() << " mappings and "
|
||||||
|
<< renames.size() << " renames";
|
||||||
|
return {mappings, renames};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Mappings::map(std::string inp) {
|
||||||
|
if (!this->mappings.count(inp)) {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "unknown mapping '" << inp << "'";
|
||||||
|
return "<unknown>";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mapped = this->mappings[inp];
|
||||||
|
|
||||||
|
if (this->renames.count(mapped))
|
||||||
|
return renames[mapped];
|
||||||
|
|
||||||
|
return mapped;
|
||||||
|
}
|
||||||
|
} // namespace mappings
|
17
src/mappings.hpp
Normal file
17
src/mappings.hpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
namespace mappings {
|
||||||
|
class Mappings {
|
||||||
|
std::map<std::string, std::string> mappings;
|
||||||
|
std::map<std::string, std::string> renames;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Mappings(std::map<std::string, std::string> mappings,
|
||||||
|
std::map<std::string, std::string> renames) {
|
||||||
|
this->mappings = mappings;
|
||||||
|
this->renames = renames;
|
||||||
|
}
|
||||||
|
static Mappings load();
|
||||||
|
std::string map(std::string inp);
|
||||||
|
};
|
||||||
|
} // namespace mappings
|
34
src/resourceloc.cpp
Normal file
34
src/resourceloc.cpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#include "resourceloc.hpp"
|
||||||
|
#include <boost/algorithm/string/split.hpp>
|
||||||
|
#include <boost/algorithm/string/trim.hpp>
|
||||||
|
#include <boost/format.hpp>
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace resourceloc {
|
||||||
|
std::string resolve(std::string inp) {
|
||||||
|
boost::algorithm::trim_if(inp, boost::is_any_of(" \n\r\""));
|
||||||
|
|
||||||
|
std::vector<std::string> components;
|
||||||
|
boost::algorithm::split(components, inp, boost::is_any_of("/"));
|
||||||
|
|
||||||
|
if (components.size() < 3 || components[0] != "" || components[1] != "mods") {
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "invalid resourceloc";
|
||||||
|
return "<invalid>";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string path_component;
|
||||||
|
for (unsigned int i = 3; i < components.size(); i++) {
|
||||||
|
path_component += components[i];
|
||||||
|
if (i != components.size() - 1) {
|
||||||
|
path_component += "/";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return boost::str(boost::format("new ResourceLocation(\"%1%\", \"%2%\")") %
|
||||||
|
components[2] % path_component);
|
||||||
|
}
|
||||||
|
} // namespace resourceloc
|
4
src/resourceloc.hpp
Normal file
4
src/resourceloc.hpp
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#include <string>
|
||||||
|
namespace resourceloc {
|
||||||
|
std::string resolve(std::string inp);
|
||||||
|
}
|
71
src/server.cpp
Normal file
71
src/server.cpp
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
#include "server.hpp"
|
||||||
|
#include "data.hpp"
|
||||||
|
#include "mappings.hpp"
|
||||||
|
#include "resourceloc.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <boost/log/trivial.hpp>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <sys/ipc.h>
|
||||||
|
#include <sys/msg.h>
|
||||||
|
|
||||||
|
namespace server {
|
||||||
|
void sendToClient(int msqid, std::string msg) {
|
||||||
|
data::ResponseMsg pkt;
|
||||||
|
pkt.msgtype = data::clientbound_msg;
|
||||||
|
pkt.datalen = msg.size();
|
||||||
|
std::copy(msg.begin(), msg.end(), pkt.data);
|
||||||
|
|
||||||
|
if (msgsnd(msqid, &pkt, sizeof(data::ResponseMsg) - sizeof(long), 0) < 0) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "failed to send response " << strerror(errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleResolveResourceLoc(int msqid, data::RequestMsg *msg) {
|
||||||
|
std::string s(&msg->data[0], msg->datalen);
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "got request to resolve resourceloc '" << s << "'";
|
||||||
|
auto res = resourceloc::resolve(s);
|
||||||
|
|
||||||
|
sendToClient(msqid, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleMap(int msqid, mappings::Mappings *mappings, data::RequestMsg *msg) {
|
||||||
|
std::string s(&msg->data[0], msg->datalen);
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "got request to map '" << s << "'";
|
||||||
|
sendToClient(msqid, mappings->map(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(key_t key) {
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "starting server";
|
||||||
|
|
||||||
|
auto msqid = msgget(key, 0664 | IPC_CREAT);
|
||||||
|
|
||||||
|
if (msqid < 0) {
|
||||||
|
BOOST_LOG_TRIVIAL(fatal) << "msgget fail";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "msqid " << msqid;
|
||||||
|
|
||||||
|
auto mappings = mappings::Mappings::load();
|
||||||
|
|
||||||
|
data::RequestMsg msg;
|
||||||
|
for (;;) {
|
||||||
|
if (msgrcv(msqid, &msg, sizeof(data::RequestMsg) - sizeof(long),
|
||||||
|
data::serverbound_msg, 0) < 0) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "receive error " << strerror(errno);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (msg.type) {
|
||||||
|
case data::map:
|
||||||
|
handleMap(msqid, &mappings, &msg);
|
||||||
|
break;
|
||||||
|
case data::resolve_resource_loc:
|
||||||
|
handleResolveResourceLoc(msqid, &msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace server
|
5
src/server.hpp
Normal file
5
src/server.hpp
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
namespace server {
|
||||||
|
void run(key_t key);
|
||||||
|
}
|
|
@ -1,8 +0,0 @@
|
||||||
defmodule PortingtoolsTest do
|
|
||||||
use ExUnit.Case
|
|
||||||
doctest Portingtools
|
|
||||||
|
|
||||||
test "greets the world" do
|
|
||||||
assert Portingtools.hello() == :world
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1 +0,0 @@
|
||||||
ExUnit.start()
|
|
Loading…
Reference in a new issue