Created
February 26, 2015 16:49
-
-
Save jboecker/111aa4cf2bdff4c16329 to your computer and use it in GitHub Desktop.
DCS Witchcraft adapted to the DCS "server" Lua environment (e.g. by commenting out env.info() calls)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Server hooks | |
module('server', package.seeall) | |
-- do not load real gettext here | |
-- _ only marks strings for translation | |
local _ = function(msg) return msg end | |
local log | |
local names = {} | |
local function log_write(str) | |
net.log(str) | |
if log then log:write(os.date("%c") .. " : " .. str .. "\n") end | |
end | |
local function unit_type(unit) return net.get_unit_property(unit, 4) or "" end | |
local function side_name(side) | |
if side == 0 then return "Spectators" | |
elseif side == 1 then return "Red" | |
else return "Blue" end | |
end | |
function on_net_start() | |
--log = io.open(lfs.writedir() .. "Logs/net-server-"..os.date("%Y%m%d-%H%M%S")..".log", "w") | |
log = io.open(lfs.writedir() .. "Logs/net-server.log", "w") | |
log_write("Server started") | |
names = {} | |
names[net.get_name(1)] = 1 | |
end | |
function on_mission(filename) | |
--already reported | |
--log_write("Loaded mission ", filename) | |
-- parse available slots | |
local serializer = [[ | |
serialize = function(val) | |
if type(val)=='number' or type(val)=='boolean' then | |
return tostring(val) | |
elseif type(val)=='string' then | |
return string.format("%q", val) | |
elseif type(val)=='table' then | |
local k,v | |
local str = '{' | |
for k,v in pairs(val) do | |
str=str..'['..serialize(k)..']='..serialize(v)..',' | |
end | |
str = str..'}' | |
return str | |
end | |
return 'nil' | |
end | |
]] | |
-- load serializer into mission env | |
net.dostring_in('mission', serializer) | |
-- parse available slots | |
local slot_parser = [[ | |
local side_parser = function(side) | |
local i,v | |
local slots = {} | |
for i,v in ipairs(side) do | |
local u = { unit_id = v.unitId, type = v.type, onboard_num = v.onboard_num } | |
local group = v.group | |
if group then | |
u.group_name = group.name | |
u.group_task = group.task | |
u.country_name = group.country.name | |
end | |
table.insert(slots, u) | |
end | |
return slots | |
end | |
local res = { red = side_parser(db.clients.red), blue = side_parser(db.clients.blue) } | |
return serialize(res) | |
]] | |
local val, res = net.dostring_in('mission', slot_parser) | |
--net.log(string.format("%s: (%s) %q", 'mission', tostring(res), val)) | |
if res then | |
local t = loadstring('return '..val) | |
game.slots = t() | |
else | |
game.slots = {} | |
end | |
end | |
function on_net_stop() | |
log_write("Server stopped") | |
if log then | |
log:close() | |
log = nil | |
end | |
names = {} | |
end | |
function on_process() | |
end | |
function on_connect(id, addr, port, name, ucid) | |
--[[ banning example | |
if banned_hosts and banned_hosts[addr] then | |
-- extend the ban | |
--banned_hosts[addr] = os.time() | |
return "Banned by IP", false | |
end | |
if banned_names and banned_names[name] then | |
-- extend the ban | |
--banned_names[name] = os.time() | |
return "Banned by name", false | |
end | |
if banned_serials and banned_serials[ucid] then | |
-- extend the ban | |
--banned_names[name] = os.time() | |
return "Banned by UniqueClientID", false | |
end | |
]] | |
-- write to log | |
log_write(string.format("Connected client: id = [%d], addr = %s:%d, name = %q, ucid = %q", | |
id, addr, port, name, ucid)) | |
net.recv_chat(string.format("Connected client: id = [%d], addr = %s:%d, name = %q, ucid = %q", id, addr, port, name, ucid)) | |
if names[name] then | |
return _("Please, provide a unique nickname."), false | |
end | |
names[name] = id | |
return true | |
end | |
function on_disconnect(id, err) | |
local n = net.get_name(id) | |
if names[n] then | |
names[n] = nil | |
end | |
log_write(string.format("Disconnected client [%d] %q", id, n or "")) | |
end | |
-- | |
function on_set_name(id, new_name) | |
-- check against ban list | |
--if banned_names[new_name] then | |
-- kick(id, "banned name") | |
--end | |
old_name = net.get_name(id) | |
if names[new_name] then | |
log_write(string.format("Client [%d] %q tried to changed name to %q", id, old_name, new_name)) | |
return old_name | |
end | |
names[old_name] = nil | |
names[new_name] = id | |
log_write(string.format("Client [%d] %q changed name to %q", id, old_name, new_name)) | |
return name | |
end | |
function on_set_unit(id, side, unit) | |
name = net.get_name(id) | |
if unit ~= "" then | |
msg = string.format("Client [%d] %q joined %s in %q(%s)", id, name, side_name(side), unit_type(unit), unit) | |
else | |
msg = string.format("Client [%d] %q joined %s", id, name, side_name(side)) | |
end | |
log_write(msg) | |
return true | |
end | |
function on_chat(id, msg, all) | |
if msg=="/mybad" then | |
return string.format("I (%d, %q) has made a screenshot at %f", id, net.get_name(id), net.get_model_time()) | |
elseif string.sub(msg, 1, 1) == '/' then | |
net.recv_chat("got command: "..msg, 0) | |
return | |
end | |
return msg | |
end | |
-------------------------------------------------- | |
-- load event callbacks | |
dofile('./Scripts/net/events.lua') | |
dofile(lfs.writedir() .. 'Scripts/net/WitchcraftServerEnv.lua') | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--[[ | |
Setup of on_process() function taken from the excellent example set by SLMod | |
]] -- | |
log("Loading Witchcraft into the server environment...") | |
witchcraft = witchcraft or {} | |
witchcraft.oldfunc = {} | |
witchcraft.oldfunc.on_process = server.on_process() | |
do | |
witchcraft.host = "localhost" | |
witchcraft.port = 3001 | |
local require = require | |
local loadfile = loadfile | |
package.path = package.path..";.\\LuaSocket\\?.lua" | |
package.cpath = package.cpath..";.\\LuaSocket\\?.dll" | |
local JSON = loadfile("Scripts\\JSON.lua")() | |
witchcraft.JSON = JSON | |
local socket = require("socket") | |
function witchcraft.step(arg, time) | |
witchcraft.txbuf = witchcraft.txbuf .. '{"type":"dummy"}\n' | |
if witchcraft.txbuf:len() > 0 then | |
local bytes_sent = nil | |
local ret1, ret2, ret3 = witchcraft.conn:send(witchcraft.txbuf) | |
if ret1 then | |
bytes_sent = ret1 | |
else | |
--env.info("could not send witchcraft: "..ret2) | |
if ret3 == 0 then | |
if ret2 == "closed" then | |
witchcraft.txbuf = '{"type":"dummy"}\n' | |
witchcraft.rxbuf = "" | |
witchcraft.lastUnitUpdateTime = 0 | |
witchcraft.conn = socket.tcp() | |
witchcraft.conn:settimeout(.0001) | |
--env.info("witchcraft: socket was closed") | |
end | |
--env.info("reconnecting to "..tostring(witchcraft.host)..":"..tostring(witchcraft.port)) | |
witchcraft.conn:connect(witchcraft.host, witchcraft.port) | |
return | |
end | |
bytes_sent = ret3 | |
end | |
witchcraft.txbuf = witchcraft.txbuf:sub(bytes_sent + 1) | |
else | |
if witchcraft.txidle_hook then | |
local bool, err = pcall(witchcraft.txidle_hook) | |
if not bool then | |
--env.info("witchcraft.txidle_hook() failed: "..err) | |
end | |
end | |
end | |
local line, err = witchcraft.conn:receive() | |
if err then | |
--env.info("witchcraft read error: "..err) | |
else | |
msg = JSON:decode(line) | |
if msg.type == "lua" then | |
local response_msg = {} | |
response_msg.type = "luaresult" | |
response_msg.name = msg.name | |
local f, error_msg = loadstring(msg.code, msg.name) | |
if f then | |
witchcraft.context = {} | |
witchcraft.context.arg = msg.arg | |
setfenv(f, witchcraft.mission_env) | |
response_msg.success, response_msg.result = pcall(f) | |
else | |
response_msg.success = false | |
response_msg.result = tostring(error_msg) | |
end | |
local response_string = "" | |
local function encode_response() | |
response_string = JSON:encode(response_msg):gsub("\n","").."\n" | |
end | |
local success, result = pcall(encode_response) | |
if not success then | |
response_msg.success = false | |
response_msg.result = tostring(result) | |
encode_response() | |
end | |
witchcraft.txbuf = witchcraft.txbuf .. response_string | |
end | |
end | |
end | |
witchcraft.start = function(mission_env_) | |
witchcraft.mission_env = mission_env_ | |
if not witchcraft.scheduled then | |
witchcraft.lastUnitUpdateTime = 0 | |
witchcraft.unitUpdateInterval = 0 | |
witchcraft.txbuf = '{"type":"dummy"}\n' | |
witchcraft.rxbuf = "" | |
witchcraft.lastUnitUpdateTime = 0 | |
witchcraft.conn = socket.tcp() | |
witchcraft.conn:settimeout(.0001) | |
witchcraft.conn:connect(witchcraft.host, witchcraft.port) | |
witchcraft.scheduled = true | |
end | |
end | |
witchcraft.log = function(data) | |
local msg = { ["type"] = "log", ["data"] = data }; | |
witchcraft.txbuf = witchcraft.txbuf .. JSON:encode(msg):gsub("\n","").."\n" | |
end | |
function server.on_process() | |
if not witchcraft.started then | |
witchcraft.start(_G) | |
witchcraft.started = true | |
end | |
witchcraft.step(nil, 0) | |
end | |
end | |
log("Witchcraft loaded") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment