#RequireContext CMapEditorPlugin
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/* Grand2020 by */
/* jovenium */
/* based on Grand2 by LeGask and Reaby */
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#Include "TextLib" as TextLib
#Include "MathLib" as MathLib
#Include "TimeLib" as TiL
#Include "MapUnits" as MapUnits
//#Setting S_HOSTNAME "http://localhost:8080"
#Setting S_HOSTNAME "https://grand2020.jovenium.net"
#Struct JsonBlock {
Text Modif;
Int3 Coord;
Text ModelName;
Integer Direction;
Text login;
Integer role;
Integer Color;
Integer Timestamp;
Boolean ForcePlace;
Boolean GhostMode;
}
#Struct JsonBlockList {
JsonBlock[] JsonBlocks;
Text token;
}
#Struct SClassicBlock {
Int3 Coord;
CMapEditorPlugin::CardinalDirections Dir;
Text Name;
Text Url;
}
#Struct SGhostBlock {
Int3 Coord;
CMapEditorPlugin::CardinalDirections Dir;
Text Name;
}
#Const Version "v0.1.3"
#Const ScriptName "Grand2020.Script.txt"
#Const C_AllowedPlaceMode [
CMapEditorPlugin::PlaceMode::Block,
CMapEditorPlugin::PlaceMode::Unknown,
CMapEditorPlugin::PlaceMode::Skin,
CMapEditorPlugin::PlaceMode::Test,
CMapEditorPlugin::PlaceMode::Plugin
]
declare Text HOST;
declare Int3 SelectionStartCoord;
declare Int3 SelectionEndCoord;
declare Integer G_TimeLastModif;
declare JsonBlockList G_ListModif;
declare Boolean ListenerRequestUp;
declare Integer G_TimeListenerClosed;
declare Text G_Token;
declare Text G_LobbyId;
declare Integer G_IsAdmin;
//layers
declare CUILayer UIModalStartOrQuit;
declare CUILayer UIMainModal;
declare CUILayer UIServerSettings;
declare CUILayer UIParameter;//icon + parameter modal
declare CUILayer UIChat;//icon + t input + chat modal
declare CUILayer UIDebugView;//debug modal
declare CUILayer UIChatPopup;//messagePopup
declare CUILayer UIUpdateModal;
Void HttpGet(Text _address) {
Http.CreateGet(_address, False);
}
CHttpRequest HttpPost(Text _address, Text[Text] _params) {
declare content = "";
foreach (Key => Param in _params) {
content = """{"data" : {{{Param}}} }""";
}
declare len = TextLib::Length(content)-1;
declare req = Http.CreatePost(_address, content,"Content-Type: application/json");
return req;
}
Text getUpdateModalManialink() {
return """
""";
}
Text getMainModalManialink() {
return """
""";
}
Text getChatManialink() {
return """
""";
}
Text getDebugViewManialink() {
return """
""";
}
Text getParameterManialink() {
return """
""";
}
Text getModalStartOrQuitManialink() {
return """
""";
}
Text getChatPopupManialink() {
return """
""";
}
Text getServerSettingsManialink(Text _HOST) {
return """
""";
}
Text getUiManialink() {
return """
""";
}
Text LineFeed() {
return """
""";
}
Void AddEventLine(Text _Line) {
LayerCustomEvent(UIDebugView,"newLine",[_Line ^ LineFeed()]);
}
Void AddChatLine(Text _Line) {
LayerCustomEvent(UIChat,"addChatLine",[_Line ^ "$z\n"]);
}
Void AddChatPopup(Text _Message, Integer _Duration, Boolean _Cut){
declare Text Message = _Message;
AddChatLine(Message);
if ((TextLib::Length(Message)) >=70 && _Cut) {
Message = TextLib::SubString(Message, 0, 70)^"...";
}
LayerCustomEvent(UIChatPopup, "addChatPopup", [Message, TextLib::ToText(_Duration)]);
}
Void AddChatPopup(Text _Message){
AddChatPopup(_Message, 3000, True);
}
Void AddModifToQueue(JsonBlock block) {
G_ListModif.JsonBlocks.add(block);
G_TimeLastModif = Now;
//log(G_TimeLastModif);
}
CHttpRequest SendCreateOrJoin(Text Message) {
declare Text[Text] json = ["data" => Message];
return HttpPost(HOST^"/"^G_LobbyId^"/join", json);
}
Void SendMessage(Text Message) {
declare Text[Text] json = ["data" => Message];
HttpPost(HOST^"/"^G_LobbyId^"/push?login="^LocalUser.Name, json);
}
Void LoopSendModif() {
if (G_TimeLastModif >= Now - 1000) return;
if (G_ListModif.JsonBlocks.count < 1) return;
log(Now);
declare Text Data = G_ListModif.tojson();
//log(Data);
SendMessage(Data);
G_ListModif.JsonBlocks.clear();
}
Text GetLatestVersion(){
declare Request = Http.CreateGet(HOST^"/version", False);
declare Text Result = "unknown";
wait(Request.IsCompleted);
if(Request.StatusCode >= 200 && Request.StatusCode < 300){
Result = Request.Result;
}
return Result;
}
Void CheckForUpdate(){
declare Text LatestVersion = "";
LatestVersion = GetLatestVersion();
if(LatestVersion == "unknown"){
AddChatPopup("$F00Editor : Something went wrong when\nchecking for update.", 5000, False);
}else if(LatestVersion != Version){
AddChatPopup("$F00Editor : An update of the plugin is\navailable. Please download it before playing.", 10000, False);
sleep(500);
LayerCustomEvent( UIUpdateModal,"showUpdate",[HOST,LatestVersion]);
UIUpdateModal.IsVisible = True;
}
}
Integer getBlockDirection(CMapEditorPlugin::CardinalDirections direction) {
switch (direction) {
case CMapEditorPlugin::CardinalDirections::North: {return 0;}
case CMapEditorPlugin::CardinalDirections::East: {return 1;}
case CMapEditorPlugin::CardinalDirections::South:{ return 2;}
case CMapEditorPlugin::CardinalDirections::West:{ return 3;}
}
return 0;
}
CMapEditorPlugin::CardinalDirections convertBlockDirection(Integer direction) {
switch (direction) {
case 0: return CMapEditorPlugin::CardinalDirections::North;
case 1: return CMapEditorPlugin::CardinalDirections::East;
case 2: return CMapEditorPlugin::CardinalDirections::South;
case 3: return CMapEditorPlugin::CardinalDirections::West;
}
return CMapEditorPlugin::CardinalDirections::North;
}
Integer getBlockColor(CMapEditorPlugin::MapElemColor _Color){
switch (_Color) {
case CMapEditorPlugin::MapElemColor::Default:{return 0;}
case CMapEditorPlugin::MapElemColor::White: {return 1;}
case CMapEditorPlugin::MapElemColor::Green: {return 2;}
case CMapEditorPlugin::MapElemColor::Blue: {return 3;}
case CMapEditorPlugin::MapElemColor::Red: {return 4;}
case CMapEditorPlugin::MapElemColor::Black: {return 5;}
}
return 0;
}
CMapEditorPlugin::MapElemColor convertBlockColor(Integer _Color){
switch (_Color) {
case 0:{return CMapEditorPlugin::MapElemColor::Default;}
case 1:{return CMapEditorPlugin::MapElemColor::White;}
case 2:{return CMapEditorPlugin::MapElemColor::Green;}
case 3:{return CMapEditorPlugin::MapElemColor::Blue;}
case 4:{return CMapEditorPlugin::MapElemColor::Red;}
case 5:{return CMapEditorPlugin::MapElemColor::Black;}
}
return CMapEditorPlugin::MapElemColor::Default;
}
Boolean IsAirGhostModeAllowed(){
//TODO : enable the airGhostMode when the macroblock set will be made and if the player have the set in his game.
return False;
}
Int3 GetOneOffsetInTheRightDirection(CBlock _block){
declare Dir = _block.Dir;
declare Int3 result;
declare Int3 OneOffset = _block.BlockUnits[0].AbsoluteOffset;
if(Dir == CMapEditorPlugin::CardinalDirections::North){
result = MapUnits::GetRotatedOffsetPositive(OneOffset, ::CardinalDirections::North ,<0,0,0>);
}else if(Dir == CMapEditorPlugin::CardinalDirections::East){
result = MapUnits::GetRotatedOffsetPositive(OneOffset, ::CardinalDirections::East ,<0,0,OneOffset.Z+1>);
}else if(Dir == CMapEditorPlugin::CardinalDirections::South){
result = MapUnits::GetRotatedOffsetPositive(OneOffset, ::CardinalDirections::South ,);
}else{
result = MapUnits::GetRotatedOffsetPositive(OneOffset, ::CardinalDirections::West ,);
}
result = _block.Coord + result;
return result;
}
Boolean DeleteOnePillar(Int3 _Coord){
declare Boolean Found = False;
declare CBlock BlockToDelete;
foreach(block in ClassicBlocks){
if(Found){
BlockToDelete = block;
break;
}else if(block.Coord == _Coord){
log("DeleteOnePillar:found");
AutoSave();
Found = True;
}
}
if(BlockToDelete != Null){
if(ClassicBlocks.exists(BlockToDelete)){
RemoveBlock(GetOneOffsetInTheRightDirection(BlockToDelete));
AutoSave();
return True;
}
}
return False;
}
//return a list of the current pillars
SClassicBlock[] GetPillars(){
declare SClassicBlock[] Result;
foreach(block in ClassicBlocks){
if(TextLib::Find("Pillar",block.BlockModel.Name,False,True)){
Result.add(SClassicBlock{Coord =block.Coord , Dir = block.Dir, Name = block.BlockModel.Name});
}
}
return Result;
}
//return the number of pillars to delete
Integer NeedToDelete(SClassicBlock[] Origin){
declare Integer Result = 0;
declare SClassicBlock[] Current;
declare Boolean Found = False;
declare Integer YieldTime = 100;
declare Integer i = 0;
Current = GetPillars();
foreach(block in Current){
Found = False;
foreach(originBlock in Origin){
if(originBlock.Coord == block.Coord && originBlock.Dir == block.Dir && originBlock.Name == block.Name){
Found = True;
i +=1;
}
}
if(!Found){
Result +=1;
}
if(i >= YieldTime){
yield;
i = 0;
}
}
return Result;
}
Void Simulation_AirMode(Integer _Delta,SClassicBlock[] _Pillars, Integer _NbBlocks, Int3 _Coord){
declare Boolean IsLastBlock = False;
declare Boolean OneBlockRemoved = True;
declare Integer Delta = _Delta;
declare Integer PillarToDelete = 0;
log("Simulation_AirMode:number block to delete:");
log(Delta);
AutoSave();
if(Delta != ClassicBlocks.count - _NbBlocks){
log("Simulation_AirMode:weird :");
log(Delta);
log(ClassicBlocks.count - _NbBlocks);
return;
}
if(Delta < 0){
}else if(Delta == 0){
log(_Pillars);
PillarToDelete = NeedToDelete(_Pillars);
while(OneBlockRemoved && PillarToDelete > 0){
OneBlockRemoved = DeleteOnePillar(_Coord);
if(OneBlockRemoved){
PillarToDelete -= 1;
}
}
}else if(Delta == 1){
IsLastBlock=True;
log("Simulation_AirMode:not deletion to do.");
}else{
while(OneBlockRemoved && Delta >= 2){
log("Simulation_AirMode:oneblockremoved");
OneBlockRemoved = DeleteOnePillar(_Coord);
Delta = ClassicBlocks.count - _NbBlocks;
log("Simulation_AirMode:Delta");
log(Delta);
}
}
}
//return a list of the current GhostBlocks
SGhostBlock[] GetStackGhostBlocks(){
declare SGhostBlock[] Result;
foreach(block in GhostBlocks){
Result.add(SGhostBlock{Coord =block.Coord , Dir = block.Dir, Name = block.BlockModel.Name});
}
return Result;
}
//return the number of pillars to delete
SGhostBlock GetGhostBlockErased(SGhostBlock[] Origin){
declare SGhostBlock Result = SGhostBlock{Coord = <-1,-1,-1>};
declare SGhostBlock[] Current;
declare Boolean Found = False;
Current = GetStackGhostBlocks();
foreach(originBlock in Origin){
Found = False;
foreach(block in Current){
if(originBlock.Coord == block.Coord && originBlock.Dir == block.Dir && originBlock.Name == block.Name){
Found = True;
}
}
if(!Found){
//if the origin block is not found in the current map, it has been removed
return originBlock;
}
}
return Result;
}
Void Simulation_GhostMode(CBlockModel _BlockModel, Int3 _Coord, CMapEditorPlugin::CardinalDirections _Dir, Boolean _Undo){
if(_Undo) Undo();
PlaceGhostBlock(_BlockModel, _Coord, _Dir);
AutoSave();
}
Int3 GetRotatedAndTranslatedOffset(Int3 OneOffset, Int3 CursorCoord, ::CardinalDirections Dir, Integer X, Integer Z){
declare Int3 result;
if(Dir == CMapEditorPlugin::CardinalDirections::North){
result = MapUnits::GetRotatedOffsetPositive(OneOffset, ::CardinalDirections::North ,<0,0,0>);
}else if(Dir == CMapEditorPlugin::CardinalDirections::East){
//translate by z in x
result = MapUnits::GetRotatedOffset(OneOffset,::CardinalDirections::East);
result = result + ;
}else if(Dir == CMapEditorPlugin::CardinalDirections::South){
// tranlate by x and z
result = MapUnits::GetRotatedOffset(OneOffset,::CardinalDirections::South);
result = result + ;
}else{
//translate by x in z
result = MapUnits::GetRotatedOffset(OneOffset,::CardinalDirections::West);
result = result + <0,0,X>;
}
result = CursorCoord + result;
return result;
}
/** Logic */
Void OnListenerResponse(Text _response) {
declare JsonBlock block;
declare JsonBlockList BlockLists;
declare CMapEditorPlugin::MapElemColor TmpElemColor;
declare Integer NbClassicBlocks = 0;
declare Integer DeltaNbClassicBlocks = 0;
declare SClassicBlock[] Pillars;
declare Boolean OnGround;
declare Integer VariantIndex;
declare CBlockModelVariant Variant;
declare Int3 CalculatedOffset;
declare Integer BiggestX;
declare Integer BiggestZ;
BlockLists.fromjson(_response);
TmpElemColor = NextMapElemColor;
foreach( block in BlockLists.JsonBlocks){
yield;
declare BlockModel = GetBlockModelFromName(block.ModelName);
if (block.Modif == "Place" || block.Modif == "PlaceAir"){
EnableEditorInputsCustomProcessing = True; //> stop the local player inputs to avoid desync due to the custom air_mapping and the user interactions.
NbClassicBlocks = ClassicBlocks.count;
Pillars = GetPillars();
NextMapElemColor = convertBlockColor(block.Color);
if(block.GhostMode){
Simulation_GhostMode(BlockModel, block.Coord, convertBlockDirection(block.Direction), False);
}else{
if(BlockModel != Null){
declare Boolean result = PlaceBlock(BlockModel, block.Coord, convertBlockDirection(block.Direction));
if (!result && block.ForcePlace) {
OnGround = False;
BiggestX = 0;
BiggestZ = 0;
CanPlaceBlock(BlockModel, block.Coord, convertBlockDirection(block.Direction), OnGround, VariantIndex);
if(OnGround){
Variant <=> BlockModel.VariantGround;
}else{
Variant <=> BlockModel.VariantAir;
}
if(Variant != Null){
foreach(BlockUnitModel in Variant.BlockUnitModels){
if(BlockUnitModel.RelativeOffset.X > BiggestX) BiggestX = BlockUnitModel.RelativeOffset.X;
if(BlockUnitModel.RelativeOffset.Z > BiggestZ) BiggestZ = BlockUnitModel.RelativeOffset.Z;
}
foreach(BlockUnitModel in Variant.BlockUnitModels){
CalculatedOffset = GetRotatedAndTranslatedOffset(BlockUnitModel.RelativeOffset, block.Coord, convertBlockDirection(block.Direction), BiggestX, BiggestZ);
RemoveBlock(CalculatedOffset);
}
}else{
RemoveBlock(block.Coord);
}
PlaceBlock(BlockModel, block.Coord, convertBlockDirection(block.Direction));
}
}
AutoSave();
DeltaNbClassicBlocks = ClassicBlocks.count - NbClassicBlocks;
AddEventLine(TiL::FormatDate(TiL::GetCurrent(), TiL::EDateFormats::Time) ^ " $o|$o " ^ block.login ^ " $o+$o " ^ block.ModelName ^ " at " ^ block.Coord);
//NextMapElemColor = TmpElemColor;
if(block.Modif == "PlaceAir"){
Simulation_AirMode(DeltaNbClassicBlocks, Pillars, NbClassicBlocks, block.Coord);
}
}
NextMapElemColor = TmpElemColor;
EnableEditorInputsCustomProcessing = False;
}
else if (block.Modif == "Erase"){
if(block.GhostMode){
RemoveGhostBlock(BlockModel, block.Coord, convertBlockDirection(block.Direction));
}else{
RemoveBlock(block.Coord);
}
AutoSave();
AddEventLine(TiL::FormatDate(TiL::GetCurrent(), TiL::EDateFormats::Time) ^ " $o|$o " ^ block.login ^ " $o-$o at " ^ block.Coord);
}else if (block.Modif == "Message"){
AddChatPopup(block.login ^": "^block.ModelName);
}else if (block.Modif == "Skin"){
foreach(b in ClassicBlocks){
if(b.Coord == block.Coord && b.Dir == convertBlockDirection(block.Direction) && IsBlockModelSkinnable(b.BlockModel)){
SetBlockSkin(b, block.ModelName);
}
}
}
}
}
/***
* _ForcePlace define the Block Placement comportement. By Default PlaceBlock() dont override a block. But the normal PlaceBlock function of the editor that a user use, erease the block at the position then do a PlaceBlock(). This comportement is only apply on the first block of a multiple placing(when the user use spacebar+mouse mouvements).
*
*/
Void OnMapModifiedBlockAirModePlace(Int3 _Coord,Boolean _ForcePlace, Boolean _GhostMode){
declare Modif = "PlaceAir";
declare JsonBlock block = JsonBlock{Modif = Modif, Coord = _Coord, ModelName = Cursor.BlockModel.Name, Direction = getBlockDirection(Cursor.Dir), login = LocalUser.Name, Color = getBlockColor(NextMapElemColor), Timestamp = Now, ForcePlace = _ForcePlace, GhostMode = _GhostMode};
AddModifToQueue(block);
AddEventLine(TiL::FormatDate(TiL::GetCurrent(), TiL::EDateFormats::Time) ^ " $o|$o " ^ LocalUser.Name ^ " $o+$o " ^ Cursor.BlockModel.Name ^ " at " ^ _Coord);
}
Void OnMapModifiedBlockPlace(Int3 _Coord,Boolean _ForcePlace, Boolean _GhostMode){
declare Modif = "Place";
declare JsonBlock block = JsonBlock{Modif = Modif, Coord = _Coord, ModelName = Cursor.BlockModel.Name, Direction = getBlockDirection(Cursor.Dir), login = LocalUser.Name, Color = getBlockColor(NextMapElemColor), Timestamp = Now, ForcePlace = _ForcePlace, GhostMode = _GhostMode};
AddModifToQueue(block);
AddEventLine(TiL::FormatDate(TiL::GetCurrent(), TiL::EDateFormats::Time) ^ " $o|$o " ^ LocalUser.Name ^ " $o+$o " ^ Cursor.BlockModel.Name ^ " at " ^ _Coord);
}
Void OnMapModifiedBlockErase(Int3 _Coord, SGhostBlock _GhostBlockErased){
declare Modif = "Erase";
declare JsonBlock block = JsonBlock{Modif = Modif, Coord = _Coord, login = LocalUser.Name, Timestamp = Now};
if(_GhostBlockErased.Coord != <-1,-1,-1>){
block.ModelName = _GhostBlockErased.Name;
block.Direction = getBlockDirection(_GhostBlockErased.Dir);
block.Coord = _GhostBlockErased.Coord;
block.GhostMode = True;
}
AddModifToQueue(block);
AddEventLine(TiL::FormatDate(TiL::GetCurrent(), TiL::EDateFormats::Time) ^ " $o|$o " ^ LocalUser.Name ^ " $o-$o at " ^ Cursor.Coord);
}
Void OnSkinModified(){
declare Modif = "Skin";
foreach(block in Blocks){
if(GetBlockSkin(block) != ""){
declare JsonBlock block = JsonBlock{Modif = Modif,ModelName = GetBlockSkin(block), Direction = getBlockDirection(block.Dir), Coord = block.Coord, login = LocalUser.Name, Timestamp = Now};
AddModifToQueue(block);
}
}
AddEventLine(TiL::FormatDate(TiL::GetCurrent(), TiL::EDateFormats::Time) ^ " $o|$o " ^ LocalUser.Name ^ " $o-$o skin synchro");
}
***OnInit***
***
declare Boolean Page_StopScript for ManialinkPage = False;
declare Boolean Page_AirModeVisibility for ManialinkPage = False;
declare Boolean Page_EnableAirMode for ManialinkPage = False;
declare Boolean Page_EnableGhostMode for ManialinkPage = False;
declare Boolean Page_IsLogged for ManialinkPage = False;
declare Boolean Page_EditorAllowAirGhostMode for ManialinkPage = False;
declare Integer NbClassicBlocks = 0;
declare Integer DeltaNbClassicBlocks = 0;
declare SClassicBlock[] Pillars;
declare SGhostBlock[] StackGhostBlocks;
LayersDefaultManialinkVersion = 3;
ManialinkText = getUiManialink();
/*Init UI Layers*/
UIServerSettings = UILayerCreate();
UIServerSettings.IsVisible = False;
UIServerSettings.InOutAnimation = CUILayer::EUILayerAnimation::ScaleSlow;
UIServerSettings.ManialinkPage = getServerSettingsManialink(HOST);
UIChatPopup = UILayerCreate();
UIChatPopup.IsVisible = True;
UIChatPopup.ManialinkPage = getChatPopupManialink();
UIModalStartOrQuit = UILayerCreate();
UIModalStartOrQuit.InOutAnimation = CUILayer::EUILayerAnimation::ScaleFast;
UIModalStartOrQuit.IsVisible = True;
UIModalStartOrQuit.ManialinkPage = getModalStartOrQuitManialink();
UIParameter = UILayerCreate();
UIParameter.IsVisible = False;
UIParameter.ManialinkPage = getParameterManialink();
UIChat = UILayerCreate();
UIChat.IsVisible = False;
UIChat.ManialinkPage = getChatManialink();
UIDebugView = UILayerCreate();
UIDebugView.IsVisible = True;
UIDebugView.ManialinkPage = getDebugViewManialink();
UIMainModal = UILayerCreate();
UIMainModal.InOutAnimation = CUILayer::EUILayerAnimation::ScaleFast;
UIMainModal.IsVisible = False;
UIMainModal.ManialinkPage = getMainModalManialink();
UIUpdateModal = UILayerCreate();
UIUpdateModal.InOutAnimation = CUILayer::EUILayerAnimation::ScaleFast;
UIUpdateModal.IsVisible = False;
UIUpdateModal.ManialinkPage = getUpdateModalManialink();
log("starting...");
log(TiL::FormatDate(TiL::GetCurrent(), TiL::EDateFormats::Time) ^ " > " ^ ScriptName ^ " V " ^ Version ^ " launched.");
HideInventory = True;
sleep(200); //time to let the layer be ready to handle events
AddChatPopup("$F00Editor: Welcome, do not forget to disable \nthe Air Block Mode.", 5000, False);
Page_EditorAllowAirGhostMode = IsAirGhostModeAllowed();
if(Page_EditorAllowAirGhostMode){
//TODO : when the macroblock set will be made ; Create all macroblock instances.
}
***
//send a request to get all new actions every 3 seconds
***SendHttpListener***
***
if(!ListenerRequestUp && G_TimeListenerClosed + 3000 < Now){
declare JsonBlockList BlockList = JsonBlockList{token = G_Token};
declare Text Data = BlockList.tojson();
declare Text[Text] json = ["data" => Data];
//log("json");
//log(json);
HttpPost(HOST^"/"^G_LobbyId^"/listener?login="^LocalUser.Name, json);
ListenerRequestUp = True;
}
***
//check if the last listener request is closed or not and play the logic if there is a response
***OnHttpRequest***
***
if(Request.Url == HOST^"/"^G_LobbyId^"/listener?login="^LocalUser.Name && Request.IsCompleted) {
if (Request.StatusCode == 200) {
OnListenerResponse(Request.Result);
}
ListenerRequestUp = False;
G_TimeListenerClosed = Now;
}
***
***OnCustomEventSendChat***
***
declare Modif = "Message";
declare JsonBlock block = JsonBlock{Modif = Modif, ModelName = msg, login = LocalUser.Name, Timestamp = Now};
AddModifToQueue(block);
AddChatPopup(block.login ^": "^block.ModelName);
AddEventLine(TiL::FormatDate(TiL::GetCurrent(), TiL::EDateFormats::Time) ^ " $o|$o " ^ LocalUser.Name ^ " messageSend ");
***
//create or join a lobby by requesting the server then setup the user interface and token if it's OK
***OnCreateOrJoinLobby***
***
declare Modif = "Create";
declare JsonBlock block = JsonBlock{Modif = Modif, login = LocalUser.Name, role = G_IsAdmin, Timestamp = Now};
declare Text Data = block.tojson();
declare Request = SendCreateOrJoin(Data);
declare Boolean Exit = False;
declare Boolean Dropped = False;
while(!Exit){
if(Request.IsCompleted){
Exit = True;
}
foreach(Event in PendingEvents){
if(Event.Type == CMapEditorPluginEvent::Type::LayerCustomEvent){
if(Event.CustomEventType != "createOrJoinLobby"){
Http.Destroy(Request);
Dropped = True;
Exit = True;
}
}
}
yield;
}
if(Dropped){
G_Token = "";
AddChatPopup("$F00Editor: Something went wrong.\nAre you sure this is the right party code\nor if it's the right server?", 5000, False);
}else if(Request.StatusCode >= 200 && Request.StatusCode < 300) {
declare Result = Request.Result;
declare JsonBlockList BlockList;
Http.Destroy(Request);
BlockList.fromjson(Result);
G_Token = BlockList.token;
G_ListModif.token = G_Token;
Page_IsLogged = True;
//setup Ingame interface when the player is logged
HideInventory = True;
UIMainModal.IsVisible = False;
UIParameter.IsVisible = True;
UIChat.IsVisible = True;
AddChatPopup("$F00Editor: Your multi-editor is lauched, Have Fun!", 5000, False);
}else{
G_Token = "";
AddChatPopup("$F00Editor: Something went wrong.\nAre you sure this is the right party code\nor if it's the right server?", 5000, False);
}
//log(G_Token);
***
Void dummy() {
//this dummy function fix the compilation
}
/* --------------------- Main Script ------------------------ */
main() {
HOST = S_HOSTNAME;
ListenerRequestUp = False;
declare Boolean CursorOpen = False;
declare Boolean KeyPressAfterCursorOpen = False;
declare Boolean MapModifiedWhenCursorOpen = False;
declare Boolean WelcomeMessageIsShown = False;
declare Boolean ChangedPlaceModeToSkin = False;
declare Boolean HasCustomRGB = False;
declare Boolean HasCheckedForUpdate = False;
+++ OnInit +++
while(True) {
NbClassicBlocks = ClassicBlocks.count;
Pillars = GetPillars();
StackGhostBlocks = GetStackGhostBlocks();
yield;
DeltaNbClassicBlocks = ClassicBlocks.count - NbClassicBlocks;
if (Page_StopScript) break;
//wait the plugin when the player test the map
while(PlaceMode == C_AllowedPlaceMode[3]){
yield;
}
if(!C_AllowedPlaceMode.exists(PlaceMode)){
PlaceMode = C_AllowedPlaceMode[0]; //::PlaceMode::Block
}
if(PlaceMode == C_AllowedPlaceMode[2] && !ChangedPlaceModeToSkin){
ChangedPlaceModeToSkin = True;
AddChatPopup("$F00Editor: Multi images and\nURLs are not supported.", 5000, False);
}else if(PlaceMode != C_AllowedPlaceMode[2] && ChangedPlaceModeToSkin){
ChangedPlaceModeToSkin = False;
}
Page_AirModeVisibility = (PlaceMode == ::PlaceMode::Block || PlaceMode == ::PlaceMode::FreeBlock) && !HideInventory;
if(Page_EnableGhostMode && !HasCustomRGB){
HasCustomRGB = True;
Cursor.SetCustomRGB (<.05,.17,.05>);
}else if (!Page_EnableGhostMode && HasCustomRGB){
HasCustomRGB = False;
Cursor.ResetCustomRGB();
}
LoopSendModif();
if(Page_IsLogged){
if(!HasCheckedForUpdate){
CheckForUpdate();
HasCheckedForUpdate = True;
}
+++ SendHttpListener +++
}
foreach(HttpEvent in Http.PendingEvents) {
declare Request = HttpEvent.Request;
+++ OnHttpRequest +++
if(!ListenerRequestUp){
Http.Destroy(Request);
}
} // httpEvents
foreach (Event in PendingEvents) {
switch (Event.Type) {
/******************************************************/
/*************** LayerCustomEvent ***************/
/******************************************************/
case CMapEditorPluginEvent::Type::LayerCustomEvent: {
switch (Event.CustomEventType) {
case "removeAllAndContinue": {
RemoveAll();
AutoSave();
UILayerDestroy(UIModalStartOrQuit);
UIMainModal.IsVisible = True;
HideInventory = False;
PlaceMode = ::PlaceMode::Block;
}
case "exitPlugin": {
HideInventory = True;
Page_StopScript = True;
}
case "openDebugView": {
LayerCustomEvent(UIDebugView, "openDebugView", []);
}
case "closeDebugView": {
LayerCustomEvent(UIDebugView, "closeDebugView", []);
}
case "createOrJoinLobby": {
G_LobbyId = Event.CustomEventData[0];
G_IsAdmin = TextLib::ToInteger(Event.CustomEventData[1]);
+++ OnCreateOrJoinLobby +++
}
case "addChatPopup": {
AddChatPopup(Event.CustomEventData[0], TextLib::ToInteger(Event.CustomEventData[1]), False);
}
case "sendChat": {
declare Text msg = Event.CustomEventData[0];
if(msg != ""){
+++ OnCustomEventSendChat +++
}
}
case "openServerSettings": {
UIServerSettings.IsVisible = True;
}
case "closeServerSettings": {
UIServerSettings.IsVisible = False;
LayerCustomEvent (UIServerSettings, "reloadHostName", [HOST,""]);
}
case "saveServerSettings": {
HOST = Event.CustomEventData[0];
declare Pass = Event.CustomEventData[1];
UIServerSettings.IsVisible = False;
}
case "copyPartyCode": {
System.ClipboardSet(G_LobbyId);
Audio.PlaySoundEvent(CAudioManager::ELibSound::Alert, 0, 1.);
}
}
}
/******************************************************/
/***************** EditorInput ******************/
/******************************************************/
case CMapEditorPluginEvent::Type::EditorInput: {
if(Event.Input == CMapEditorPluginEvent::EInput::Undo){
Redo();
}
}
/******************************************************/
/********* EditorEvent mapping related **********/
/******************************************************/
case CMapEditorPluginEvent::Type::CursorSelectionBegin: {
if(PlaceMode == ::PlaceMode::Block && EditMode == ::EditMode::Place){
SelectionStartCoord = Cursor.Coord;
CursorOpen = True;
log("main:Placed!");
if(Page_EnableGhostMode){
OnMapModifiedBlockPlace(Cursor.Coord, True, True);
Simulation_GhostMode(Cursor.BlockModel, SelectionStartCoord, Cursor.Dir, True);
}else if(Page_EnableAirMode){
OnMapModifiedBlockAirModePlace(Cursor.Coord, True, False);
Simulation_AirMode(DeltaNbClassicBlocks, Pillars, NbClassicBlocks, SelectionStartCoord);
}else{
OnMapModifiedBlockPlace(Cursor.Coord,True, False);
}
}else if(EditMode == ::EditMode::Erase) {
if(PlaceMode == ::PlaceMode::Block){
declare SGhostBlock GhostBlockErased = GetGhostBlockErased(StackGhostBlocks);
OnMapModifiedBlockErase(Cursor.Coord, GhostBlockErased);
}
}
}
case CMapEditorPluginEvent::Type::KeyPress: {
//if spacebar press, the user is using the 'drawing' effect to place block.
if(PlaceMode == ::PlaceMode::Block && EditMode == ::EditMode::Place){
if(Event.KeyCode == 119){
KeyPressAfterCursorOpen = CursorOpen;
}
}
}
case CMapEditorPluginEvent::Type::MapModified: {
if(PlaceMode == ::PlaceMode::Block && EditMode == ::EditMode::Place){
if(KeyPressAfterCursorOpen) MapModifiedWhenCursorOpen = True;
}
}
case CMapEditorPluginEvent::Type::CursorChange: {
if(PlaceMode == ::PlaceMode::Block && EditMode == ::EditMode::Place){
if(MapModifiedWhenCursorOpen) {
log("main:Placed bis!");
//at log(Cursor.Coord);
if(Page_EnableGhostMode){
//do nothing. The GhostMode, if you use the spacebar, only the firstblock is placed.
Undo();
}else if(Page_EnableAirMode){
OnMapModifiedBlockAirModePlace(Cursor.Coord,False, False);
Simulation_AirMode(DeltaNbClassicBlocks, Pillars, NbClassicBlocks, Cursor.Coord);
}else{
OnMapModifiedBlockPlace(Cursor.Coord,False, False);
}
}
}
MapModifiedWhenCursorOpen = False;
}
case CMapEditorPluginEvent::Type::CursorSelectionEnd: {
if(PlaceMode == CMapEditorPlugin::PlaceMode::Skin){
OnSkinModified();
}else{
SelectionEndCoord = Cursor.Coord;
CursorOpen = False;
KeyPressAfterCursorOpen = False;
MapModifiedWhenCursorOpen = False;
SelectionStartCoord = <0, 0, 0>;
SelectionEndCoord = <0, 0, 0>;
}
}
}
} // pending events
+++ Loop +++
}
}