Merge branch 'master' into PerWorldThreads.
Also fixed the AllToLua script not resolving conflicts.
This commit is contained in:
commit
af645c62c9
19
GNUmakefile
19
GNUmakefile
@ -37,8 +37,6 @@ all: MCServer/MCServer
|
|||||||
# -- according to http://stackoverflow.com/questions/6183899/undefined-reference-to-dlopen, libs must come after all sources
|
# -- according to http://stackoverflow.com/questions/6183899/undefined-reference-to-dlopen, libs must come after all sources
|
||||||
# BUILDDIR ... folder where the intermediate object files are built
|
# BUILDDIR ... folder where the intermediate object files are built
|
||||||
|
|
||||||
LNK_LIBS = -lstdc++ -ldl
|
|
||||||
|
|
||||||
ifeq ($(release),1)
|
ifeq ($(release),1)
|
||||||
################
|
################
|
||||||
# release build - fastest run-time, no gdb support
|
# release build - fastest run-time, no gdb support
|
||||||
@ -83,6 +81,23 @@ endif
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###################################################
|
||||||
|
# Set the link libraries based on the OS
|
||||||
|
# Linux uses libdl
|
||||||
|
# FreeBSD uses libltdl
|
||||||
|
# TODO: other OSs?
|
||||||
|
|
||||||
|
UNAME := $(shell uname -s)
|
||||||
|
ifeq ($(UNAME),Linux)
|
||||||
|
LNK_LIBS = -lstdc++ -ldl
|
||||||
|
else
|
||||||
|
LNK_LIBS = -lstdc++ -lltdl
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
################
|
################
|
||||||
# 32-bit build override in 64-bit build environments
|
# 32-bit build override in 64-bit build environments
|
||||||
# - so that BearBin doesn't need to modify his makefile after each makefile change :)
|
# - so that BearBin doesn't need to modify his makefile after each makefile change :)
|
||||||
|
@ -336,27 +336,3 @@ function HandleConsoleUnload(Split)
|
|||||||
Out = Out .. "Num loaded chunks after: " .. cRoot:Get():GetTotalChunkCount();
|
Out = Out .. "Num loaded chunks after: " .. cRoot:Get():GetTotalChunkCount();
|
||||||
return true, Out;
|
return true, Out;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Helper functions:
|
|
||||||
|
|
||||||
--- Returns the list of players banned by name, separated by ", "
|
|
||||||
function BanListByName()
|
|
||||||
local NumValues = BannedPlayersIni:NumValues("Banned");
|
|
||||||
local Banned = {};
|
|
||||||
local KeyID = BannedPlayersIni:FindKey("Banned");
|
|
||||||
for i = 1, NumValues do
|
|
||||||
local PlayerName = BannedPlayersIni:ValueName(KeyID, i - 1);
|
|
||||||
if (BannedPlayersIni:GetValueB("Banned", PlayerName)) then
|
|
||||||
-- Player listed AND banned
|
|
||||||
table.insert(Banned, PlayerName);
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return table.concat(Banned, ", ");
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Returns the list of players banned by IP, separated by ", "
|
|
||||||
function BanListByIPs()
|
|
||||||
-- TODO: No IP ban implemented yet
|
|
||||||
return "";
|
|
||||||
end
|
|
||||||
|
29
MCServer/Plugins/Core/do.lua
Normal file
29
MCServer/Plugins/Core/do.lua
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
function HandleDoCommand( Split, Player )
|
||||||
|
|
||||||
|
if #Split < 3 then
|
||||||
|
SendMessage( "Usage: /do <player> <command> [arguments]" )
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get the command and arguments.
|
||||||
|
local newSplit = table.concat( Split, " ", 3 )
|
||||||
|
|
||||||
|
local pluginManager = cRoot:Get():GetPluginManager()
|
||||||
|
pluginManager:ExecuteCommand( Split[2], newSplit )
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function HandleSudoCommand ( Split, Player )
|
||||||
|
|
||||||
|
if #Split < 3 then
|
||||||
|
SendMessage( "Usage: /sudo <player> <command> [arguments]" )
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get the command and arguments.
|
||||||
|
local newSplit = table.concat( Split, " ", 3 )
|
||||||
|
|
||||||
|
local pluginManager = cRoot:Get():GetPluginManager()
|
||||||
|
pluginManager:ForceExecuteCommand( Split[2], newSplit )
|
||||||
|
|
||||||
|
end
|
@ -1,3 +1,162 @@
|
|||||||
function SetBackCoordinates( Player )
|
function SetBackCoordinates( Player )
|
||||||
BackCoords[Player:GetName()] = Vector3i( Player:GetPosX(), Player:GetPosY(), Player:GetPosZ() )
|
BackCoords[Player:GetName()] = Vector3i( Player:GetPosX(), Player:GetPosY(), Player:GetPosZ() )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function SendMessage(a_Player, a_Message)
|
||||||
|
if (g_UsePrefixes) then
|
||||||
|
a_Player:SendMessage(cChatColor.Yellow .. "[INFO] " .. cChatColor.White .. a_Message)
|
||||||
|
else
|
||||||
|
a_Player:SendMessage(cChatColor.Yellow .. a_Message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SendMessageSuccess(a_Player, a_Message)
|
||||||
|
if (g_UsePrefixes) then
|
||||||
|
a_Player:SendMessage(cChatColor.Green .. "[INFO] " .. cChatColor.White .. a_Message)
|
||||||
|
else
|
||||||
|
a_Player:SendMessage(cChatColor.Green .. a_Message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SendMessageFailure(a_Player, a_Message)
|
||||||
|
if (g_UsePrefixes) then
|
||||||
|
a_Player:SendMessage(cChatColor.Red .. "[INFO] " .. cChatColor.White .. a_Message)
|
||||||
|
else
|
||||||
|
a_Player:SendMessage(cChatColor.Red .. a_Message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the list of players banned by name, separated by ", "
|
||||||
|
function BanListByName()
|
||||||
|
local NumValues = BannedPlayersIni:NumValues("Banned");
|
||||||
|
local Banned = {};
|
||||||
|
local KeyID = BannedPlayersIni:FindKey("Banned");
|
||||||
|
for i = 1, NumValues do
|
||||||
|
local PlayerName = BannedPlayersIni:ValueName(KeyID, i - 1);
|
||||||
|
if (BannedPlayersIni:GetValueB("Banned", PlayerName)) then
|
||||||
|
-- Player listed AND banned
|
||||||
|
table.insert(Banned, PlayerName);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return table.concat(Banned, ", ");
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Returns the list of players banned by IP, separated by ", "
|
||||||
|
function BanListByIPs()
|
||||||
|
-- TODO: No IP ban implemented yet
|
||||||
|
return "";
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Kicks a player by name, with the specified reason; returns bool whether found and player's real name
|
||||||
|
function KickPlayer( PlayerName, Reason )
|
||||||
|
|
||||||
|
local RealName = ""
|
||||||
|
if (Reason == nil) then
|
||||||
|
Reason = "You have been kicked"
|
||||||
|
end
|
||||||
|
|
||||||
|
local FoundPlayerCallback = function( a_Player )
|
||||||
|
RealName = a_Player:GetName()
|
||||||
|
|
||||||
|
local Server = cRoot:Get():GetServer()
|
||||||
|
LOGINFO( "'" .. RealName .. "' is being kicked for ( "..Reason..") " )
|
||||||
|
Server:SendMessage("Kicking " .. RealName)
|
||||||
|
|
||||||
|
a_Player:GetClientHandle():Kick(Reason)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not cRoot:Get():FindAndDoWithPlayer( PlayerName, FoundPlayerCallback ) then
|
||||||
|
-- Could not find player
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
return true, RealName -- Player has been kicked
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ReturnColorFromChar( Split, char )
|
||||||
|
|
||||||
|
-- Check if the char represents a color. Else return nil.
|
||||||
|
if char == "0" then
|
||||||
|
return cChatColor.Black
|
||||||
|
elseif char == "1" then
|
||||||
|
return cChatColor.Navy
|
||||||
|
elseif char == "2" then
|
||||||
|
return cChatColor.Green
|
||||||
|
elseif char == "3" then
|
||||||
|
return cChatColor.Blue
|
||||||
|
elseif char == "4" then
|
||||||
|
return cChatColor.Red
|
||||||
|
elseif char == "5" then
|
||||||
|
return cChatColor.Purple
|
||||||
|
elseif char == "6" then
|
||||||
|
return cChatColor.Gold
|
||||||
|
elseif char == "7" then
|
||||||
|
return cChatColor.LightGray
|
||||||
|
elseif char == "8" then
|
||||||
|
return cChatColor.Gray
|
||||||
|
elseif char == "9" then
|
||||||
|
return cChatColor.DarkPurple
|
||||||
|
elseif char == "a" then
|
||||||
|
return cChatColor.LightGreen
|
||||||
|
elseif char == "b" then
|
||||||
|
return cChatColor.LightBlue
|
||||||
|
elseif char == "c" then
|
||||||
|
return cChatColor.Rose
|
||||||
|
elseif char == "d" then
|
||||||
|
return cChatColor.LightPurple
|
||||||
|
elseif char == "e" then
|
||||||
|
return cChatColor.Yellow
|
||||||
|
elseif char == "f" then
|
||||||
|
return cChatColor.White
|
||||||
|
elseif char == "k" then
|
||||||
|
return cChatColor.Random
|
||||||
|
elseif char == "l" then
|
||||||
|
return cChatColor.Bold
|
||||||
|
elseif char == "m" then
|
||||||
|
return cChatColor.Strikethrough
|
||||||
|
elseif char == "n" then
|
||||||
|
return cChatColor.Underlined
|
||||||
|
elseif char == "o" then
|
||||||
|
return cChatColor.Italic
|
||||||
|
elseif char == "r" then
|
||||||
|
return cChatColor.Plain
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function CheckHardcore(Victim)
|
||||||
|
if HardCore == "true" then
|
||||||
|
if Victim:IsPlayer() == true then
|
||||||
|
local KilledPlayer = tolua.cast(Victim, "cPlayer")
|
||||||
|
BanPlayer(KilledPlayer:GetName(), "You died, haha. Good game, bro.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Teleports a_SrcPlayer to a player named a_DstPlayerName; if a_TellDst is true, will send a notice to the destination player
|
||||||
|
function TeleportToPlayer( a_SrcPlayer, a_DstPlayerName, a_TellDst )
|
||||||
|
|
||||||
|
local teleport = function(OtherPlayer)
|
||||||
|
|
||||||
|
if OtherPlayer == a_SrcPlayer then
|
||||||
|
-- Asked to teleport to self?
|
||||||
|
SendMessageFailure( a_SrcPlayer, "Y' can't teleport to yerself!" )
|
||||||
|
else
|
||||||
|
SetBackCoordinates( a_SrcPlayer )
|
||||||
|
a_SrcPlayer:TeleportToEntity( OtherPlayer )
|
||||||
|
SendMessageSuccess( a_SrcPlayer, "You teleported to " .. OtherPlayer:GetName() .. "!" )
|
||||||
|
if (a_TellDst) then
|
||||||
|
SendMessage( OtherPlayer, Player:GetName().." teleported to you!" )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local World = a_SrcPlayer:GetWorld()
|
||||||
|
if not World:DoWithPlayer(a_DstPlayerName, teleport) then
|
||||||
|
SendMessageFailure( a_SrcPlayer, "Can't find player " .. a_DstPlayerName)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
@ -17,30 +17,3 @@ function HandleKickCommand( Split, Player )
|
|||||||
return true
|
return true
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Kicks a player by name, with the specified reason; returns bool whether found and player's real name
|
|
||||||
function KickPlayer( PlayerName, Reason )
|
|
||||||
|
|
||||||
local RealName = ""
|
|
||||||
if (Reason == nil) then
|
|
||||||
Reason = "You have been kicked"
|
|
||||||
end
|
|
||||||
|
|
||||||
local FoundPlayerCallback = function( a_Player )
|
|
||||||
RealName = a_Player:GetName()
|
|
||||||
|
|
||||||
local Server = cRoot:Get():GetServer()
|
|
||||||
LOGINFO( "'" .. RealName .. "' is being kicked for ( "..Reason..") " )
|
|
||||||
Server:SendMessage("Kicking " .. RealName)
|
|
||||||
|
|
||||||
a_Player:GetClientHandle():Kick(Reason)
|
|
||||||
end
|
|
||||||
|
|
||||||
if not cRoot:Get():FindAndDoWithPlayer( PlayerName, FoundPlayerCallback ) then
|
|
||||||
-- Could not find player
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
return true, RealName -- Player has been kicked
|
|
||||||
|
|
||||||
end
|
|
||||||
|
@ -7,6 +7,11 @@ Messages = {}
|
|||||||
Destination = {}
|
Destination = {}
|
||||||
--END VARIABLES
|
--END VARIABLES
|
||||||
|
|
||||||
|
-- Configuration
|
||||||
|
-- Use prefixes or not.
|
||||||
|
-- If set to true, messages are prefixed, e. g. "[FATAL]". If false, messages are colored.
|
||||||
|
g_UsePrefixes = true
|
||||||
|
|
||||||
--COMMENCE AWESOMENESS!
|
--COMMENCE AWESOMENESS!
|
||||||
function Initialize( Plugin )
|
function Initialize( Plugin )
|
||||||
PLUGIN = Plugin
|
PLUGIN = Plugin
|
||||||
@ -62,6 +67,8 @@ function Initialize( Plugin )
|
|||||||
PluginManager:BindCommand("/viewdistance", "core.viewdistance", HandleViewDistanceCommand, " [".. cClientHandle.MIN_VIEW_DISTANCE .."-".. cClientHandle.MAX_VIEW_DISTANCE .."] - Change your view distance")
|
PluginManager:BindCommand("/viewdistance", "core.viewdistance", HandleViewDistanceCommand, " [".. cClientHandle.MIN_VIEW_DISTANCE .."-".. cClientHandle.MAX_VIEW_DISTANCE .."] - Change your view distance")
|
||||||
PluginManager:BindCommand("/weather", "core.weather", HandleWeatherCommand, " ~ Change world weather")
|
PluginManager:BindCommand("/weather", "core.weather", HandleWeatherCommand, " ~ Change world weather")
|
||||||
PluginManager:BindCommand("/worlds", "core.worlds", HandleWorldsCommand, " - Shows a list of all the worlds")
|
PluginManager:BindCommand("/worlds", "core.worlds", HandleWorldsCommand, " - Shows a list of all the worlds")
|
||||||
|
PluginManager:BindCommand("/sudo", "core.sudo", HandleSudoCommand, " - Runs a command as a player, ignoring permissions")
|
||||||
|
PluginManager:BindCommand("/do", "core.do", HandleDoCommand, " - Runs a command as a player.")
|
||||||
|
|
||||||
InitConsoleCommands()
|
InitConsoleCommands()
|
||||||
|
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
-- Use prefixes or not.
|
|
||||||
-- If set to true, messages are prefixed, e. g. "[FATAL]". If false, messages are colored.
|
|
||||||
g_UsePrefixes = true
|
|
||||||
|
|
||||||
function SendMessage(a_Player, a_Message)
|
|
||||||
if (g_UsePrefixes) then
|
|
||||||
a_Player:SendMessage(cChatColor.Yellow .. "[INFO] " .. cChatColor.White .. a_Message)
|
|
||||||
else
|
|
||||||
a_Player:SendMessage(cChatColor.Yellow .. a_Message)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SendMessageSuccess(a_Player, a_Message)
|
|
||||||
if (g_UsePrefixes) then
|
|
||||||
a_Player:SendMessage(cChatColor.Green .. "[INFO] " .. cChatColor.White .. a_Message)
|
|
||||||
else
|
|
||||||
a_Player:SendMessage(cChatColor.Green .. a_Message)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SendMessageFailure(a_Player, a_Message)
|
|
||||||
if (g_UsePrefixes) then
|
|
||||||
a_Player:SendMessage(cChatColor.Red .. "[INFO] " .. cChatColor.White .. a_Message)
|
|
||||||
else
|
|
||||||
a_Player:SendMessage(cChatColor.Red .. a_Message)
|
|
||||||
end
|
|
||||||
end
|
|
@ -42,53 +42,3 @@ function ShowMOTDTo( Player )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ReturnColorFromChar( Split, char )
|
|
||||||
|
|
||||||
-- Check if the char represents a color. Else return nil.
|
|
||||||
if char == "0" then
|
|
||||||
return cChatColor.Black
|
|
||||||
elseif char == "1" then
|
|
||||||
return cChatColor.Navy
|
|
||||||
elseif char == "2" then
|
|
||||||
return cChatColor.Green
|
|
||||||
elseif char == "3" then
|
|
||||||
return cChatColor.Blue
|
|
||||||
elseif char == "4" then
|
|
||||||
return cChatColor.Red
|
|
||||||
elseif char == "5" then
|
|
||||||
return cChatColor.Purple
|
|
||||||
elseif char == "6" then
|
|
||||||
return cChatColor.Gold
|
|
||||||
elseif char == "7" then
|
|
||||||
return cChatColor.LightGray
|
|
||||||
elseif char == "8" then
|
|
||||||
return cChatColor.Gray
|
|
||||||
elseif char == "9" then
|
|
||||||
return cChatColor.DarkPurple
|
|
||||||
elseif char == "a" then
|
|
||||||
return cChatColor.LightGreen
|
|
||||||
elseif char == "b" then
|
|
||||||
return cChatColor.LightBlue
|
|
||||||
elseif char == "c" then
|
|
||||||
return cChatColor.Rose
|
|
||||||
elseif char == "d" then
|
|
||||||
return cChatColor.LightPurple
|
|
||||||
elseif char == "e" then
|
|
||||||
return cChatColor.Yellow
|
|
||||||
elseif char == "f" then
|
|
||||||
return cChatColor.White
|
|
||||||
elseif char == "k" then
|
|
||||||
return cChatColor.Random
|
|
||||||
elseif char == "l" then
|
|
||||||
return cChatColor.Bold
|
|
||||||
elseif char == "m" then
|
|
||||||
return cChatColor.Strikethrough
|
|
||||||
elseif char == "n" then
|
|
||||||
return cChatColor.Underlined
|
|
||||||
elseif char == "o" then
|
|
||||||
return cChatColor.Italic
|
|
||||||
elseif char == "r" then
|
|
||||||
return cChatColor.Plain
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
@ -54,12 +54,3 @@ function OnKilling(Victim, Killer)
|
|||||||
CheckHardcore(Victim)
|
CheckHardcore(Victim)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function CheckHardcore(Victim)
|
|
||||||
if HardCore == "true" then
|
|
||||||
if Victim:IsPlayer() == true then
|
|
||||||
local KilledPlayer = tolua.cast(Victim, "cPlayer")
|
|
||||||
BanPlayer(KilledPlayer:GetName(), "You died, haha. Good game, bro.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -72,29 +72,3 @@ function HandleTPAcceptCommand( Split, Player )
|
|||||||
return true
|
return true
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Teleports a_SrcPlayer to a player named a_DstPlayerName; if a_TellDst is true, will send a notice to the destination player
|
|
||||||
function TeleportToPlayer( a_SrcPlayer, a_DstPlayerName, a_TellDst )
|
|
||||||
|
|
||||||
local teleport = function(OtherPlayer)
|
|
||||||
|
|
||||||
if OtherPlayer == a_SrcPlayer then
|
|
||||||
-- Asked to teleport to self?
|
|
||||||
SendMessageFailure( a_SrcPlayer, "Y' can't teleport to yerself!" )
|
|
||||||
else
|
|
||||||
SetBackCoordinates( a_SrcPlayer )
|
|
||||||
a_SrcPlayer:TeleportToEntity( OtherPlayer )
|
|
||||||
SendMessageSuccess( a_SrcPlayer, "You teleported to " .. OtherPlayer:GetName() .. "!" )
|
|
||||||
if (a_TellDst) then
|
|
||||||
SendMessage( OtherPlayer, Player:GetName().." teleported to you!" )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
local World = a_SrcPlayer:GetWorld()
|
|
||||||
if not World:DoWithPlayer(a_DstPlayerName, teleport) then
|
|
||||||
SendMessageFailure( a_SrcPlayer, "Can't find player " .. a_DstPlayerName)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
20
MCServer/Plugins/TransAPI/LICENSE
Normal file
20
MCServer/Plugins/TransAPI/LICENSE
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2013 Alexander Harkness
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
the Software without restriction, including without limitation the rights to
|
||||||
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||||
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
20
MCServer/Plugins/TransAPI/README.md
Normal file
20
MCServer/Plugins/TransAPI/README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
TransAPI
|
||||||
|
========
|
||||||
|
|
||||||
|
A plugin translation API for MCServer.
|
||||||
|
|
||||||
|
TransAPI is designed to be used with the [client library](https://github.com/bearbin/transapi-client), however there is also a stable API available for use.
|
||||||
|
|
||||||
|
API
|
||||||
|
---
|
||||||
|
|
||||||
|
GetLanguage ( cPlayer )
|
||||||
|
Returns the user's preferred language (or server default if not set). (ISO 639-1 language code)
|
||||||
|
|
||||||
|
GetConsoleLanguage ( )
|
||||||
|
Returns the preferred language for console text. (ISO 639-1 language code)
|
||||||
|
|
||||||
|
Commands
|
||||||
|
--------
|
||||||
|
|
||||||
|
* /language [lang] - Takes a language code (ISO 639-1) and sets the user's preferred language to that. (tranapi.setlang)
|
91
MCServer/Plugins/TransAPI/main.lua
Normal file
91
MCServer/Plugins/TransAPI/main.lua
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
-- This plugin copyright Alexander Harkness 2013, licensed under the MIT license.
|
||||||
|
|
||||||
|
-- Configuration
|
||||||
|
g_ServerLang = "en"
|
||||||
|
g_ConsoleLang = "en"
|
||||||
|
|
||||||
|
-- Global Variables
|
||||||
|
g_Plugin = nil
|
||||||
|
g_PluginManager = nil
|
||||||
|
g_PluginDir = nil
|
||||||
|
g_UserData = nil
|
||||||
|
|
||||||
|
-- START WITH DA AWESOME!
|
||||||
|
function Initialize( Plugin )
|
||||||
|
|
||||||
|
-- Set up the globals.
|
||||||
|
g_Plugin = Plugin
|
||||||
|
g_PluginManager = cRoot:Get():GetPluginManager()
|
||||||
|
g_PluginDir = Plugin:GetDirectory()
|
||||||
|
|
||||||
|
-- Set up the plugin details.
|
||||||
|
Plugin:SetName( "TransAPI" )
|
||||||
|
Plugin:SetVersion( 1 )
|
||||||
|
|
||||||
|
-- This is the place for commands!
|
||||||
|
g_PluginManager:BindCommand("/language", "transapi.setlang", HandleLanguageCommand, " - Set your preferred language (use ISO 639-1)")
|
||||||
|
|
||||||
|
-- Load the userdata file.
|
||||||
|
g_UserData = cIniFile( g_PluginDir .. "/userdata.ini" )
|
||||||
|
if g_UserData ~= true then
|
||||||
|
LOGERROR( "TransAPI INI file could not be opened!" )
|
||||||
|
end
|
||||||
|
|
||||||
|
LOG( "Initialized " .. Plugin:GetName() .. " v." .. Plugin:GetVersion() )
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetLanguage( Player )
|
||||||
|
|
||||||
|
-- Returns a language to use.
|
||||||
|
if g_UserData:ReadFile() == true then
|
||||||
|
local userLang = g_UserData:GetValueSet( Player:GetName(), "language", "false" )
|
||||||
|
g_UserData:WriteFile()
|
||||||
|
end
|
||||||
|
|
||||||
|
if userLang == "false" then
|
||||||
|
return g_ServerLang
|
||||||
|
else
|
||||||
|
return userLang
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function GetConsoleLanguage()
|
||||||
|
-- Return the language to use for console messages.
|
||||||
|
return g_ConsoleLang
|
||||||
|
end
|
||||||
|
|
||||||
|
function HandleLanguageCommand ( Split, Player )
|
||||||
|
|
||||||
|
-- If the user is not setting the language, tell them the currently selected one.
|
||||||
|
if #Split ~= 2 then
|
||||||
|
|
||||||
|
local userLang = g_UserData:GetValueSet( Player:GetName(), "language", "false" )
|
||||||
|
if userLang == "false" then
|
||||||
|
return g_ServerLang
|
||||||
|
else
|
||||||
|
return userLang
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Set the language.
|
||||||
|
local success = g_UserData:SetValue( Player:GetName(), "language" Split[2] )
|
||||||
|
g_UserData:WriteFile()
|
||||||
|
|
||||||
|
if not success then
|
||||||
|
Player:SendMessage( "Language could not be set!" )
|
||||||
|
else
|
||||||
|
Player:SendMessage( "Language set!" )
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function OnDisable()
|
||||||
|
LOG( "Disabled TransAPI!" )
|
||||||
|
end
|
@ -72,6 +72,8 @@ Wool = String, 1:1, 1:2, 2:1, 2:2
|
|||||||
TNT = Gunpowder, 1:1, 3:1, 2:2, 1:3, 3:3 | Sand, 2:1, 1:2, 3:2, 2:3
|
TNT = Gunpowder, 1:1, 3:1, 2:2, 1:3, 3:3 | Sand, 2:1, 1:2, 3:2, 2:3
|
||||||
PillarQuartzBlock = QuartzSlab, 1:1, 1:2
|
PillarQuartzBlock = QuartzSlab, 1:1, 1:2
|
||||||
ChiseledQuartzBlock, 2 = QuartzBlock, 1:1, 1:2
|
ChiseledQuartzBlock, 2 = QuartzBlock, 1:1, 1:2
|
||||||
|
CoalBlock = Coal, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||||
|
HayBale = Wheat, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||||
|
|
||||||
# Slabs:
|
# Slabs:
|
||||||
StoneSlab, 6 = Stone, 1:1, 2:1, 3:1
|
StoneSlab, 6 = Stone, 1:1, 2:1, 3:1
|
||||||
@ -105,7 +107,8 @@ SmoothSandstone, 4 = Sandstone, 1:1, 1:2, 2:1, 2:2
|
|||||||
OrnamentSandstone = SandstoneSlab, 1:1, 1:2
|
OrnamentSandstone = SandstoneSlab, 1:1, 1:2
|
||||||
JackOLantern = Pumpkin, 1:1 | Torch, 1:2
|
JackOLantern = Pumpkin, 1:1 | Torch, 1:2
|
||||||
|
|
||||||
|
# Other
|
||||||
|
Carpet = Wool, 1:3, 2:3
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -157,6 +160,7 @@ FishingRod = Stick, 3:3, 2:2, 1:1 | String, 1:2, 1:3
|
|||||||
Shears = IronIngot, 1:1, 2:2
|
Shears = IronIngot, 1:1, 2:2
|
||||||
Shears = IronIngot, 2:1, 1:2
|
Shears = IronIngot, 2:1, 1:2
|
||||||
FireCharge = BlazePowder, * | Coal, * | Gunpowder, *
|
FireCharge = BlazePowder, * | Coal, * | Gunpowder, *
|
||||||
|
Lead = String, 1:1, 1:2, 2:1, 3:3 | Slimeball, 2:2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -271,12 +275,13 @@ Bread = Wheat, 1:1, 2:1, 3:1
|
|||||||
Sugar = Sugarcane, *
|
Sugar = Sugarcane, *
|
||||||
Cake = MilkBucket, 1:1, 2:1, 3:1 | Sugar, 1:2, 3:2 | Egg, 2:2 | Wheat, 1:3, 2:3, 3:3
|
Cake = MilkBucket, 1:1, 2:1, 3:1 | Sugar, 1:2, 3:2 | Egg, 2:2 | Wheat, 1:3, 2:3, 3:3
|
||||||
Cookie = Wheat, *, * | CocoaBeans, *
|
Cookie = Wheat, *, * | CocoaBeans, *
|
||||||
GoldenApple = RedApple, 2:2 | GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
|
GoldenApple = RedApple, 2:2 | GoldIngot, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
|
||||||
EnchantedGoldenApple = RedApple, 2:2 | GoldBlock, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
|
EnchantedGoldenApple = RedApple, 2:2 | GoldBlock, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
|
||||||
Melon = MelonSlice, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
Melon = MelonSlice, 1:1, 1:2, 1:3, 2:1, 2:2, 2:3, 3:1, 3:2, 3:3
|
||||||
MelonSeeds = MelonSlice, *
|
MelonSeeds = MelonSlice, *
|
||||||
PumpkinSeeds, 4 = Pumpkin, *
|
PumpkinSeeds, 4 = Pumpkin, *
|
||||||
PumpkinPie = Pumpkin, * | Sugar, * | egg, *
|
PumpkinPie = Pumpkin, * | Sugar, * | egg, *
|
||||||
|
Wheat, 9 = Haybale, *
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -293,6 +298,8 @@ Diamond, 9 = DiamondBlock, *
|
|||||||
LapisLazuli, 9 = LapisBlock, *
|
LapisLazuli, 9 = LapisBlock, *
|
||||||
Emerald, 9 = EmeraldBlock, *
|
Emerald, 9 = EmeraldBlock, *
|
||||||
RedstoneDust, 9 = RedstoneBlock, *
|
RedstoneDust, 9 = RedstoneBlock, *
|
||||||
|
Coal, 9 = CoalBlock, *
|
||||||
|
Clay, 4 = ClayBlock, *
|
||||||
|
|
||||||
Painting = Stick, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Wool, 2:2
|
Painting = Stick, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Wool, 2:2
|
||||||
ItemFrame = Stick, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Leather, 2:2
|
ItemFrame = Stick, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3 | Leather, 2:2
|
||||||
@ -382,7 +389,7 @@ BrewingStand = Cobblestone, 1:2, 2:2, 3:2 | BlazeRod, 2:1
|
|||||||
BlazePowder, 2 = BlazeRod, *
|
BlazePowder, 2 = BlazeRod, *
|
||||||
MagmaCream = SlimeBall, * | BlazePowder, *
|
MagmaCream = SlimeBall, * | BlazePowder, *
|
||||||
FermentedSpiderEye = SpiderEye, * | Sugar, * | BrownMushroom, *
|
FermentedSpiderEye = SpiderEye, * | Sugar, * | BrownMushroom, *
|
||||||
GlisteringMelon = MelonSlice, * | GoldNugget, *
|
GlisteringMelon = MelonSlice, 2:2 | GoldNugget, 1:1, 1:2, 1:3, 2:1, 2:3, 3:1, 3:2, 3:3
|
||||||
GoldNugget, 9 = GoldIngot, *
|
GoldNugget, 9 = GoldIngot, *
|
||||||
EnchantmentTable = Obsidian, 1:3, 2:3, 3:3, 2:2 | Diamond, 1:2, 3:2 | Book, 2:1
|
EnchantmentTable = Obsidian, 1:3, 2:3, 3:3, 2:2 | Diamond, 1:2, 3:2 | Book, 2:1
|
||||||
|
|
||||||
|
@ -13,5 +13,5 @@ Color=2
|
|||||||
Inherits=Default
|
Inherits=Default
|
||||||
|
|
||||||
[Default]
|
[Default]
|
||||||
Permissions=core.build,core.help,core.playerlist,core.pluginlist,core.spawn
|
Permissions=core.build,core.help,core.playerlist,core.pluginlist,core.spawn,transapi.setlang
|
||||||
Color=7
|
Color=7
|
@ -281,7 +281,8 @@ pillarquartzblock=155:2
|
|||||||
quartzstairs=156
|
quartzstairs=156
|
||||||
activatorrail=157
|
activatorrail=157
|
||||||
dropper=158
|
dropper=158
|
||||||
|
haybale=170
|
||||||
|
carpet=171
|
||||||
ironshovel=256
|
ironshovel=256
|
||||||
ironspade=256
|
ironspade=256
|
||||||
ironpickaxe=257
|
ironpickaxe=257
|
||||||
@ -294,6 +295,7 @@ redapple=260
|
|||||||
bow=261
|
bow=261
|
||||||
arrow=262
|
arrow=262
|
||||||
coal=263
|
coal=263
|
||||||
|
coalblock=173
|
||||||
charcoal=263:1
|
charcoal=263:1
|
||||||
diamond=264
|
diamond=264
|
||||||
ironingot=265
|
ironingot=265
|
||||||
@ -528,6 +530,7 @@ netherbrickitem=405
|
|||||||
netherquartz=406
|
netherquartz=406
|
||||||
tntminecart=407
|
tntminecart=407
|
||||||
hopperminecart=408
|
hopperminecart=408
|
||||||
|
lead=420
|
||||||
|
|
||||||
goldrecord=2256
|
goldrecord=2256
|
||||||
greenrecord=2257
|
greenrecord=2257
|
||||||
@ -541,3 +544,6 @@ stradrecord=2264
|
|||||||
wardrecord=2265
|
wardrecord=2265
|
||||||
11record=2266
|
11record=2266
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ DefaultWorld=world
|
|||||||
Plugin=Core
|
Plugin=Core
|
||||||
Plugin=ChunkWorx
|
Plugin=ChunkWorx
|
||||||
Plugin=ChatLog
|
Plugin=ChatLog
|
||||||
|
Plugin=TransAPI
|
||||||
|
|
||||||
[Monsters]
|
[Monsters]
|
||||||
AnimalsOn=0
|
AnimalsOn=0
|
||||||
|
62
Tests/ConsoleColors/ConsoleColors.cpp
Normal file
62
Tests/ConsoleColors/ConsoleColors.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
// ConsoleColors.cpp
|
||||||
|
|
||||||
|
// Tests the various console color combinations
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// Evaluates to the number of elements in an array (compile-time!)
|
||||||
|
#define ARRAYCOUNT(X) (sizeof(X) / sizeof(*(X)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
static const char * Attribs[] =
|
||||||
|
{
|
||||||
|
"0", // All attribs off
|
||||||
|
"1", // bold
|
||||||
|
"2", // faint
|
||||||
|
"7", // inverse
|
||||||
|
"1;7", // bold inverse
|
||||||
|
"2;7", // faint inverse
|
||||||
|
} ;
|
||||||
|
for (int i = 0; i < ARRAYCOUNT(Attribs); i++)
|
||||||
|
{
|
||||||
|
const char * Attrib = Attribs[i];
|
||||||
|
for (int fg = 30; fg <= 37; fg++)
|
||||||
|
{
|
||||||
|
for (int bg = 40; bg <= 47; bg++)
|
||||||
|
{
|
||||||
|
printf("\x1b[%s;%d;%dm %s;%d;%d ", Attrib, fg, bg, Attrib, fg, bg);
|
||||||
|
} // for bg
|
||||||
|
puts("\x1b[0m"); // Reset terminal back to normal colors for the newline
|
||||||
|
} // for fg
|
||||||
|
} // for i - Attribs[]
|
||||||
|
|
||||||
|
for (int i = 1; i < ARRAYCOUNT(Attribs); i++)
|
||||||
|
{
|
||||||
|
const char * Attrib = Attribs[i];
|
||||||
|
for (int fg = 30; fg <= 37; fg++)
|
||||||
|
{
|
||||||
|
for (int bg = 40; bg <= 47; bg++)
|
||||||
|
{
|
||||||
|
printf("\x1b[%d;%d;%sm %d;%d;%s ", fg, bg, Attrib, fg, bg, Attrib);
|
||||||
|
} // for bg
|
||||||
|
puts("\x1b[0m"); // Reset terminal back to normal colors for the newline
|
||||||
|
} // for fg
|
||||||
|
} // for i - Attribs[]
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -8,8 +8,10 @@
|
|||||||
|
|
||||||
|
|
||||||
:: If there was a Git conflict, resolve it by resetting to HEAD; we're regenerating the files from scratch anyway
|
:: If there was a Git conflict, resolve it by resetting to HEAD; we're regenerating the files from scratch anyway
|
||||||
git checkout -- Bindings.cpp
|
git checkout --ours Bindings.cpp
|
||||||
git checkout -- Bindings.h
|
git add -u Bindings.cpp
|
||||||
|
git checkout --ours Bindings.h
|
||||||
|
git add -u Bindings.h
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
** Lua binding: AllToLua
|
** Lua binding: AllToLua
|
||||||
** Generated automatically by tolua++-1.0.92 on 08/12/13 21:48:05.
|
** Generated automatically by tolua++-1.0.92 on 08/13/13 23:00:22.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
@ -28856,6 +28856,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
|||||||
tolua_constant(tolua_S,"E_BLOCK_NETHER_QUARTZ_ORE",E_BLOCK_NETHER_QUARTZ_ORE);
|
tolua_constant(tolua_S,"E_BLOCK_NETHER_QUARTZ_ORE",E_BLOCK_NETHER_QUARTZ_ORE);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_HOPPER",E_BLOCK_HOPPER);
|
tolua_constant(tolua_S,"E_BLOCK_HOPPER",E_BLOCK_HOPPER);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_QUARTZ_BLOCK",E_BLOCK_QUARTZ_BLOCK);
|
tolua_constant(tolua_S,"E_BLOCK_QUARTZ_BLOCK",E_BLOCK_QUARTZ_BLOCK);
|
||||||
|
tolua_constant(tolua_S,"E_BLOCK_QUARTZ_STAIR",E_BLOCK_QUARTZ_STAIR);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_ACTIVATOR_RAIL",E_BLOCK_ACTIVATOR_RAIL);
|
tolua_constant(tolua_S,"E_BLOCK_ACTIVATOR_RAIL",E_BLOCK_ACTIVATOR_RAIL);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_DROPPER",E_BLOCK_DROPPER);
|
tolua_constant(tolua_S,"E_BLOCK_DROPPER",E_BLOCK_DROPPER);
|
||||||
tolua_constant(tolua_S,"E_BLOCK_CARPET",E_BLOCK_CARPET);
|
tolua_constant(tolua_S,"E_BLOCK_CARPET",E_BLOCK_CARPET);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
** Lua binding: AllToLua
|
** Lua binding: AllToLua
|
||||||
** Generated automatically by tolua++-1.0.92 on 08/12/13 21:48:06.
|
** Generated automatically by tolua++-1.0.92 on 08/13/13 23:00:22.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Exported function */
|
/* Exported function */
|
||||||
|
@ -165,6 +165,7 @@ enum ENUM_BLOCK_ID
|
|||||||
E_BLOCK_NETHER_QUARTZ_ORE = 153,
|
E_BLOCK_NETHER_QUARTZ_ORE = 153,
|
||||||
E_BLOCK_HOPPER = 154,
|
E_BLOCK_HOPPER = 154,
|
||||||
E_BLOCK_QUARTZ_BLOCK = 155,
|
E_BLOCK_QUARTZ_BLOCK = 155,
|
||||||
|
E_BLOCK_QUARTZ_STAIR = 156,
|
||||||
E_BLOCK_ACTIVATOR_RAIL = 157,
|
E_BLOCK_ACTIVATOR_RAIL = 157,
|
||||||
|
|
||||||
E_BLOCK_DROPPER = 158,
|
E_BLOCK_DROPPER = 158,
|
||||||
|
@ -152,6 +152,7 @@ cBlockHandler * cBlockHandler::CreateBlockHandler(BLOCKTYPE a_BlockType)
|
|||||||
case E_BLOCK_PISTON_EXTENSION: return new cBlockPistonHeadHandler ();
|
case E_BLOCK_PISTON_EXTENSION: return new cBlockPistonHeadHandler ();
|
||||||
case E_BLOCK_PLANKS: return new cBlockWoodHandler (a_BlockType);
|
case E_BLOCK_PLANKS: return new cBlockWoodHandler (a_BlockType);
|
||||||
case E_BLOCK_PUMPKIN_STEM: return new cBlockStemsHandler (a_BlockType);
|
case E_BLOCK_PUMPKIN_STEM: return new cBlockStemsHandler (a_BlockType);
|
||||||
|
case E_BLOCK_QUARTZ_STAIR: return new cBlockStairsHandler (a_BlockType);
|
||||||
case E_BLOCK_RAIL: return new cBlockRailHandler (a_BlockType);
|
case E_BLOCK_RAIL: return new cBlockRailHandler (a_BlockType);
|
||||||
case E_BLOCK_POTATOES: return new cBlockCropsHandler (a_BlockType);
|
case E_BLOCK_POTATOES: return new cBlockCropsHandler (a_BlockType);
|
||||||
case E_BLOCK_POWERED_RAIL: return new cBlockRailHandler (a_BlockType);
|
case E_BLOCK_POWERED_RAIL: return new cBlockRailHandler (a_BlockType);
|
||||||
|
@ -791,8 +791,8 @@ void cPlayer::SendMessage(const AString & a_Message)
|
|||||||
|
|
||||||
void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
|
void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
|
||||||
{
|
{
|
||||||
m_LastGroundHeight = (float)a_PosY;
|
|
||||||
SetPosition( a_PosX, a_PosY, a_PosZ );
|
SetPosition( a_PosX, a_PosY, a_PosZ );
|
||||||
|
m_LastGroundHeight = (float)a_PosY;
|
||||||
|
|
||||||
m_World->BroadcastTeleportEntity(*this, GetClientHandle());
|
m_World->BroadcastTeleportEntity(*this, GetClientHandle());
|
||||||
m_ClientHandle->SendPlayerMoveLook();
|
m_ClientHandle->SendPlayerMoveLook();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user