summaryrefslogblamecommitdiffstats
path: root/src/Bindings/ManualBindings.cpp
blob: d288d37f7915055b66609471343fd0941d2b1178 (plain) (tree)
1
2
3
4
5
6
7
8
9
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
3841
3842
3843
3844
3845
3846
3847
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184
4185
4186
4187
4188
4189
4190
4191
4192
4193
4194
4195
4196
4197
4198
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287



                                                                                              
                          

                  
                
                                    
                         
                          
                      
                          
                      
                         




                               
                              
                         
                                          
                                                
                                         
                                                



                                             
                                        
                                           
                                             
                                    
                               
                                                    
                             
                                 
                             
                         
                              
                           
                               
 

 

 







                                                                                         

                                                                 

































                                                                                               
                                 
                                                                                                    


                                         

                                            













                                                                    
                                                                             


                                         

                                            


                                              
                                                                                     














                                               
                                                





                                           
                                                                                                                                             



                                                                                                   
                                                                                                                                                      

         


                                                           
 
                                                    







                              
                                                        
 

                             
                                         
                 
                                                 
                                           












                                                          
                    





                                                                                    
 





                                                          
                                         
                                      







                                                  
                                    





                                                                                          






                 
                                                        
 
                             
            
                                         

                                   























                                                                      
                                         
                                   





                                                  




                                          
                    



                                                                            
 







                                                   
                                         
                                   





                                                  







                                                                     






                 
                                                 
 
                          
                                    

                                               
 

                                               






                 

                                                           





                                        

                                                                
                      






                 

                                                        








                                            
 



                                               






                 



                                                                    
 


                                                                        
                                                                                                                




                                                                   
                                   












                                                 







                                                                              
                                                                        
                                                         


                                                                        
                                                                                                                                                              
         
 
                           
                                                                                   






                 
                                             
 







                                                                              
                                                                                          






                 
                                             
 







                                                                              
                                                                                             






                 
                                              
 







                                                                              
                                                                                           






                 









                                                  
 




















                                                  
 










                                        
                                                         




                                                         
                                                                                                                
                              
                               
         
                                                                                                      
                      
 





                      
 






















































































































































































































































                                                                                                  

                                                             


                                                                   
                        








                                                            
 

                       
                                                   









                                                        











































































































                                                                   

                                                         


                                                
                        
                                    
            


                                                            
         
         
                         
         
 

                         
                                                     
 


                                                      
 


 

 


























                                                      

                                                                  


                                                                                                                        
 
                                 
                              






                 

                                                               
                                                               
                              











                                                                              











                                                                                                                                                   









                                                            




                                                                                                              
 
                                                  
                                                               
                              



                                                                              
 
                                           






                                                                                   





                                                                                                  
 
                                     
                                         





                                                                                           
                                                                    





                                                                                                     
 












                                                                                                              
 
                                                   
                                                                                                       
                              




                                                                                                                                  
                                                       





                                                                                                                                      
 
                                           
                                                                               





                                                                                                  
 

                                                                  
                              






                                                                                                          
                                         



                                                 





                                                                                                       
 











                                                            




                                                                                                                                                
          
 


                                                        
                                                                                             




                                                              
                                                                                             
                                      






                                                                                                                                          

                                                                    


                                                                         
 







                                                                                                    
                                                                                                                                                                       
                                  

                                                                               
 

                                                                                                                      
                                                                                                                                                    







                          
                                                                   
 



                                                                 
 






                                                             
         
                         
         
 



                                   




                                                                                                                     
                                                 


                                                                        


                                                                                

                 



                                                                                                                                                              
                                         


                                                                                                                
                 


                                          
 

                                                                






                 
                                                                          
 



                                                                        
 






                                                             
         


                         



                                   




                                                                                                                            
                                                 


                                                                        


                                                                                

                 


                                                                                                                                                              
                 

                                             


                                                                                                  
                 


                                          
 

                                                                       





                 
 
                                                                   
 

                                                                                     
                                                                                                                  
          
                                
                                                               
                              
         
                         
         
 

                                               
                    



                                                                           


                      
            



                                                                




                                                                                 
                                        



                                                                                                                            
                                                      



                                                                        
         
                                                                                                                            

                         
 
                                                                                      
                                                                                        
         
                                                                                                        
                                  

                         
 
                     
                 




 
 
                                                                          
 



                                                                                                             
 
                                                         
                                
                                                               
                              
         
                         
         
 

                                               
                    



                                                                          


                      
            


                                                                               




                                                                                        
                                        



                                                                                                                                   
                                                      



                                                            
         
                                                                                                                                           

                         
 
                                                                                      
                                                                                   
         
                                                                                                        
                                  

                         
                     
                 





 





                                                                        
 







                                                              
 









                                                                                                
 
                                                            
                                                                   
                                  








                                                                                                            
 







                                                                                      
                                        
                                                       
                                                    




                                               
 

                                                              




                                                                                                         






                                                                                           

                         




                                                                                                                                  






                                     

































                                                                                            














                                                                                                                
                                                            
 
                                                                              
 





                                                      
         
                         
         
 
                          
                                                                                            
                            
         
                                                                                             
                         
         
 

                                       






                 














                                                                                
                                                                                            

                            
                                                                                             

                         
 








                                        






                                                                                            


                                                       





                          

                                                  
 
                                        
                                                                                                     






                 

                      
                                                                             

                                                       
 
                                                                            
 
                                                                



                                                 
         

                                                                      

                         
 
                           
                                                  






                 


                                         
 


                                                                      
 





                                              
         

                                                                                                           
         
  

 
 














                                                                                                           
         
                         
         





                                                  
         
                         

         



                                                                     
         

                                                                                   
         
                                                
         
                                                                

         

                                                                                          






                 
                                                          
 
                             
 


                                                                                               
 

                                                                                            
 


                                        




 
 
                                                               
 
                             
 
                                      
                                                                                                     
                          
 

                                                                                            
 


                                         




 
 
                                         
 
                                                     

                                 
                                                                                                                      



                                    
                                       
                                                                                             






                 
















                                                                                                                  
                                                                                                                      







                                                  
                                                

                                                          
                                                                                                                                             













                                                                            
                                                                                                                      




                                        
                                                                                             











                                                                            
                                                                                                                      







                                                   
                                                

                                                           
                                                                                                                                              








                                                                            
                                                                                                                  



                                      
                                                                                                                              
         

                                                        













                                                           
                                                                                                    








                                                                 
                                                                                                    








                                                                     

                                                                                                    



                                      
                                                                                                             
         


                                                                                                                             









                                           




















































































































































                                                                                                                








































                                                                                          
 

                                                                                                                      
 
                                         
 

                                                                      

                                           









                                                        
                                                      








                        
                                      
                                                                     
                                                          



                                 
                                                                                      





                                         
 


                                  
 
                              
                                             






                 
                                                     
                                                                     
                                                                         
 


                                 
                                                                                      


                                         
         
                         
         





                                  
                                                            






                 


                                                                     
 






                                                                                      
         
                         
         



























































































                                                                                                  






                 










                                                               
                                                                                                    
                              















                                                                                       











                                                                     
 



                                       
 



















                                                                                  
 

                                 
 




























                                                                                                          
 

                                       
 

















                                                                                                          
                                                                  


                       
                                                          
                                        
                                   



                         
 


                                                      
                                                           



                                           
                                          





                                                    
 






                                                                          

                                                
                        
 
                         
                                                                                                                    




                                                                                                                        
 
                                                       

                                        















                                                                                                 













                                                                        
 


























                                                                       
 












                                                                 











                                                                            
         

                                                                                                              
                                    
                 
                                                                                                        



                                                   

                                                                
                         
         
 
             
                                                                                     






                 
                                                                                           








                                                                          
 
                                                                                                                                                    
         





                                                                                            



                                                                           

                           
 
                                                                                                           
         





                                                                              



                                                                           

                           
 

                                                                                             





                                                                         



                                                                           

                           
 

                                                                                            





                                                                        



                                                                           

                           
 

                                                
                                                                                  
         
 

                                             
                                                                               












                                                            



                                                                                                        
 






                                                                                      
 
                        

                             



                                                          




                         
                 
                                                                                       






                                                       








                                                                                                        








































































                                                                                                          











































                                                              















































                                                                                                  



                                                            


                                                           



                         
 
                                 

                                  
                             



                                                                                             
 

                                                               
                                                                           
                              



                                                                                  
 
                                                                                 


                                 






                 























                                                                                                    



                                                                           
 








                                                            
                                                                                                        
                            
         
                                                                                                                 


                         
                                                                                        




                                                                                         


                                                                              








                         
 



                                                                                       
 







                                                         
 
                                                                                                  
                            
         
                                                                                                             

                         


                                                                     











                                                                             





                                                                       
 




                                                   
 
                                                                                                  
                            
         
                                                                                                   

                         
 










                                                    



                                                                                            
 




                                                   
 







                                                                                                                
 

















                                                                                                            



                                                                                       
 







                                                         
 
                                                                                                  
                            
         
                                                                                                             

                         


                                                                     











                                                                                





                                                                       
 




                                                   
 
                                                                                                  
                            
         
                                                                                                 

                         
 










                                                  





                                                                                                         
 




                                                   
 
                                                                                                  
                            
         
                                                                                                 

                         
 










                                                      


                                                                      
                                                                                           








                                                         
                                                                                                  
                            
         
                                                                                                                



                                                         
                                                                                    






                                        
 


                                                                        
                                                                                           








                                                         
                                                                                                  
                            
         
                                                                                                                













                                                                                  


                                                                    
                                                                                           








                                                         
                                                                                                  
                            
         
                                                                                                              


                                                         
                                                                                  





                                        

 


                                                                      
                                                                                           







                                                         
                                                                                                  
                            
         
                                                                                                              

                         
 






                                                                         





 






















                                                                                                   
                                           




























                                                                                                                                                                                                   
                                   



















                                                                                                                 


























                                                                                                                                   



                                                                               
 








                                                             
                                                                                                          
                            
         
                                                                                                               

                         
 





                                                      
 












                                                                                                  
 








                                                             
                                                                                                          
                            
         
                                                                                                                   

                         
 





                                                          
 












                                                                                                  
 








                                                             
                                                                                                          
                            
         
                                                                                                         

                         
 




                                       
 












                                                                                                  
 








                                                             
                                                                                                          
                            
         
                                                                                                        

                         
 





                                           
 












                                                                                                  
 








                                                             
                                                                                                          
                            
         
                                                                                                       

                         
 



                                 
 












                                                                                                  
 








                                                             
                                                                                                          
                            
         
                                                                                                            

                         
 
                        

                                        
                                                                     
 












                                                                                                  
 





                                                       
                                                                                                          
                            
         
                                                                                                           

                         
 

                              
 








                                                                                                  




















































































































































































































































































































































































































































































































































































                                                                                                                              
                                               
 
                                            


                                                       
                                                            
                                                              
                                                      

                                                                                               
                                                                                               
                                                                                               

                           

                                                                                    
                                                                                              








                                                                                                                                 
 
                                                         
                                                                                                              
                                                                                                           
                                                                                                       
                                                                                                                    





                                                                                                                     
                                         
 




                                                                                                                 



                                                                                                       





                                                                                                            








                                                                                                                     












                                                                                      















                                                                                                                

                                         
                                                            

                                                                                                            




                                                                                             


                                                                                       

                                                         


                                                                                                

                                                                                                                                        
                                         
 
                                                          
                                                                                                                   
                                         
 






                                                                                                                           
                                         



                                                                                                    


                                                                                                      
                                                      

                                                                                                      
                                         
 



                                                                                         
                                                             
                                                                                                       

                                                                                                                  
                                                                                                          
                                                                                                                                               
                                                                                                                     
                                                                                                           

                                                                                                                     
                                                                                                                                                 
                                                                                                             
                                                                                                                
                                                                                                         
                                                                                                             
                                         





                                                                                                                             
                                                                                                     



                                                                                                       
                                                                                                     

                                         


                                                                                                                                      
                                                                                                    

                                         





                                                                                                      
                                         
 






                                                                                                           
                                                        






                                                                                                                        
                                         
 



                                                                                                         

                                         

























                                                                                                          
                                     

                                         
 

                                 

#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "ManualBindings.h"
#undef TOLUA_TEMPLATE_BIND
#include <sstream>
#include <iomanip>
#include <array>
#include "tolua++/include/tolua++.h"
#include "polarssl/md5.h"
#include "polarssl/sha1.h"
#include "PluginLua.h"
#include "PluginManager.h"
#include "LuaWindow.h"
#include "LuaChunkStay.h"
#include "../Root.h"
#include "../World.h"
#include "../Entities/Player.h"
#include "../WebAdmin.h"
#include "../ClientHandle.h"
#include "../ChannelManager.h"
#include "../BlockArea.h"
#include "../BlockEntities/BeaconEntity.h"
#include "../BlockEntities/BrewingstandEntity.h"
#include "../BlockEntities/ChestEntity.h"
#include "../BlockEntities/CommandBlockEntity.h"
#include "../BlockEntities/DispenserEntity.h"
#include "../BlockEntities/DropperEntity.h"
#include "../BlockEntities/FurnaceEntity.h"
#include "../BlockEntities/HopperEntity.h"
#include "../BlockEntities/NoteEntity.h"
#include "../BlockEntities/MobHeadEntity.h"
#include "../BlockEntities/FlowerPotEntity.h"
#include "../Generating/ChunkDesc.h"
#include "../LineBlockTracer.h"
#include "../WorldStorage/SchematicFileSerializer.h"
#include "../CompositeChat.h"
#include "../StringCompression.h"
#include "../CommandOutput.h"
#include "../BuildInfo.h"
#include "../HTTP/UrlParser.h"
#include "../BoundingBox.h"
#include "../ChannelCallback.h"





////////////////////////////////////////////////////////////////////////////////
// LuaCommandHandler:

/** Defines a bridge between cPluginManager::cCommandHandler and cLuaState::cCallback. */
class LuaCommandHandler:
	public cPluginManager::cCommandHandler
{
public:
	LuaCommandHandler(cLuaState::cCallbackPtr && a_Callback):
		m_Callback(std::move(a_Callback))
	{
	}

	virtual bool ExecuteCommand(
		const AStringVector & a_Split,
		cPlayer * a_Player,
		const AString & a_Command,
		cCommandOutputCallback * a_Output
	) override
	{
		bool res = false;
		AString s;
		if (!m_Callback->Call(a_Split, a_Player, a_Command, cLuaState::Return, res, s))
		{
			return false;
		}
		if (res && (a_Output != nullptr) && !s.empty())
		{
			a_Output->Out(s);
		}
		return res;
	}

protected:
	cLuaState::cCallbackPtr m_Callback;
};





////////////////////////////////////////////////////////////////////////////////
// cManualBindings:

// Better error reporting for Lua
int cManualBindings::tolua_do_error(lua_State * L, const char * a_pMsg, tolua_Error * a_pToLuaError)
{
	// Retrieve current function name
	lua_Debug entry;
	VERIFY(lua_getstack(L, 0, &entry));
	VERIFY(lua_getinfo(L, "n", &entry));

	// Insert function name into error msg
	AString msg(a_pMsg);
	ReplaceString(msg, "#funcname#", entry.name?entry.name:"?");

	// Send the error to Lua
	tolua_error(L, msg.c_str(), a_pToLuaError);
	return 0;
}





int cManualBindings::lua_do_error(lua_State * L, const char * a_pFormat, ...)
{
	// Retrieve current function name
	lua_Debug entry;
	VERIFY(lua_getstack(L, 0, &entry));
	VERIFY(lua_getinfo(L, "n", &entry));

	// Insert function name into error msg
	AString msg(a_pFormat);
	ReplaceString(msg, "#funcname#", (entry.name != nullptr) ? entry.name : "?");

	// Copied from luaL_error and modified
	va_list argp;
	va_start(argp, a_pFormat);
	luaL_where(L, 1);
	lua_pushvfstring(L, msg.c_str(), argp);
	va_end(argp);
	lua_concat(L, 2);
	return lua_error(L);
}





// Lua bound functions with special return types
static int tolua_Clamp(lua_State * tolua_S)
{
	cLuaState LuaState(tolua_S);
	int NumArgs = lua_gettop(LuaState);
	if (NumArgs != 3)
	{
		return cManualBindings::lua_do_error(LuaState, "Error in function call '#funcname#': Requires 3 arguments, got %i", NumArgs);
	}

	if (!lua_isnumber(LuaState, 1) || !lua_isnumber(LuaState, 2) || !lua_isnumber(LuaState, 3))
	{
		return cManualBindings::lua_do_error(LuaState, "Error in function call '#funcname#': Expected a number for parameters #1, #2 and #3");
	}

	lua_Number Number = tolua_tonumber(LuaState, 1, 0);
	lua_Number Min = tolua_tonumber(LuaState, 2, 0);
	lua_Number Max = tolua_tonumber(LuaState, 3, 0);

	lua_Number Result = Clamp(Number, Min, Max);
	LuaState.Push(Result);
	return 1;
}





static int tolua_CompressStringZLIB(lua_State * tolua_S)
{
	cLuaState S(tolua_S);
	if (
		!S.CheckParamString(1) ||
		(
			!S.CheckParamNumber(2) &&
			!S.CheckParamEnd(2)
		)
	)
	{
		cLuaState::LogStackTrace(tolua_S);
		return 0;
	}

	// Get the params:
	AString ToCompress;
	int CompressionLevel = 5;
	S.GetStackValues(1, ToCompress, CompressionLevel);

	// Compress the string:
	AString res;
	CompressString(ToCompress.data(), ToCompress.size(), res, CompressionLevel);
	S.Push(res);
	return 1;
}





static int tolua_UncompressStringZLIB(lua_State * tolua_S)
{
	cLuaState S(tolua_S);
	if (
		!S.CheckParamString(1) ||
		!S.CheckParamNumber(2)
	)
	{
		cLuaState::LogStackTrace(tolua_S);
		return 0;
	}

	// Get the params:
	AString ToUncompress;
	size_t UncompressedSize = 0;
	S.GetStackValues(1, ToUncompress, UncompressedSize);

	// Compress the string:
	AString res;
	UncompressString(ToUncompress.data(), ToUncompress.size(), res, UncompressedSize);
	S.Push(res);
	return 1;
}





static int tolua_CompressStringGZIP(lua_State * tolua_S)
{
	cLuaState S(tolua_S);
	if (
		!S.CheckParamString(1) ||
		!S.CheckParamEnd(2)
	)
	{
		cLuaState::LogStackTrace(tolua_S);
		return 0;
	}

	// Get the params:
	AString ToCompress;
	S.GetStackValues(1, ToCompress);

	// Compress the string:
	AString res;
	CompressStringGZIP(ToCompress.data(), ToCompress.size(), res);
	S.Push(res);
	return 1;
}





static int tolua_UncompressStringGZIP(lua_State * tolua_S)
{
	cLuaState S(tolua_S);
	if (
		!S.CheckParamString(1) ||
		!S.CheckParamEnd(2)
	)
	{
		cLuaState::LogStackTrace(tolua_S);
		return 0;
	}

	// Get the params:
	AString ToUncompress;
	S.GetStackValues(1, ToUncompress);

	// Compress the string:
	AString res;
	UncompressStringGZIP(ToUncompress.data(), ToUncompress.size(), res);
	S.Push(res);
	return 1;
}





static int tolua_InflateString(lua_State * tolua_S)
{
	cLuaState S(tolua_S);
	if (
		!S.CheckParamString(1) ||
		!S.CheckParamEnd(2)
	)
	{
		cLuaState::LogStackTrace(tolua_S);
		return 0;
	}

	// Get the params:
	AString ToUncompress;
	S.GetStackValues(1, ToUncompress);

	// Compress the string:
	AString res;
	InflateString(ToUncompress.data(), ToUncompress.size(), res);
	S.Push(res);
	return 1;
}





static int tolua_StringSplit(lua_State * tolua_S)
{
	// Get the params:
	cLuaState LuaState(tolua_S);
	AString str, delim;
	LuaState.GetStackValues(1, str, delim);

	// Execute and push the result:
	LuaState.Push(StringSplit(str, delim));
	return 1;
}





static int tolua_StringSplitWithQuotes(lua_State * tolua_S)
{
	cLuaState S(tolua_S);

	AString str;
	AString delim;

	S.GetStackValues(1, str, delim);

	AStringVector Split = StringSplitWithQuotes(str, delim);
	S.Push(Split);
	return 1;
}





static int tolua_StringSplitAndTrim(lua_State * tolua_S)
{
	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamString(1, 2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Process:
	AString str, delim;
	L.GetStackValues(1, str, delim);
	L.Push(StringSplitAndTrim(str, delim));
	return 1;
}





/** Retrieves the log message from the first param on the Lua stack.
Can take either a string or a cCompositeChat.
*/
static AString GetLogMessage(lua_State * tolua_S)
{
	tolua_Error err;
	if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err))
	{
		return reinterpret_cast<cCompositeChat *>(tolua_tousertype(tolua_S, 1, nullptr))->ExtractText();
	}
	else
	{
		size_t len = 0;
		const char * str = lua_tolstring(tolua_S, 1, &len);
		if (str != nullptr)
		{
			return AString(str, len);
		}
	}
	return "";
}





static int tolua_LOG(lua_State * tolua_S)
{
	// If there's no param, spit out an error message instead of crashing:
	if (lua_isnil(tolua_S, 1))
	{
		LOGWARNING("Attempting to LOG a nil value!");
		cLuaState::LogStackTrace(tolua_S);
		return 0;
	}

	// If the param is a cCompositeChat, read the log level from it:
	cLogger::eLogLevel LogLevel = cLogger::llRegular;
	tolua_Error err;
	if (tolua_isusertype(tolua_S, 1, "cCompositeChat", false, &err))
	{
		LogLevel = cCompositeChat::MessageTypeToLogLevel(reinterpret_cast<cCompositeChat *>(tolua_tousertype(tolua_S, 1, nullptr))->GetMessageType());
	}

	// Log the message:
	cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), LogLevel);
	return 0;
}





static int tolua_LOGINFO(lua_State * tolua_S)
{
	// If there's no param, spit out an error message instead of crashing:
	if (lua_isnil(tolua_S, 1))
	{
		LOGWARNING("Attempting to LOGINFO a nil value!");
		cLuaState::LogStackTrace(tolua_S);
		return 0;
	}

	cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), cLogger::llInfo);
	return 0;
}





static int tolua_LOGWARN(lua_State * tolua_S)
{
	// If there's no param, spit out an error message instead of crashing:
	if (lua_isnil(tolua_S, 1))
	{
		LOGWARNING("Attempting to LOGWARN a nil value!");
		cLuaState::LogStackTrace(tolua_S);
		return 0;
	}

	cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), cLogger::llWarning);
	return 0;
}





static int tolua_LOGERROR(lua_State * tolua_S)
{
	// If there's no param, spit out an error message instead of crashing:
	if (lua_isnil(tolua_S, 1))
	{
		LOGWARNING("Attempting to LOGERROR a nil value!");
		cLuaState::LogStackTrace(tolua_S);
		return 0;
	}

	cLogger::GetInstance().LogSimple(GetLogMessage(tolua_S).c_str(), cLogger::llError);
	return 0;
}





static int tolua_Base64Encode(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (
		!L.CheckParamString(1) ||
		!L.CheckParamEnd(2)
	)
	{
		return 0;
	}

	AString Src;
	L.GetStackValue(1, Src);
	AString res = Base64Encode(Src);
	L.Push(res);
	return 1;
}





static int tolua_Base64Decode(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (
		!L.CheckParamString(1) ||
		!L.CheckParamEnd(2)
	)
	{
		return 0;
	}

	AString Src;
	L.GetStackValue(1, Src);
	AString res = Base64Decode(Src);
	L.Push(res);
	return 1;
}





cPluginLua * cManualBindings::GetLuaPlugin(lua_State * L)
{
	// Get the plugin identification out of LuaState:
	lua_getglobal(L, LUA_PLUGIN_INSTANCE_VAR_NAME);
	if (!lua_islightuserdata(L, -1))
	{
		LOGWARNING("%s: cannot get plugin instance, what have you done to my Lua state?", __FUNCTION__);
		lua_pop(L, 1);
		return nullptr;
	}
	cPluginLua * Plugin = reinterpret_cast<cPluginLua *>(const_cast<void*>(lua_topointer(L, -1)));
	lua_pop(L, 1);

	return Plugin;
}





static int tolua_cFile_ChangeFileExt(lua_State * tolua_S)
{
	// API signature:
	// ChangeFileExt(string, string) -> string

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2, 3) ||
		!L.CheckParamEnd(4)
	)
	{
		return 0;
	}

	// Execute:
	AString FileName, NewExt;
	ASSERT(L.GetStackValues(2, FileName, NewExt));
	L.Push(cFile::ChangeFileExt(FileName, NewExt));
	return 1;
}





static int tolua_cFile_Copy(lua_State * tolua_S)
{
	// API signature:
	// cFile:Copy(string, string) -> bool

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2, 3) ||
		!L.CheckParamEnd(4)
	)
	{
		return 0;
	}

	// Execute:
	AString SrcFile, DstFile;
	ASSERT(L.GetStackValues(2, SrcFile, DstFile));
	L.Push(cFile::Copy(SrcFile, DstFile));
	return 1;
}





static int tolua_cFile_CreateFolder(lua_State * tolua_S)
{
	// API signature:
	// cFile:CreateFolder(string) -> bool

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Execute:
	AString FolderPath;
	ASSERT(L.GetStackValues(2, FolderPath));
	L.Push(cFile::CreateFolder(FolderPath));
	return 1;
}





static int tolua_cFile_CreateFolderRecursive(lua_State * tolua_S)
{
	// API signature:
	// cFile:CreateFolderRecursive(string) -> bool

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Execute:
	AString FolderPath;
	ASSERT(L.GetStackValues(2, FolderPath));
	L.Push(cFile::CreateFolderRecursive(FolderPath));
	return 1;
}





static int tolua_cFile_Delete(lua_State * tolua_S)
{
	// API signature:
	// cFile:Delete(string) -> bool

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Execute:
	AString Path;
	ASSERT(L.GetStackValues(2, Path));
	L.Push(cFile::Delete(Path));
	return 1;
}





static int tolua_cFile_DeleteFile(lua_State * tolua_S)
{
	// API signature:
	// cFile:DeleteFile(string) -> bool

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Execute:
	AString Path;
	ASSERT(L.GetStackValues(2, Path));
	L.Push(cFile::DeleteFile(Path));
	return 1;
}





static int tolua_cFile_DeleteFolder(lua_State * tolua_S)
{
	// API signature:
	// cFile:DeleteFolder(string) -> bool

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Execute:
	AString Path;
	ASSERT(L.GetStackValues(2, Path));
	L.Push(cFile::DeleteFolder(Path));
	return 1;
}





static int tolua_cFile_DeleteFolderContents(lua_State * tolua_S)
{
	// API signature:
	// cFile:DeleteFolderContents(string) -> bool

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Execute:
	AString Path;
	ASSERT(L.GetStackValues(2, Path));
	L.Push(cFile::DeleteFolderContents(Path));
	return 1;
}





static int tolua_cFile_Exists(lua_State * tolua_S)
{
	// API signature:
	// cFile:Exists(string) -> bool

	// Obsolete, use IsFile() or IsFolder() instead
	cLuaState L(tolua_S);
	LOGWARNING("cFile:Exists() is obsolete, use cFile:IsFolder() or cFile:IsFile() instead!");
	L.LogStackTrace();

	// Check params:
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Execute:
	AString Path;
	ASSERT(L.GetStackValues(2, Path));
	L.Push(cFile::Exists(Path));
	return 1;
}





static int tolua_cFile_GetFolderContents(lua_State * tolua_S)
{
	// API signature:
	// cFile:GetFolderContents(string) -> {string, string, ...}

	// Check params:
	cLuaState LuaState(tolua_S);
	if (
		!LuaState.CheckParamUserTable(1, "cFile") ||
		!LuaState.CheckParamString   (2) ||
		!LuaState.CheckParamEnd      (3)
	)
	{
		return 0;
	}

	// Get params:
	AString Folder;
	ASSERT(LuaState.GetStackValues(2, Folder));

	// Execute and push result:
	LuaState.Push(cFile::GetFolderContents(Folder));
	return 1;
}





static int tolua_cFile_GetLastModificationTime(lua_State * tolua_S)
{
	// API signature:
	// cFile:GetLastModificationTime(string) -> number

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Execute:
	AString Path;
	ASSERT(L.GetStackValues(2, Path));
	L.Push(cFile::GetLastModificationTime(Path));
	return 1;
}





static int tolua_cFile_GetSize(lua_State * tolua_S)
{
	// API signature:
	// cFile:GetSize(string) -> number

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Execute:
	AString Path;
	ASSERT(L.GetStackValues(2, Path));
	L.Push(cFile::GetSize(Path));
	return 1;
}





static int tolua_cFile_IsFile(lua_State * tolua_S)
{
	// API signature:
	// cFile:IsFile(string) -> bool

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Execute:
	AString Path;
	ASSERT(L.GetStackValues(2, Path));
	L.Push(cFile::IsFile(Path));
	return 1;
}





static int tolua_cFile_IsFolder(lua_State * tolua_S)
{
	// API signature:
	// cFile:IsFolder(string) -> bool

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Execute:
	AString Path;
	ASSERT(L.GetStackValues(2, Path));
	L.Push(cFile::IsFolder(Path));
	return 1;
}





static int tolua_cFile_ReadWholeFile(lua_State * tolua_S)
{
	// API signature:
	// cFile:ReadWholeFile(string) -> string

	// Check params:
	cLuaState LuaState(tolua_S);
	if (
		!LuaState.CheckParamUserTable(1, "cFile") ||
		!LuaState.CheckParamString   (2) ||
		!LuaState.CheckParamEnd      (3)
	)
	{
		return 0;
	}

	// Get params:
	AString FileName;
	ASSERT(LuaState.GetStackValues(2, FileName));

	// Execute and push result:
	LuaState.Push(cFile::ReadWholeFile(FileName));
	return 1;
}





static int tolua_cFile_Rename(lua_State * tolua_S)
{
	// API signature:
	// cFile:Rename(string, string) -> bool

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cFile") ||
		!L.CheckParamString(2, 3) ||
		!L.CheckParamEnd(4)
	)
	{
		return 0;
	}

	// Execute:
	AString SrcPath, DstPath;
	ASSERT(L.GetStackValues(2, SrcPath, DstPath));
	L.Push(cFile::Rename(SrcPath, DstPath));
	return 1;
}





static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S)
{
	// API function no longer available:
	LOGWARNING("cPluginManager:GetAllPlugins() is no longer available, use cPluginManager:ForEachPlugin() instead");
	cLuaState::LogStackTrace(tolua_S);

	// Return an empty table:
	lua_newtable(tolua_S);
	return 1;
}





static int tolua_cPluginManager_GetCurrentPlugin(lua_State * S)
{
	cPluginLua * Plugin = cManualBindings::GetLuaPlugin(S);
	if (Plugin == nullptr)
	{
		// An error message has already been printed in GetLuaPlugin()
		return 0;
	}
	tolua_pushusertype(S, Plugin, "cPluginLua");
	return 1;
}





static int tolua_cPluginManager_GetPlugin(lua_State * tolua_S)
{
	// API function no longer available:
	LOGWARNING("cPluginManager:GetPlugin() is no longer available. Use cPluginManager:DoWithPlugin() or cPluginManager:CallPlugin() instead.");
	cLuaState::LogStackTrace(tolua_S);
	return 0;
}





static int tolua_cPluginManager_LogStackTrace(lua_State * S)
{
	cLuaState::LogStackTrace(S);
	return 0;
}





static int tolua_cPluginManager_AddHook_FnRef(cPluginManager * a_PluginManager, cLuaState & S, int a_ParamIdx)
{
	// Helper function for cPluginmanager:AddHook() binding
	// Takes care of the new case (#121): args are HOOK_TYPE and CallbackFunction
	// The arg types have already been checked

	// Retrieve the cPlugin from the LuaState:
	cPluginLua * Plugin = cManualBindings::GetLuaPlugin(S);
	if (Plugin == nullptr)
	{
		// An error message has been already printed in GetLuaPlugin()
		return 0;
	}

	// Retrieve and check the hook type
	int HookType;
	if (!S.GetStackValue(a_ParamIdx, HookType))
	{
		LOGWARNING("cPluginManager.AddHook(): Cannot read the hook type.");
		S.LogStackTrace();
		return 0;
	}
	if (!a_PluginManager->IsValidHookType(HookType))
	{
		LOGWARNING("cPluginManager.AddHook(): Invalid HOOK_TYPE parameter: %d", HookType);
		S.LogStackTrace();
		return 0;
	}

	// Add the hook to the plugin
	cLuaState::cCallbackPtr callback;
	if (!S.GetStackValue(a_ParamIdx + 1, callback))
	{
		LOGWARNING("cPluginManager.AddHook(): Cannot read the callback parameter");
		S.LogStackTrace();
		return 0;
	}
	if (!Plugin->AddHookCallback(HookType, std::move(callback)))
	{
		LOGWARNING("cPluginManager.AddHook(): Cannot add hook %d, unknown error.", HookType);
		S.LogStackTrace();
		return 0;
	}
	a_PluginManager->AddHook(Plugin, HookType);

	// Success
	return 0;
}





static int tolua_cPluginManager_AddHook_DefFn(cPluginManager * a_PluginManager, cLuaState & S, int a_ParamIdx)
{
	// Helper function for cPluginmanager:AddHook() binding
	// Takes care of the old case (#121): args are cPluginLua and HOOK_TYPE
	// The arg types have already been checked

	// Retrieve and check the cPlugin parameter
	cPluginLua * Plugin = reinterpret_cast<cPluginLua *>(tolua_tousertype(S, a_ParamIdx, nullptr));
	if (Plugin == nullptr)
	{
		LOGWARNING("cPluginManager.AddHook(): Invalid Plugin parameter, expected a valid cPlugin object. Hook not added");
		S.LogStackTrace();
		return 0;
	}
	if (Plugin != cManualBindings::GetLuaPlugin(S))
	{
		// The plugin parameter passed to us is not our stored plugin. Disallow this!
		LOGWARNING("cPluginManager.AddHook(): Invalid Plugin parameter, cannot add hook to foreign plugins. Hook not added.");
		S.LogStackTrace();
		return 0;
	}

	// Retrieve and check the hook type
	int HookType = static_cast<int>(tolua_tonumber(S, a_ParamIdx + 1, -1));
	if (!a_PluginManager->IsValidHookType(HookType))
	{
		LOGWARNING("cPluginManager.AddHook(): Invalid HOOK_TYPE parameter: %d", HookType);
		S.LogStackTrace();
		return 0;
	}

	// Get the standard name for the callback function:
	const char * FnName = cPluginLua::GetHookFnName(HookType);
	if (FnName == nullptr)
	{
		LOGWARNING("cPluginManager.AddHook(): Unknown hook type (%d). Hook not added.", HookType);
		S.LogStackTrace();
		return 0;
	}

	// Retrieve the function to call and add it to the plugin:
	cLuaState::cCallbackPtr callback;
	lua_getglobal(S, FnName);
	bool res = S.GetStackValue(-1, callback);
	lua_pop(S, 1);
	if (!res || !callback->IsValid())
	{
		LOGWARNING("cPluginManager.AddHook(): Function %s not found. Hook not added.", FnName);
		S.LogStackTrace();
		return 0;
	}
	a_PluginManager->AddHook(Plugin, HookType);

	// Success
	return 0;
}





static int tolua_cPluginManager_AddHook(lua_State * tolua_S)
{
	/*
	Function signatures:
	cPluginManager:AddHook(HOOK_TYPE, CallbackFunction)        -- (1) recommended
	cPluginManager.AddHook(HOOK_TYPE, CallbackFunction)        -- (2) accepted silently (#401 deprecates this)
	cPluginManager:Get():AddHook(HOOK_TYPE, CallbackFunction)  -- (3) accepted silently
	cPluginManager:Get():AddHook(Plugin, HOOK_TYPE)            -- (4) old style (#121), accepted but complained about in the console
	cPluginManager.AddHook(Plugin, HOOK_TYPE)                  -- (5) old style (#121) mangled, accepted but complained about in the console
	*/

	cLuaState S(tolua_S);
	cPluginManager * PlgMgr = cPluginManager::Get();

	// If the first param is a cPluginManager instance, use it instead of the global one:
	int ParamIdx = 1;
	tolua_Error err;
	if (tolua_isusertype(S, 1, "cPluginManager", 0, &err))
	{
		// Style 2 or 3, retrieve the PlgMgr instance
		PlgMgr = reinterpret_cast<cPluginManager *>(tolua_tousertype(S, 1, nullptr));
		if (PlgMgr == nullptr)
		{
			LOGWARNING("Malformed plugin, use cPluginManager.AddHook(HOOK_TYPE, CallbackFunction). Fixing the call for you.");
			S.LogStackTrace();
			PlgMgr = cPluginManager::Get();
		}
		ParamIdx += 1;
	}
	else if (tolua_isusertable(S, 1, "cPluginManager", 0, &err))
	{
		// Style 1, use the global PlgMgr, but increment ParamIdx
		ParamIdx++;
	}

	if (lua_isnumber(S, ParamIdx) && lua_isfunction(S, ParamIdx + 1))
	{
		// The next params are a number and a function, assume style 1 or 2
		return tolua_cPluginManager_AddHook_FnRef(PlgMgr, S, ParamIdx);
	}
	else if (tolua_isusertype(S, ParamIdx, "cPlugin", 0, &err) && lua_isnumber(S, ParamIdx + 1))
	{
		// The next params are a cPlugin and a number, assume style 3 or 4
		LOGINFO("cPluginManager.AddHook(): Deprecated format used, use cPluginManager.AddHook(HOOK_TYPE, CallbackFunction) instead. Fixing the call for you.");
		S.LogStackTrace();
		return tolua_cPluginManager_AddHook_DefFn(PlgMgr, S, ParamIdx);
	}

	AString ParamDesc;
	Printf(ParamDesc, "%s, %s, %s", S.GetTypeText(1).c_str(), S.GetTypeText(2).c_str(), S.GetTypeText(3).c_str());
	LOGWARNING("cPluginManager:AddHook(): bad parameters. Expected HOOK_TYPE and CallbackFunction, got %s. Hook not added.", ParamDesc.c_str());
	S.LogStackTrace();
	return 0;
}





static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S)
{
	/*
	Function signature:
	cPluginManager:Get():ForEachCommand(a_CallbackFn) -> bool
	*/

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cPluginManager") ||
		!L.CheckParamFunction(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Get the params:
	cLuaState::cRef FnRef;
	L.GetStackValues(2, FnRef);
	if (!FnRef.IsValid())
	{
		LOGWARN("Error in function call 'ForEachCommand': Could not get function reference of parameter #1");
		return 0;
	}

	// Callback for enumerating all commands:
	class cLuaCallback : public cPluginManager::cCommandEnumCallback
	{
	public:
		cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef):
			m_LuaState(a_LuaState),
			m_FnRef(a_FnRef)
		{
		}

	private:
		virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) override
		{
			UNUSED(a_Plugin);
			bool ret = false;
			m_LuaState.Call(m_FnRef, a_Command, a_Permission, a_HelpString, cLuaState::Return, ret);
			return ret;
		}
		cLuaState & m_LuaState;
		cLuaState::cRef & m_FnRef;
	} Callback(L, FnRef);

	// Execute and push the returned value:
	L.Push(cPluginManager::Get()->ForEachCommand(Callback));
	return 1;
}





static int tolua_cPluginManager_ForEachConsoleCommand(lua_State * tolua_S)
{
	/*
	Function signature:
	cPluginManager:Get():ForEachConsoleCommand(a_CallbackFn) -> bool
	*/

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cPluginManager") ||
		!L.CheckParamFunction(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Get the params:
	cLuaState::cRef FnRef;
	L.GetStackValues(2, FnRef);
	if (!FnRef.IsValid())
	{
		LOGWARN("Error in function call 'ForEachConsoleCommand': Could not get function reference of parameter #1");
		return 0;
	}

	// Callback for enumerating all commands:
	class cLuaCallback : public cPluginManager::cCommandEnumCallback
	{
	public:
		cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef):
			m_LuaState(a_LuaState),
			m_FnRef(a_FnRef)
		{
		}

	private:
		virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) override
		{
			UNUSED(a_Plugin);
			UNUSED(a_Permission);
			bool ret = false;
			m_LuaState.Call(m_FnRef, a_Command, a_HelpString, cLuaState::Return, ret);
			return ret;
		}
		cLuaState & m_LuaState;
		cLuaState::cRef & m_FnRef;
	} Callback(L, FnRef);

	// Execute and push the returned value:
	L.Push(cPluginManager::Get()->ForEachConsoleCommand(Callback));
	return 1;
}





static int tolua_cPluginManager_BindCommand(lua_State * a_LuaState)
{
	/* Function signatures:
		cPluginManager:BindCommand(Command, Permission, Function, HelpString)
		cPluginManager.BindCommand(Command, Permission, Function, HelpString)  -- without the "self" param
	*/
	cLuaState L(a_LuaState);
	cPluginLua * Plugin = cManualBindings::GetLuaPlugin(L);
	if (Plugin == nullptr)
	{
		return 0;
	}

	// Read the arguments to this API call:
	tolua_Error tolua_err;
	int idx = 1;
	if (
		tolua_isusertype (L, 1, "cPluginManager", 0, &tolua_err) ||
		tolua_isusertable(L, 1, "cPluginManager", 0, &tolua_err)
	)
	{
		idx++;
	}
	if (
		!tolua_iscppstring(L, idx,     0, &tolua_err) ||
		!tolua_iscppstring(L, idx + 1, 0, &tolua_err) ||
		!tolua_iscppstring(L, idx + 3, 0, &tolua_err) ||
		!tolua_isnoobj    (L, idx + 4, &tolua_err)
	)
	{
		tolua_error(L, "#ferror in function 'BindCommand'.", &tolua_err);
		return 0;
	}
	if (!lua_isfunction(L, idx + 2))
	{
		luaL_error(L, "\"BindCommand\" function expects a function as its 3rd parameter. Command-binding aborted.");
		return 0;
	}
	cPluginManager * self = cPluginManager::Get();
	AString Command, Permission, HelpString;
	cLuaState::cCallbackPtr Handler;
	L.GetStackValues(idx, Command, Permission, Handler, HelpString);
	if (!Handler->IsValid())
	{
		LOGERROR("\"BindCommand\": Cannot create a function reference. Command \"%s\" not bound.", Command.c_str());
		return 0;
	}

	auto CommandHandler = std::make_shared<LuaCommandHandler>(std::move(Handler));
	if (!self->BindCommand(Command, Plugin, CommandHandler, Permission, HelpString))
	{
		// Refused. Possibly already bound. Error message has been given, display the callstack:
		L.LogStackTrace();
		return 0;
	}

	L.Push(true);
	return 1;
}





static int tolua_cPluginManager_BindConsoleCommand(lua_State * a_LuaState)
{
	/* Function signatures:
		cPluginManager:BindConsoleCommand(Command, Function, HelpString)
		cPluginManager.BindConsoleCommand(Command, Function, HelpString)  -- without the "self" param
	*/

	// Get the plugin identification out of LuaState:
	cLuaState L(a_LuaState);
	cPluginLua * Plugin = cManualBindings::GetLuaPlugin(L);
	if (Plugin == nullptr)
	{
		return 0;
	}

	// Read the arguments to this API call:
	tolua_Error tolua_err;
	int idx = 1;
	if (
		tolua_isusertype(L, 1, "cPluginManager", 0, &tolua_err) ||
		tolua_isusertable(L, 1, "cPluginManager", 0, &tolua_err)
	)
	{
		idx++;
	}
	if (
		!tolua_iscppstring(L, idx,     0, &tolua_err) ||  // Command
		!tolua_iscppstring(L, idx + 2, 0, &tolua_err) ||  // HelpString
		!tolua_isnoobj    (L, idx + 3, &tolua_err)
	)
	{
		tolua_error(L, "#ferror in function 'BindConsoleCommand'.", &tolua_err);
		return 0;
	}
	if (!lua_isfunction(L, idx + 1))
	{
		luaL_error(L, "\"BindConsoleCommand\" function expects a function as its 2nd parameter. Command-binding aborted.");
		return 0;
	}
	cPluginManager * self = cPluginManager::Get();
	AString Command, HelpString;
	cLuaState::cCallbackPtr Handler;
	L.GetStackValues(idx, Command, Handler, HelpString);
	if (!Handler->IsValid())
	{
		LOGERROR("\"BindConsoleCommand\": Cannot create a function reference. Console command \"%s\" not bound.", Command.c_str());
		return 0;
	}

	auto CommandHandler = std::make_shared<LuaCommandHandler>(std::move(Handler));
	if (!self->BindConsoleCommand(Command, Plugin, CommandHandler, HelpString))
	{
		// Refused. Possibly already bound. Error message has been given, display the callstack:
		L.LogStackTrace();
		return 0;
	}
	L.Push(true);
	return 1;
}





static int tolua_cPluginManager_CallPlugin(lua_State * tolua_S)
{
	/*
	Function signature:
	cPluginManager:CallPlugin("PluginName", "FunctionName", args...)
	*/

	// Check the parameters:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cPluginManager") ||
		!L.CheckParamString(2, 3))
	{
		return 0;
	}

	// Retrieve the plugin name and function name
	AString PluginName, FunctionName;
	L.ToString(2, PluginName);
	L.ToString(3, FunctionName);
	if (PluginName.empty() || FunctionName.empty())
	{
		LOGWARNING("cPluginManager:CallPlugin(): Invalid plugin name or function name");
		L.LogStackTrace();
		return 0;
	}

	// If requesting calling the current plugin, refuse:
	cPluginLua * ThisPlugin = cManualBindings::GetLuaPlugin(L);
	if (ThisPlugin == nullptr)
	{
		return 0;
	}
	if (ThisPlugin->GetName() == PluginName)
	{
		LOGWARNING("cPluginManager::CallPlugin(): Calling self is not implemented (why would it?)");
		L.LogStackTrace();
		return 0;
	}

	// Call the destination plugin using a plugin callback:
	class cCallback :
		public cPluginManager::cPluginCallback
	{
	public:
		int m_NumReturns;

		cCallback(const AString & a_FunctionName, cLuaState & a_SrcLuaState) :
			m_NumReturns(0),
			m_FunctionName(a_FunctionName),
			m_SrcLuaState(a_SrcLuaState)
		{
		}
	protected:
		const AString & m_FunctionName;
		cLuaState & m_SrcLuaState;

		virtual bool Item(cPlugin * a_Plugin) override
		{
			if (!a_Plugin->IsLoaded())
			{
				return false;
			}
			m_NumReturns = static_cast<cPluginLua *>(a_Plugin)->CallFunctionFromForeignState(
				m_FunctionName, m_SrcLuaState, 4, lua_gettop(m_SrcLuaState)
			);
			return true;
		}
	} Callback(FunctionName, L);
	if (!cPluginManager::Get()->DoWithPlugin(PluginName, Callback))
	{
		return 0;
	}
	if (Callback.m_NumReturns < 0)
	{
		// The call has failed, there are zero return values. Do NOT return negative number (Lua considers that a "yield")
		return 0;
	}
	return Callback.m_NumReturns;
}





static int tolua_cPluginManager_ExecuteConsoleCommand(lua_State * tolua_S)
{
	/*
	Function signature:
	cPluginManager:ExecuteConsoleCommand(EntireCommandStr) -> OutputString
	*/

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cPluginManager") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Get the params:
	AString Command;
	L.GetStackValues(2, Command);
	auto Split = StringSplit(Command, " ");

	// Store the command output in a string:
	cStringAccumCommandOutputCallback CommandOutput;
	L.Push(cPluginManager::Get()->ExecuteConsoleCommand(Split, CommandOutput, Command));
	L.Push(CommandOutput.GetAccum());
	return 2;
}





static int tolua_cPluginManager_FindPlugins(lua_State * tolua_S)
{
	// API function no longer exists:
	LOGWARNING("cPluginManager:FindPlugins() is obsolete, use cPluginManager:RefreshPluginList() instead!");
	cLuaState::LogStackTrace(tolua_S);

	// Still, do the actual work performed by the API function when it existed:
	cPluginManager::Get()->RefreshPluginList();
	return 0;
}





static int tolua_cPlayer_GetPermissions(lua_State * tolua_S)
{
	// Function signature: cPlayer:GetPermissions() -> {permissions-array}

	// Check the params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cPlayer") ||
		!L.CheckParamEnd     (2)
	)
	{
		return 0;
	}

	// Get the params:
	cPlayer * self = reinterpret_cast<cPlayer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		LOGWARNING("%s: invalid self (%p)", __FUNCTION__, static_cast<void *>(self));
		return 0;
	}

	// Push the permissions:
	L.Push(self->GetPermissions());
	return 1;
}





static int tolua_cPlayer_GetRestrictions(lua_State * tolua_S)
{
	// Function signature: cPlayer:GetRestrictions() -> {restrictions-array}

	// Check the params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cPlayer") ||
		!L.CheckParamEnd     (2)
	)
	{
		return 0;
	}

	// Get the params:
	cPlayer * self = reinterpret_cast<cPlayer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		LOGWARNING("%s: invalid self (%p)", __FUNCTION__, static_cast<void *>(self));
		return 0;
	}

	// Push the permissions:
	L.Push(self->GetRestrictions());
	return 1;
}





static int tolua_cPlayer_PermissionMatches(lua_State * tolua_S)
{
	// Function signature: cPlayer:PermissionMatches(PermissionStr, TemplateStr) -> bool

	// Check the params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cPlayer") ||
		!L.CheckParamString   (2, 3) ||
		!L.CheckParamEnd      (4)
	)
	{
		return 0;
	}

	// Get the params:
	AString Permission, Template;
	L.GetStackValues(2, Permission, Template);

	// Push the result of the match:
	L.Push(cPlayer::PermissionMatches(StringSplit(Permission, "."), StringSplit(Template, ".")));
	return 1;
}





template <
	class OBJTYPE,
	void (OBJTYPE::*SetCallback)(cLuaState::cCallbackPtr && a_CallbackFn)
>
static int tolua_SetObjectCallback(lua_State * tolua_S)
{
	// Function signature: OBJTYPE:SetWhateverCallback(CallbackFunction)

	// Get the parameters - self and the function reference:
	cLuaState L(tolua_S);
	OBJTYPE * self;
	cLuaState::cCallbackPtr callback;
	if (!L.GetStackValues(1, self, callback))
	{
		LOGWARNING("%s: Cannot get parameters", __FUNCTION__);
		L.LogStackTrace();
		return 0;
	}

	// Set the callback
	(self->*SetCallback)(std::move(callback));
	return 0;
}





// Callback class used for the WebTab:
class cWebTabCallback:
	public cWebAdmin::cWebTabCallback
{
public:
	/** The Lua callback to call to generate the page contents. */
	cLuaState::cCallback m_Callback;

	virtual bool Call(
		const HTTPRequest & a_Request,
		const AString & a_UrlPath,
		AString & a_Content,
		AString & a_ContentType
	) override
	{
		AString content, contentType;
		return m_Callback.Call(&a_Request, a_UrlPath, cLuaState::Return, a_Content, a_ContentType);
	}
};





static int tolua_cPluginLua_AddWebTab(lua_State * tolua_S)
{
	// OBSOLETE, use cWebAdmin:AddWebTab() instead!
	// Function signature:
	// cPluginLua:AddWebTab(Title, CallbackFn, [UrlPath])

	// TODO: Warn about obsolete API usage
	// Only implement after merging the new API change and letting some time for changes in the plugins

	// Check params:
	cLuaState LuaState(tolua_S);
	cPluginLua * self = cManualBindings::GetLuaPlugin(tolua_S);
	if (self == nullptr)
	{
		return 0;
	}
	if (
		!LuaState.CheckParamString(2) ||
		!LuaState.CheckParamFunction(3) ||
		// Optional string as param 4
		!LuaState.CheckParamEnd(5)
	)
	{
		return 0;
	}

	// Read the params:
	AString title, urlPath;
	auto callback = std::make_shared<cWebTabCallback>();
	if (!LuaState.GetStackValues(2, title, callback->m_Callback))
	{
		LOGWARNING("cPlugin:AddWebTab(): Cannot read required parameters");
		return 0;
	}
	if (!LuaState.GetStackValue(4, urlPath))
	{
		urlPath = cWebAdmin::GetURLEncodedString(title);
	}

	cRoot::Get()->GetWebAdmin()->AddWebTab(title, urlPath, self->GetName(), callback);

	return 0;
}





static int tolua_cPlugin_GetDirectory(lua_State * tolua_S)
{
	cLuaState L(tolua_S);

	// Log the obsoletion warning:
	LOGWARNING("cPlugin:GetDirectory() is obsolete, use cPlugin:GetFolderName() instead.");
	L.LogStackTrace();

	// Retrieve the params:
	cPlugin * Plugin = static_cast<cPluginLua *>(tolua_tousertype(tolua_S, 1, nullptr));

	// Get the folder name:
	L.Push(Plugin->GetFolderName());
	return 1;
}





static int tolua_cPlugin_GetLocalDirectory(lua_State * tolua_S)
{
	cLuaState L(tolua_S);

	// Log the obsoletion warning:
	LOGWARNING("cPlugin:GetLocalDirectory() is obsolete, use cPlugin:GetLocalFolder() instead.");
	L.LogStackTrace();

	// Retrieve the params:
	cPlugin * Plugin = static_cast<cPluginLua *>(tolua_tousertype(tolua_S, 1, nullptr));

	// Get the folder:
	L.Push(Plugin->GetLocalFolder());
	return 1;
}





static int tolua_md5(lua_State * tolua_S)
{
	// Calculate the raw md5 checksum byte array:
	unsigned char Output[16];
	size_t len = 0;
	const unsigned char * SourceString = reinterpret_cast<const unsigned char *>(lua_tolstring(tolua_S, 1, &len));
	if (SourceString == nullptr)
	{
		return 0;
	}
	md5(SourceString, len, Output);
	lua_pushlstring(tolua_S, reinterpret_cast<const char *>(Output), ARRAYCOUNT(Output));
	return 1;
}





/** Does the same as tolua_md5, but reports that the usage is obsolete and the plugin should use cCrypto.md5(). */
static int tolua_md5_obsolete(lua_State * tolua_S)
{
	LOGWARNING("Using md5() is obsolete, please change your plugin to use cCryptoHash.md5()");
	cLuaState::LogStackTrace(tolua_S);
	return tolua_md5(tolua_S);
}





static int tolua_md5HexString(lua_State * tolua_S)
{
	// Calculate the raw md5 checksum byte array:
	unsigned char md5Output[16];
	size_t len = 0;
	const unsigned char * SourceString = reinterpret_cast<const unsigned char *>(lua_tolstring(tolua_S, 1, &len));
	if (SourceString == nullptr)
	{
		return 0;
	}
	md5(SourceString, len, md5Output);

	// Convert the md5 checksum to hex string:
	std::stringstream Output;
	Output << std::hex << std::setfill('0');
	for (size_t i = 0; i < ARRAYCOUNT(md5Output); i++)
	{
		Output << std::setw(2) << static_cast<unsigned short>(md5Output[i]);  // Need to cast to a number, otherwise a char is output
	}
	lua_pushlstring(tolua_S, Output.str().c_str(), Output.str().size());
	return 1;
}





static int tolua_sha1(lua_State * tolua_S)
{
	// Calculate the raw SHA1 checksum byte array from the input string:
	unsigned char Output[20];
	size_t len = 0;
	const unsigned char * SourceString = reinterpret_cast<const unsigned char *>(lua_tolstring(tolua_S, 1, &len));
	if (SourceString == nullptr)
	{
		return 0;
	}
	sha1(SourceString, len, Output);
	lua_pushlstring(tolua_S, reinterpret_cast<const char *>(Output), ARRAYCOUNT(Output));
	return 1;
}





static int tolua_sha1HexString(lua_State * tolua_S)
{
	// Calculate the raw SHA1 checksum byte array from the input string:
	unsigned char sha1Output[20];
	size_t len = 0;
	const unsigned char * SourceString = reinterpret_cast<const unsigned char *>(lua_tolstring(tolua_S, 1, &len));
	if (SourceString == nullptr)
	{
		return 0;
	}
	sha1(SourceString, len, sha1Output);

	// Convert the sha1 checksum to hex string:
	std::stringstream Output;
	Output << std::hex << std::setfill('0');
	for (size_t i = 0; i < ARRAYCOUNT(sha1Output); i++)
	{
		Output << std::setw(2) << static_cast<unsigned short>(sha1Output[i]);  // Need to cast to a number, otherwise a char is output
	}
	lua_pushlstring(tolua_S, Output.str().c_str(), Output.str().size());
	return 1;
}





static int tolua_push_StringStringMap(lua_State* tolua_S, std::map< std::string, std::string >& a_StringStringMap)
{
	lua_newtable(tolua_S);
	int top = lua_gettop(tolua_S);

	for (std::map<std::string, std::string>::iterator it = a_StringStringMap.begin(); it != a_StringStringMap.end(); ++it)
	{
		const char * key = it->first.c_str();
		const char * value = it->second.c_str();
		lua_pushstring(tolua_S, key);
		lua_pushstring(tolua_S, value);
		lua_settable(tolua_S, top);
	}

	return 1;
}





static int tolua_get_HTTPRequest_Params(lua_State* tolua_S)
{
	HTTPRequest * self = reinterpret_cast<HTTPRequest *>(tolua_tousertype(tolua_S, 1, nullptr));
	return tolua_push_StringStringMap(tolua_S, self->Params);
}





static int tolua_get_HTTPRequest_PostParams(lua_State* tolua_S)
{
	HTTPRequest * self = reinterpret_cast<HTTPRequest *>(tolua_tousertype(tolua_S, 1, nullptr));
	return tolua_push_StringStringMap(tolua_S, self->PostParams);
}





static int tolua_get_HTTPRequest_FormData(lua_State* tolua_S)
{
	HTTPRequest * self = reinterpret_cast<HTTPRequest *>(tolua_tousertype(tolua_S, 1, nullptr));
	std::map<std::string, HTTPFormData> & FormData = self->FormData;

	lua_newtable(tolua_S);
	int top = lua_gettop(tolua_S);

	for (std::map<std::string, HTTPFormData>::iterator it = FormData.begin(); it != FormData.end(); ++it)
	{
		lua_pushstring(tolua_S, it->first.c_str());
		tolua_pushusertype(tolua_S, &(it->second), "HTTPFormData");
		// lua_pushlstring(tolua_S, it->second.Value.c_str(), it->second.Value.size());  // Might contain binary data
		lua_settable(tolua_S, top);
	}

	return 1;
}





static int tolua_cUrlParser_GetDefaultPort(lua_State * a_LuaState)
{
	// API function signature:
	// cUrlParser:GetDefaultPort("scheme") -> number

	// Check params:
	cLuaState L(a_LuaState);
	if (
		!L.CheckParamUserTable(1, "cUrlParser") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Read params from Lua:
	AString scheme;
	L.GetStackValue(2, scheme);

	// Execute and push result:
	L.Push(cUrlParser::GetDefaultPort(scheme));
	return 1;
}





static int tolua_cUrlParser_IsKnownScheme(lua_State * a_LuaState)
{
	// API function signature:
	// cUrlParser:IsKnownScheme("scheme") -> bool

	// Check params:
	cLuaState L(a_LuaState);
	if (
		!L.CheckParamUserTable(1, "cUrlParser") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Read params from Lua:
	AString scheme;
	L.GetStackValue(2, scheme);

	// Execute and push result:
	L.Push(cUrlParser::IsKnownScheme(scheme));
	return 1;
}





static int tolua_cUrlParser_Parse(lua_State * a_LuaState)
{
	// API function signature:
	// cUrlParser:Parse("url") -> "scheme", "user", "password", "host", portnum, "path", "query", "fragment"
	// On error, returns nil and error message

	// Check params:
	cLuaState L(a_LuaState);
	if (
		!L.CheckParamUserTable(1, "cUrlParser") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Read params from Lua:
	AString url;
	L.GetStackValue(2, url);

	// Execute and push result:
	AString scheme, username, password, host, path, query, fragment;
	UInt16 port;
	auto res = cUrlParser::Parse(url, scheme, username, password, host, port, path, query, fragment);
	if (!res.first)
	{
		// Error, return nil and error msg:
		L.PushNil();
		L.Push(res.second);
		return 2;
	}
	L.Push(scheme);
	L.Push(username);
	L.Push(password);
	L.Push(host);
	L.Push(port);
	L.Push(path);
	L.Push(query);
	L.Push(fragment);
	return 8;
}





static int tolua_cUrlParser_ParseAuthorityPart(lua_State * a_LuaState)
{
	// API function signature:
	// cUrlParser:ParseAuthorityPart("authority") -> "user", "password", "host", portnum
	// On error, returns nil and error message
	// Parts not specified in the "authority" are left empty / zero

	// Check params:
	cLuaState L(a_LuaState);
	if (
		!L.CheckParamUserTable(1, "cUrlParser") ||
		!L.CheckParamString(2) ||
		!L.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Read params from Lua:
	AString authPart;
	L.GetStackValue(2, authPart);

	// Execute and push result:
	AString username, password, host;
	UInt16 port;
	auto res = cUrlParser::ParseAuthorityPart(authPart, username, password, host, port);
	if (!res.first)
	{
		// Error, return nil and error msg:
		L.PushNil();
		L.Push(res.second);
		return 2;
	}
	L.Push(username);
	L.Push(password);
	L.Push(host);
	L.Push(port);
	return 4;
}





static int tolua_cWebAdmin_AddWebTab(lua_State * tolua_S)
{
	// Function signatures:
	// cWebAdmin:AddWebTab(Title, UrlPath, CallbackFn)

	// Check params:
	cLuaState LuaState(tolua_S);
	cPluginLua * self = cManualBindings::GetLuaPlugin(tolua_S);
	if (self == nullptr)
	{
		return 0;
	}
	if (
		// Don't care whether the first param is a cWebAdmin instance or class
		!LuaState.CheckParamString(2, 3) ||
		!LuaState.CheckParamFunction(4) ||
		!LuaState.CheckParamEnd(5)
	)
	{
		return 0;
	}

	// Read the params:
	AString title, urlPath;
	auto callback = std::make_shared<cWebTabCallback>();
	if (!LuaState.GetStackValues(2, title, urlPath, callback->m_Callback))
	{
		LOGWARNING("cWebAdmin:AddWebTab(): Cannot read required parameters");
		return 0;
	}

	cRoot::Get()->GetWebAdmin()->AddWebTab(title, urlPath, self->GetName(), callback);

	return 0;
}





static int tolua_cWebAdmin_GetAllWebTabs(lua_State * tolua_S)
{
	// Function signature:
	// cWebAdmin:GetAllWebTabs() -> { {"PluginName", "UrlPath", "Title"}, {"PluginName", "UrlPath", "Title"}, ...}

	// Don't care about params at all

	auto webTabs = cRoot::Get()->GetWebAdmin()->GetAllWebTabs();
	lua_createtable(tolua_S, static_cast<int>(webTabs.size()), 0);
	int newTable = lua_gettop(tolua_S);
	int index = 1;
	cLuaState L(tolua_S);
	for (const auto & wt: webTabs)
	{
		lua_createtable(tolua_S, 0, 3);
		L.Push(wt->m_PluginName);
		lua_setfield(tolua_S, -2, "PluginName");
		L.Push(wt->m_UrlPath);
		lua_setfield(tolua_S, -2, "UrlPath");
		L.Push(wt->m_Title);
		lua_setfield(tolua_S, -2, "Title");
		lua_rawseti(tolua_S, newTable, index);
		++index;
	}
	return 1;
}





/** Binding for cWebAdmin::GetBaseURL.
Manual code required because ToLua generates an extra return value */
static int tolua_cWebAdmin_GetBaseURL(lua_State * tolua_S)
{
	// Check the param types:
	cLuaState S(tolua_S);
	if (
		// Don't care whether the first param is a cWebAdmin instance or class
		!S.CheckParamString(2) ||
		!S.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Get the parameters:
	AString Input;
	S.GetStackValue(2, Input);

	// Convert and return:
	S.Push(cWebAdmin::GetBaseURL(Input));
	return 1;
}





/** Binding for cWebAdmin::GetContentTypeFromFileExt.
Manual code required because ToLua generates an extra return value */
static int tolua_cWebAdmin_GetContentTypeFromFileExt(lua_State * tolua_S)
{
	// Check the param types:
	cLuaState S(tolua_S);
	if (
		// Don't care whether the first param is a cWebAdmin instance or class
		!S.CheckParamString(2) ||
		!S.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Get the parameters:
	AString Input;
	S.GetStackValue(2, Input);

	// Convert and return:
	S.Push(cWebAdmin::GetContentTypeFromFileExt(Input));
	return 1;
}





/** Binding for cWebAdmin::GetHTMLEscapedString.
Manual code required because ToLua generates an extra return value */
static int tolua_cWebAdmin_GetHTMLEscapedString(lua_State * tolua_S)
{
	// Check the param types:
	cLuaState S(tolua_S);
	if (
		// Don't care whether the first param is a cWebAdmin instance or class
		!S.CheckParamString(2) ||
		!S.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Get the parameters:
	AString Input;
	S.GetStackValue(2, Input);

	// Convert and return:
	S.Push(cWebAdmin::GetHTMLEscapedString(Input));
	return 1;
}





/** Binding for cWebAdmin::GetPage. */
static int tolua_cWebAdmin_GetPage(lua_State * tolua_S)
{
	/*
	Function signature:
	cWebAdmin:GetPage(a_HTTPRequest) ->
	{
		Content = "",       // Content generated by the plugin
		ContentType = "",   // Content type generated by the plugin (default: "text/html")
		UrlPath = "",       // URL path of the tab
		TabTitle = "",      // Tab's title, as register via cWebAdmin:AddWebTab()
		PluginName = "",    // Plugin's API name
		PluginFolder = "",  // Plugin's folder name (display name)
	}
	*/

	// Check the param types:
	cLuaState S(tolua_S);
	if (
		// Don't care about first param, whether it's cWebAdmin instance or class
		!S.CheckParamUserType(2, "HTTPRequest") ||
		!S.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Get the parameters:
	HTTPRequest * request = nullptr;
	if (!S.GetStackValue(2, request))
	{
		LOGWARNING("cWebAdmin:GetPage(): Cannot read the HTTPRequest parameter.");
		return 0;
	}

	// Generate the page and push the results as a dictionary-table:
	auto page = cRoot::Get()->GetWebAdmin()->GetPage(*request);
	lua_createtable(S, 0, 6);
	S.Push(page.Content);
	lua_setfield(S, -2, "Content");
	S.Push(page.ContentType);
	lua_setfield(S, -2, "ContentType");
	S.Push(page.TabUrlPath);
	lua_setfield(S, -2, "UrlPath");
	S.Push(page.TabTitle);
	lua_setfield(S, -2, "TabTitle");
	S.Push(page.PluginName);
	lua_setfield(S, -2, "PluginName");
	S.Push(cPluginManager::Get()->GetPluginFolderName(page.PluginName));
	lua_setfield(S, -2, "PluginFolder");
	return 1;
}





/** Binding for cWebAdmin::GetURLEncodedString.
Manual code required because ToLua generates an extra return value */
static int tolua_cWebAdmin_GetURLEncodedString(lua_State * tolua_S)
{
	// Check the param types:
	cLuaState S(tolua_S);
	if (
		// Don't care whether the first param is a cWebAdmin instance or class
		!S.CheckParamString(2) ||
		!S.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Get the parameters:
	AString Input;
	S.GetStackValue(2, Input);

	// Convert and return:
	S.Push(cWebAdmin::GetURLEncodedString(Input));
	return 1;
}





static int tolua_cClientHandle_SendPluginMessage(lua_State * L)
{
	cLuaState S(L);
	if (
		!S.CheckParamUserType(1, "cClientHandle") ||
		!S.CheckParamString(2, 3) ||
		!S.CheckParamEnd(4)
	)
	{
		return 0;
	}
	cClientHandle * Client = reinterpret_cast<cClientHandle *>(tolua_tousertype(L, 1, nullptr));
	if (Client == nullptr)
	{
		LOGWARNING("ClientHandle is nil in cClientHandle:SendPluginMessage()");
		S.LogStackTrace();
		return 0;
	}
	AString Channel, Message;
	Channel.assign(lua_tostring(L, 2), lua_strlen(L, 2));
	Message.assign(lua_tostring(L, 3), lua_strlen(L, 3));
	Client->SendPluginMessage(Channel, Message);
	return 0;
}





static int tolua_cMojangAPI_AddPlayerNameToUUIDMapping(lua_State * L)
{
	cLuaState S(L);
	if (
		!S.CheckParamUserTable(1, "cMojangAPI") ||
		!S.CheckParamString(2) ||
		!S.CheckParamString(3) ||
		!S.CheckParamEnd(4)
	)
	{
		return 0;
	}

	// Retrieve the parameters:
	AString UUID, PlayerName;
	S.GetStackValue(2, PlayerName);
	S.GetStackValue(3, UUID);

	// Store in the cache:
	cRoot::Get()->GetMojangAPI().AddPlayerNameToUUIDMapping(PlayerName, UUID);
	return 0;
}





static int tolua_cMojangAPI_GetPlayerNameFromUUID(lua_State * L)
{
	cLuaState S(L);
	if (
		!S.CheckParamUserTable(1, "cMojangAPI") ||
		!S.CheckParamString(2) ||
		!S.CheckParamEnd(4)
	)
	{
		return 0;
	}

	AString UUID;
	S.GetStackValue(2, UUID);

	// If the UseOnlyCached param was given, read it; default to false
	bool ShouldUseCacheOnly = false;
	if (lua_gettop(L) == 3)
	{
		ShouldUseCacheOnly = (lua_toboolean(L, 3) != 0);
		lua_pop(L, 1);
	}

	// Return the PlayerName:
	AString PlayerName = cRoot::Get()->GetMojangAPI().GetPlayerNameFromUUID(UUID, ShouldUseCacheOnly);
	S.Push(PlayerName);
	return 1;
}





static int tolua_cMojangAPI_GetUUIDFromPlayerName(lua_State * L)
{
	cLuaState S(L);
	if (
		!S.CheckParamUserTable(1, "cMojangAPI") ||
		!S.CheckParamString(2) ||
		!S.CheckParamEnd(4)
	)
	{
		return 0;
	}

	AString PlayerName;
	S.GetStackValue(2, PlayerName);

	// If the UseOnlyCached param was given, read it; default to false
	bool ShouldUseCacheOnly = false;
	if (lua_gettop(L) == 3)
	{
		ShouldUseCacheOnly = (lua_toboolean(L, 3) != 0);
		lua_pop(L, 1);
	}

	// Return the UUID:
	AString UUID = cRoot::Get()->GetMojangAPI().GetUUIDFromPlayerName(PlayerName, ShouldUseCacheOnly);
	S.Push(UUID);
	return 1;
}





static int tolua_cMojangAPI_GetUUIDsFromPlayerNames(lua_State * L)
{
	cLuaState S(L);
	if (
		!S.CheckParamUserTable(1, "cMojangAPI") ||
		!S.CheckParamTable(2) ||
		!S.CheckParamEnd(4)
	)
	{
		return 0;
	}

	// Convert the input table into AStringVector:
	AStringVector PlayerNames;
	int NumNames = luaL_getn(L, 2);
	PlayerNames.reserve(static_cast<size_t>(NumNames));
	for (int i = 1; i <= NumNames; i++)
	{
		lua_rawgeti(L, 2, i);
		AString Name;
		S.GetStackValue(-1, Name);
		if (!Name.empty())
		{
			PlayerNames.push_back(Name);
		}
		lua_pop(L, 1);
	}

	// If the UseOnlyCached param was given, read it; default to false
	bool ShouldUseCacheOnly = false;
	if (lua_gettop(L) == 3)
	{
		ShouldUseCacheOnly = (lua_toboolean(L, 3) != 0);
		lua_pop(L, 1);
	}

	// Push the output table onto the stack:
	lua_newtable(L);

	// Get the UUIDs:
	AStringVector UUIDs = cRoot::Get()->GetMojangAPI().GetUUIDsFromPlayerNames(PlayerNames, ShouldUseCacheOnly);
	if (UUIDs.size() != PlayerNames.size())
	{
		// A hard error has occured while processing the request, no UUIDs were returned. Return an empty table:
		return 1;
	}

	// Convert to output table, PlayerName -> UUID:
	size_t len = UUIDs.size();
	for (size_t i = 0; i < len; i++)
	{
		if (UUIDs[i].empty())
		{
			// No UUID was provided for PlayerName[i], skip it in the resulting table
			continue;
		}
		lua_pushlstring(L, UUIDs[i].c_str(), UUIDs[i].length());
		lua_setfield(L, 3, PlayerNames[i].c_str());
	}
	return 1;
}





static int tolua_cMojangAPI_MakeUUIDDashed(lua_State * L)
{
	// Function signature: cMojangAPI:MakeUUIDDashed(UUID) -> string

	// Check params:
	cLuaState S(L);
	if (
		!S.CheckParamUserTable(1, "cMojangAPI") ||
		!S.CheckParamString(2) ||
		!S.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Get the params:
	AString UUID;
	S.GetStackValue(2, UUID);

	// Push the result:
	S.Push(cRoot::Get()->GetMojangAPI().MakeUUIDDashed(UUID));
	return 1;
}





static int tolua_cMojangAPI_MakeUUIDShort(lua_State * L)
{
	// Function signature: cMojangAPI:MakeUUIDShort(UUID) -> string

	// Check params:
	cLuaState S(L);
	if (
		!S.CheckParamUserTable(1, "cMojangAPI") ||
		!S.CheckParamString(2) ||
		!S.CheckParamEnd(3)
	)
	{
		return 0;
	}

	// Get the params:
	AString UUID;
	S.GetStackValue(2, UUID);

	// Push the result:
	S.Push(cRoot::Get()->GetMojangAPI().MakeUUIDShort(UUID));
	return 1;
}





static int Lua_ItemGrid_GetSlotCoords(lua_State * L)
{
	tolua_Error tolua_err;
	if (
		!tolua_isusertype(L, 1, "const cItemGrid", 0, &tolua_err) ||
		!tolua_isnumber  (L, 2, 0, &tolua_err) ||
		!tolua_isnoobj   (L, 3, &tolua_err)
	)
	{
		goto tolua_lerror;
	}

	{
		const cItemGrid * self = reinterpret_cast<const cItemGrid *>(tolua_tousertype(L, 1, nullptr));
		int SlotNum = static_cast<int>(tolua_tonumber(L, 2, 0));
		if (self == nullptr)
		{
			tolua_error(L, "invalid 'self' in function 'cItemGrid:GetSlotCoords'", nullptr);
			return 0;
		}
		int X, Y;
		self->GetSlotCoords(SlotNum, X, Y);
		tolua_pushnumber(L, static_cast<lua_Number>(X));
		tolua_pushnumber(L, static_cast<lua_Number>(Y));
		return 2;
	}

tolua_lerror:
	tolua_error(L, "#ferror in function 'cItemGrid:GetSlotCoords'.", &tolua_err);
	return 0;
}





/** Provides interface between a Lua table of callbacks and the cBlockTracer::cCallbacks */
class cLuaBlockTracerCallbacks :
	public cBlockTracer::cCallbacks
{
public:
	cLuaBlockTracerCallbacks(cLuaState & a_LuaState, int a_ParamNum) :
		m_LuaState(a_LuaState),
		m_TableRef(a_LuaState, a_ParamNum)
	{
	}

	virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
	{
		bool res = false;
		if (!m_LuaState.Call(
			cLuaState::cTableRef(m_TableRef, "OnNextBlock"),
			a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_EntryFace,
			cLuaState::Return, res
		))
		{
			// No such function in the table, skip the callback
			return false;
		}
		return res;
	}

	virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) override
	{
		bool res = false;
		if (!m_LuaState.Call(
			cLuaState::cTableRef(m_TableRef, "OnNextBlockNoData"),
			a_BlockX, a_BlockY, a_BlockZ, a_EntryFace,
			cLuaState::Return, res
		))
		{
			// No such function in the table, skip the callback
			return false;
		}
		return res;
	}

	virtual bool OnOutOfWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override
	{
		bool res = false;
		if (!m_LuaState.Call(
			cLuaState::cTableRef(m_TableRef, "OnOutOfWorld"),
			a_BlockX, a_BlockY, a_BlockZ,
			cLuaState::Return, res
		))
		{
			// No such function in the table, skip the callback
			return false;
		}
		return res;
	}

	virtual bool OnIntoWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override
	{
		bool res = false;
		if (!m_LuaState.Call(
			cLuaState::cTableRef(m_TableRef, "OnIntoWorld"),
			a_BlockX, a_BlockY, a_BlockZ,
			cLuaState::Return, res
		))
		{
			// No such function in the table, skip the callback
			return false;
		}
		return res;
	}

	virtual void OnNoMoreHits(void) override
	{
		m_LuaState.Call(cLuaState::cTableRef(m_TableRef, "OnNoMoreHits"));
	}

	virtual void OnNoChunk(void) override
	{
		m_LuaState.Call(cLuaState::cTableRef(m_TableRef, "OnNoChunk"));
	}

protected:
	cLuaState & m_LuaState;
	cLuaState::cRef m_TableRef;
} ;





static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S)
{
	/* Supported function signatures:
	cLineBlockTracer:Trace(World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ)  // Canonical
	cLineBlockTracer.Trace(World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ)
	*/

	// If the first param is the cLineBlockTracer class, shift param index by one:
	int idx = 1;
	tolua_Error err;
	if (tolua_isusertable(tolua_S, 1, "cLineBlockTracer", 0, &err))
	{
		idx = 2;
	}

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(idx, "cWorld") ||
		!L.CheckParamTable   (idx + 1) ||
		!L.CheckParamNumber  (idx + 2, idx + 7) ||
		!L.CheckParamEnd     (idx + 8)
	)
	{
		return 0;
	}

	// Trace:
	cWorld * World = reinterpret_cast<cWorld *>(tolua_tousertype(L, idx, nullptr));
	cLuaBlockTracerCallbacks Callbacks(L, idx + 1);
	double StartX = tolua_tonumber(L, idx + 2, 0);
	double StartY = tolua_tonumber(L, idx + 3, 0);
	double StartZ = tolua_tonumber(L, idx + 4, 0);
	double EndX   = tolua_tonumber(L, idx + 5, 0);
	double EndY   = tolua_tonumber(L, idx + 6, 0);
	double EndZ   = tolua_tonumber(L, idx + 7, 0);
	bool res = cLineBlockTracer::Trace(*World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ);
	tolua_pushboolean(L, res ? 1 : 0);
	return 1;
}





static int tolua_cLuaWindow_new(lua_State * tolua_S)
{
	// Function signature:
	// cLuaWindow:new(type, slotsX, slotsY, title)

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cLuaWindow") ||
		!L.CheckParamNumber(2, 4) ||
		!L.CheckParamString(5) ||
		!L.CheckParamEnd(6)
	)
	{
		return 0;
	}

	// Read params:
	int windowType, slotsX, slotsY;
	AString title;
	if (!L.GetStackValues(2, windowType, slotsX, slotsY, title))
	{
		LOGWARNING("%s: Cannot read Lua parameters", __FUNCTION__);
		L.LogStackValues();
		L.LogStackTrace();
	}

	// Create the window and return it:
	L.Push(new cLuaWindow(L, static_cast<cLuaWindow::WindowType>(windowType), slotsX, slotsY, title));
	return 1;
}





static int tolua_cLuaWindow_new_local(lua_State * tolua_S)
{
	// Function signature:
	// cLuaWindow:new(type, slotsX, slotsY, title)

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cLuaWindow") ||
		!L.CheckParamNumber(2, 4) ||
		!L.CheckParamString(5) ||
		!L.CheckParamEnd(6)
	)
	{
		return 0;
	}

	// Read params:
	int windowType, slotsX, slotsY;
	AString title;
	if (!L.GetStackValues(2, windowType, slotsX, slotsY, title))
	{
		LOGWARNING("%s: Cannot read Lua parameters", __FUNCTION__);
		L.LogStackValues();
		L.LogStackTrace();
	}

	// Create the window, register it for GC and return it:
	L.Push(new cLuaWindow(L, static_cast<cLuaWindow::WindowType>(windowType), slotsX, slotsY, title));
	tolua_register_gc(tolua_S, lua_gettop(tolua_S));
	return 1;
}





static int tolua_cRoot_GetBuildCommitID(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	L.Push(BUILD_COMMIT_ID);
	return 1;
}





static int tolua_cRoot_GetBuildDateTime(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	L.Push(BUILD_DATETIME);
	return 1;
}





static int tolua_cRoot_GetBuildID(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	L.Push(BUILD_ID);
	return 1;
}





static int tolua_cRoot_GetBuildSeriesName(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	L.Push(BUILD_SERIES_NAME);
	return 1;
}





static int tolua_cRoot_GetBrewingRecipe(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cRoot") ||
		!L.CheckParamUserType (2, "const cItem") ||
		!L.CheckParamUserType (3, "const cItem") ||
		!L.CheckParamEnd      (4)
	)
	{
		return 0;
	}

	// Check the bottle param:
	cItem * Bottle = nullptr;
	L.GetStackValue(2, Bottle);
	if (Bottle == nullptr)
	{
		LOGWARNING("cRoot:GetBrewingRecipe: the Bottle parameter is nil or missing.");
		return 0;
	}

	cItem * Ingredient = nullptr;
	L.GetStackValue(3, Ingredient);
	if (Ingredient == nullptr)
	{
		LOGWARNING("cRoot:GetBrewingRecipe: the Ingredient parameter is nil or missing.");
		return 0;
	}

	// Get the recipe for the input
	cBrewingRecipes * BR = cRoot::Get()->GetBrewingRecipes();
	const cBrewingRecipes::cRecipe * Recipe = BR->GetRecipeFrom(*Bottle, *Ingredient);
	if (Recipe == nullptr)
	{
		// There is no such brewing recipe for this bottle and ingredient, return no value
		return 0;
	}

	// Push the output item
	L.Push(Recipe->Output.get());
	return 1;
}





static int tolua_cRoot_GetFurnaceRecipe(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserTable(1, "cRoot") ||
		!L.CheckParamUserType (2, "const cItem") ||
		!L.CheckParamEnd      (3)
	)
	{
		return 0;
	}

	// Check the input param:
	cItem * Input = nullptr;
	L.GetStackValue(2, Input);
	if (Input == nullptr)
	{
		LOGWARNING("cRoot:GetFurnaceRecipe: the Input parameter is nil or missing.");
		return 0;
	}

	// Get the recipe for the input
	cFurnaceRecipe * FR = cRoot::Get()->GetFurnaceRecipe();
	const cFurnaceRecipe::cRecipe * Recipe = FR->GetRecipeFrom(*Input);
	if (Recipe == nullptr)
	{
		// There is no such furnace recipe for this input, return no value
		return 0;
	}

	// Push the output, number of ticks and input as the three return values:
	L.Push(Recipe->Out);
	L.Push(Recipe->CookTime);
	L.Push(Recipe->In);
	return 3;
}





static int tolua_cScoreboard_GetTeamNames(lua_State * L)
{
	cLuaState S(L);
	if (
		!S.CheckParamUserType(1, "cScoreboard") ||
		!S.CheckParamEnd(2)
	)
	{
		return 0;
	}

	// Get the groups:
	cScoreboard * Scoreboard = reinterpret_cast<cScoreboard *>(tolua_tousertype(L, 1, nullptr));
	AStringVector Teams = Scoreboard->GetTeamNames();

	// Push the results:
	S.Push(Teams);
	return 1;
}





static int tolua_cHopperEntity_GetOutputBlockPos(lua_State * tolua_S)
{
	// function cHopperEntity::GetOutputBlockPos()
	// Exported manually because tolua would require meaningless params

	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cHopperEntity") ||
		!L.CheckParamNumber  (2) ||
		!L.CheckParamEnd     (3)
	)
	{
		return 0;
	}
	cHopperEntity * self = reinterpret_cast<cHopperEntity *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cHopperEntity::GetOutputBlockPos()'", nullptr);
		return 0;
	}

	NIBBLETYPE a_BlockMeta = static_cast<NIBBLETYPE>(tolua_tonumber(tolua_S, 2, 0));
	int a_OutputX, a_OutputY, a_OutputZ;
	bool res = self->GetOutputBlockPos(a_BlockMeta, a_OutputX, a_OutputY, a_OutputZ);
	tolua_pushboolean(tolua_S, res);
	if (res)
	{
		tolua_pushnumber(tolua_S, static_cast<lua_Number>(a_OutputX));
		tolua_pushnumber(tolua_S, static_cast<lua_Number>(a_OutputY));
		tolua_pushnumber(tolua_S, static_cast<lua_Number>(a_OutputZ));
		return 4;
	}
	return 1;
}






static int tolua_cBlockArea_GetBlockTypeMeta(lua_State * tolua_S)
{
	// function cBlockArea::GetBlockTypeMeta()
	// Exported manually because tolua generates extra input params for the outputs

	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cBlockArea") ||
		!L.CheckParamNumber  (2, 4)
	)
	{
		return 0;
	}

	cBlockArea * self = reinterpret_cast<cBlockArea *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetRelBlockTypeMeta'", nullptr);
		return 0;
	}
	int BlockX = static_cast<int>(tolua_tonumber(tolua_S, 2, 0));
	int BlockY = static_cast<int>(tolua_tonumber(tolua_S, 3, 0));
	int BlockZ = static_cast<int>(tolua_tonumber(tolua_S, 4, 0));
	BLOCKTYPE BlockType;
	NIBBLETYPE BlockMeta;
	self->GetBlockTypeMeta(BlockX, BlockY, BlockZ, BlockType, BlockMeta);
	tolua_pushnumber(tolua_S, BlockType);
	tolua_pushnumber(tolua_S, BlockMeta);
	return 2;
}





static int tolua_cBlockArea_GetOrigin(lua_State * tolua_S)
{
	// function cBlockArea::GetOrigin()
	// Returns all three coords of the origin point
	// Exported manually because there's no direct C++ equivalent,
	// plus tolua would generate extra input params for the outputs

	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cBlockArea"))
	{
		return 0;
	}

	cBlockArea * self = reinterpret_cast<cBlockArea *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetOrigin'", nullptr);
		return 0;
	}

	// Push the three origin coords:
	lua_pushnumber(tolua_S, self->GetOriginX());
	lua_pushnumber(tolua_S, self->GetOriginY());
	lua_pushnumber(tolua_S, self->GetOriginZ());
	return 3;
}





static int tolua_cBlockArea_GetNonAirCropRelCoords(lua_State * tolua_S)
{
	// function cBlockArea::GetNonAirCropRelCoords()
	// Exported manually because tolua would generate extra input params for the outputs

	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cBlockArea"))
	{
		return 0;
	}

	cBlockArea * self = nullptr;
	BLOCKTYPE IgnoreBlockType = E_BLOCK_AIR;
	L.GetStackValues(1, self, IgnoreBlockType);
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetNonAirCropRelCoords'", nullptr);
		return 0;
	}

	// Calculate the crop coords:
	int MinRelX, MinRelY, MinRelZ, MaxRelX, MaxRelY, MaxRelZ;
	self->GetNonAirCropRelCoords(MinRelX, MinRelY, MinRelZ, MaxRelX, MaxRelY, MaxRelZ, IgnoreBlockType);

	// Push the six crop coords:
	L.Push(MinRelX);
	L.Push(MinRelY);
	L.Push(MinRelZ);
	L.Push(MaxRelX);
	L.Push(MaxRelY);
	L.Push(MaxRelZ);
	return 6;
}





static int tolua_cBlockArea_GetRelBlockTypeMeta(lua_State * tolua_S)
{
	// function cBlockArea::GetRelBlockTypeMeta()
	// Exported manually because tolua generates extra input params for the outputs

	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cBlockArea") ||
		!L.CheckParamNumber  (2, 4)
	)
	{
		return 0;
	}

	cBlockArea * self = reinterpret_cast<cBlockArea *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetRelBlockTypeMeta'", nullptr);
		return 0;
	}
	int BlockX = static_cast<int>(tolua_tonumber(tolua_S, 2, 0));
	int BlockY = static_cast<int>(tolua_tonumber(tolua_S, 3, 0));
	int BlockZ = static_cast<int>(tolua_tonumber(tolua_S, 4, 0));
	BLOCKTYPE BlockType;
	NIBBLETYPE BlockMeta;
	self->GetRelBlockTypeMeta(BlockX, BlockY, BlockZ, BlockType, BlockMeta);
	tolua_pushnumber(tolua_S, BlockType);
	tolua_pushnumber(tolua_S, BlockMeta);
	return 2;
}





static int tolua_cBlockArea_GetSize(lua_State * tolua_S)
{
	// function cBlockArea::GetSize()
	// Returns all three sizes of the area
	// Exported manually because there's no direct C++ equivalent,
	// plus tolua would generate extra input params for the outputs

	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cBlockArea"))
	{
		return 0;
	}

	cBlockArea * self = reinterpret_cast<cBlockArea *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetSize'", nullptr);
		return 0;
	}

	// Push the three origin coords:
	lua_pushnumber(tolua_S, self->GetSizeX());
	lua_pushnumber(tolua_S, self->GetSizeY());
	lua_pushnumber(tolua_S, self->GetSizeZ());
	return 3;
}





static int tolua_cBlockArea_GetCoordRange(lua_State * tolua_S)
{
	// function cBlockArea::GetCoordRange()
	// Returns all three sizes of the area, miuns one, so that they represent the maximum coord value
	// Exported manually because there's no direct C++ equivalent,
	// plus tolua would generate extra input params for the outputs

	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cBlockArea"))
	{
		return 0;
	}

	cBlockArea * self = reinterpret_cast<cBlockArea *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea:GetSize'", nullptr);
		return 0;
	}

	// Push the three origin coords:
	lua_pushnumber(tolua_S, self->GetSizeX() - 1);
	lua_pushnumber(tolua_S, self->GetSizeY() - 1);
	lua_pushnumber(tolua_S, self->GetSizeZ() - 1);
	return 3;
}





static int tolua_cBlockArea_LoadFromSchematicFile(lua_State * tolua_S)
{
	// function cBlockArea::LoadFromSchematicFile
	// Exported manually because function has been moved to SchematicFileSerializer.cpp
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cBlockArea") ||
		!L.CheckParamString  (2) ||
		!L.CheckParamEnd     (3)
	)
	{
		return 0;
	}
	cBlockArea * self = reinterpret_cast<cBlockArea *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", nullptr);
		return 0;
	}

	AString Filename = tolua_tostring(tolua_S, 2, 0);
	bool res = cSchematicFileSerializer::LoadFromSchematicFile(*self, Filename);
	tolua_pushboolean(tolua_S, res);
	return 1;
}





static int tolua_cBlockArea_LoadFromSchematicString(lua_State * tolua_S)
{
	// function cBlockArea::LoadFromSchematicString
	// Exported manually because function has been moved to SchematicFileSerializer.cpp
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cBlockArea") ||
		!L.CheckParamString  (2) ||
		!L.CheckParamEnd     (3)
	)
	{
		return 0;
	}
	cBlockArea * self = reinterpret_cast<cBlockArea *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::LoadFromSchematicFile'", nullptr);
		return 0;
	}

	AString Data;
	L.GetStackValue(2, Data);
	bool res = cSchematicFileSerializer::LoadFromSchematicString(*self, Data);
	tolua_pushboolean(tolua_S, res);
	return 1;
}





static int tolua_cBlockArea_SaveToSchematicFile(lua_State * tolua_S)
{
	// function cBlockArea::SaveToSchematicFile
	// Exported manually because function has been moved to SchematicFileSerializer.cpp
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cBlockArea") ||
		!L.CheckParamString  (2) ||
		!L.CheckParamEnd     (3)
	)
	{
		return 0;
	}
	cBlockArea * self = reinterpret_cast<cBlockArea *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", nullptr);
		return 0;
	}
	AString Filename = tolua_tostring(tolua_S, 2, 0);
	bool res = cSchematicFileSerializer::SaveToSchematicFile(*self, Filename);
	tolua_pushboolean(tolua_S, res);
	return 1;
}





static int tolua_cBlockArea_SaveToSchematicString(lua_State * tolua_S)
{
	// function cBlockArea::SaveToSchematicString
	// Exported manually because function has been moved to SchematicFileSerializer.cpp
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cBlockArea") ||
		!L.CheckParamEnd     (2)
	)
	{
		return 0;
	}
	cBlockArea * self = reinterpret_cast<cBlockArea *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cBlockArea::SaveToSchematicFile'", nullptr);
		return 0;
	}

	AString Data;
	if (cSchematicFileSerializer::SaveToSchematicString(*self, Data))
	{
		L.Push(Data);
		return 1;
	}
	return 0;
}





static int tolua_cBoundingBox_CalcLineIntersection(lua_State * a_LuaState)
{
	/* Function signatures:
	bbox:CalcLineIntersection(pt1, pt2) -> bool, [number, blockface]
	cBoundingBox:CalcLineIntersection(min, max, pt1, pt2) -> bool, [number, blockface]
	*/
	cLuaState L(a_LuaState);
	const Vector3d * min;
	const Vector3d * max;
	const Vector3d * pt1;
	const Vector3d * pt2;
	double lineCoeff;
	eBlockFace blockFace;
	bool res;
	if (L.GetStackValues(2, min, max, pt1, pt2))  // Try the static signature first
	{
		res = cBoundingBox::CalcLineIntersection(min, max, pt1, pt2, lineCoeff, blockFace);
	}
	else
	{
		const cBoundingBox * bbox;
		if (!L.GetStackValues(1, bbox, pt1, pt2))  // Try the regular signature
		{
			L.LogStackValues();
			tolua_error(a_LuaState, "Invalid function params. Expected either bbox:CalcLineIntersection(pt1, pt2) or cBoundingBox:CalcLineIntersection(min, max, pt1, pt2).", nullptr);
			return 0;
		}
		res = bbox->CalcLineIntersection(pt1, pt2, lineCoeff, blockFace);
	}
	L.Push(res);
	if (res)
	{
		L.Push(lineCoeff);
		L.Push(blockFace);
		return 3;
	}
	return 1;
}





static int tolua_cBoundingBox_Intersect(lua_State * a_LuaState)
{
	/* Function signature:
	bbox:Intersect(a_OtherBbox) -> bool, cBoundingBox
	*/
	cLuaState L(a_LuaState);
	const cBoundingBox * self;
	const cBoundingBox * other;
	if (!L.GetStackValues(1, self, other))
	{
		L.LogStackValues();
		tolua_error(a_LuaState, "Invalid function params. Expected bbox:Intersect(otherBbox).", nullptr);
		return 0;
	}
	auto intersection = new cBoundingBox(*self);
	auto res = self->Intersect(*other, *intersection);
	L.Push(res);
	if (!res)
	{
		delete intersection;
		return 1;
	}
	L.Push(intersection);
	tolua_register_gc(L, lua_gettop(L));  // Make Lua own the "intersection" object
	return 2;
}





static int tolua_cChunkDesc_GetBlockTypeMeta(lua_State * a_LuaState)
{
	/* Function signature:
	ChunkDesc:GetBlockTypeMeta(RelX, RelY, RelZ) -> BlockType, BlockMeta
	*/

	cLuaState L(a_LuaState);
	const cChunkDesc * self;
	int relX, relY, relZ;
	if (!L.GetStackValues(1, self, relX, relY, relZ))
	{
		L.LogStackValues();
		tolua_error(a_LuaState, "Invalid function params. Expected chunkDesc:GetBlockTypeMeta(relX, relY, relZ)", nullptr);
		return 0;
	}
	BLOCKTYPE blockType;
	NIBBLETYPE blockMeta;
	self->GetBlockTypeMeta(relX, relY, relZ, blockType, blockMeta);
	L.Push(blockType);
	L.Push(blockMeta);
	return 2;
}





static int tolua_cCompositeChat_AddRunCommandPart(lua_State * tolua_S)
{
	// function cCompositeChat:AddRunCommandPart(Message, Command, [Style])
	// Exported manually to support call-chaining (return *this)

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cCompositeChat") ||
		!L.CheckParamString(2, 3)
	)
	{
		return 0;
	}
	cCompositeChat * self = reinterpret_cast<cCompositeChat *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddRunCommandPart'", nullptr);
		return 0;
	}

	// Add the part:
	AString Text, Command, Style;
	L.GetStackValue(2, Text);
	L.GetStackValue(3, Command);
	L.GetStackValue(4, Style);
	self->AddRunCommandPart(Text, Command, Style);

	// Cut away everything from the stack except for the cCompositeChat instance; return that:
	lua_settop(L, 1);
	return 1;
}





static int tolua_cCompositeChat_AddSuggestCommandPart(lua_State * tolua_S)
{
	// function cCompositeChat:AddSuggestCommandPart(Message, Command, [Style])
	// Exported manually to support call-chaining (return *this)

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cCompositeChat") ||
		!L.CheckParamString(2, 3)
	)
	{
		return 0;
	}
	cCompositeChat * self = reinterpret_cast<cCompositeChat *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddSuggestCommandPart'", nullptr);
		return 0;
	}

	// Add the part:
	AString Text, Command, Style;
	L.GetStackValue(2, Text);
	L.GetStackValue(3, Command);
	L.GetStackValue(4, Style);
	self->AddSuggestCommandPart(Text, Command, Style);

	// Cut away everything from the stack except for the cCompositeChat instance; return that:
	lua_settop(L, 1);
	return 1;
}





static int tolua_cCompositeChat_AddTextPart(lua_State * tolua_S)
{
	// function cCompositeChat:AddTextPart(Message, [Style])
	// Exported manually to support call-chaining (return *this)

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cCompositeChat") ||
		!L.CheckParamString(2)
	)
	{
		return 0;
	}
	cCompositeChat * self = reinterpret_cast<cCompositeChat *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddTextPart'", nullptr);
		return 0;
	}

	// Add the part:
	AString Text, Style;
	L.GetStackValue(2, Text);
	L.GetStackValue(3, Style);
	self->AddTextPart(Text, Style);

	// Cut away everything from the stack except for the cCompositeChat instance; return that:
	lua_settop(L, 1);
	return 1;
}





static int tolua_cCompositeChat_AddUrlPart(lua_State * tolua_S)
{
	// function cCompositeChat:AddTextPart(Message, Url, [Style])
	// Exported manually to support call-chaining (return *this)

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cCompositeChat") ||
		!L.CheckParamString(2, 3)
	)
	{
		return 0;
	}
	cCompositeChat * self = reinterpret_cast<cCompositeChat *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:AddUrlPart'", nullptr);
		return 0;
	}

	// Add the part:
	AString Text, Url, Style;
	L.GetStackValue(2, Text);
	L.GetStackValue(3, Url);
	L.GetStackValue(4, Style);
	self->AddUrlPart(Text, Url, Style);

	// Cut away everything from the stack except for the cCompositeChat instance; return that:
	lua_settop(L, 1);
	return 1;
}





static int tolua_cCompositeChat_ParseText(lua_State * tolua_S)
{
	// function cCompositeChat:ParseText(TextMessage)
	// Exported manually to support call-chaining (return *this)

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cCompositeChat") ||
		!L.CheckParamString(2)
	)
	{
		return 0;
	}
	cCompositeChat * self = reinterpret_cast<cCompositeChat *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:ParseText'", nullptr);
		return 0;
	}

	// Parse the text:
	AString Text;
	L.GetStackValue(2, Text);
	self->ParseText(Text);

	// Cut away everything from the stack except for the cCompositeChat instance; return that:
	lua_settop(L, 1);
	return 1;
}





static int tolua_cCompositeChat_SetMessageType(lua_State * tolua_S)
{
	// function cCompositeChat:SetMessageType(MessageType)
	// Exported manually to support call-chaining (return *this)

	// Check params:
	cLuaState L(tolua_S);
	if (
		!L.CheckParamUserType(1, "cCompositeChat") ||
		!L.CheckParamNumber(2)
	)
	{
		return 0;
	}
	cCompositeChat * self = reinterpret_cast<cCompositeChat *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:SetMessageType'", nullptr);
		return 0;
	}

	// Set the type:
	int MessageType = mtCustom;
	L.GetStackValue(2, MessageType);
	self->SetMessageType(static_cast<eMessageType>(MessageType));

	// Cut away everything from the stack except for the cCompositeChat instance; return that:
	lua_settop(L, 1);
	return 1;
}





static int tolua_cCompositeChat_UnderlineUrls(lua_State * tolua_S)
{
	// function cCompositeChat:UnderlineUrls()
	// Exported manually to support call-chaining (return *this)

	// Check params:
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cCompositeChat"))
	{
		return 0;
	}
	cCompositeChat * self = reinterpret_cast<cCompositeChat *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		tolua_error(tolua_S, "invalid 'self' in function 'cCompositeChat:UnderlineUrls'", nullptr);
		return 0;
	}

	// Call the processing
	self->UnderlineUrls();

	// Cut away everything from the stack except for the cCompositeChat instance; return that:
	lua_settop(L, 1);
	return 1;
}





static int tolua_cChannelManager_RegisterChannel(lua_State * tolua_S)
{

	// Retrieve the cPlugin from the LuaState:
	cPluginLua * Plugin = cManualBindings::GetLuaPlugin(tolua_S);
	if (Plugin == nullptr)
	{
		// An error message has been already printed in GetLuaPlugin()
		return 0;
	}

	// Check params:
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cChannelManager"))
	{
		return 0;
	}
	cChannelManager * self = reinterpret_cast<cChannelManager *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (self == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cChannelManager:RegisterChannel'");
	}
	if (!L.CheckParamString(2) || !L.CheckParamFunction(3))
	{
		return 0;
	}

	AString Channel;
	L.GetStackValue(2, Channel);
	cLuaState::cCallbackPtr Callback;
	L.GetStackValue(3, Callback);
	auto ChannelCallback = std::make_shared<cChannelCallback>(*Plugin, Callback);

	auto Result = self->RegisterChannel(Channel, ChannelCallback);

	// Cut away everything from the stack and push on the result of RegisterChannel
	lua_settop(L, 2);
	L.Push(Result);
	return 1;
}





static int tolua_cByteBuffer_ReadBEInt8(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEInt8'");
	}

	Int8 Value = 0;
	auto Success = Buffer->ReadBEInt8(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadBEInt16(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEInt16'");
	}

	Int16 Value = 0;
	auto Success = Buffer->ReadBEInt16(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadBEInt32(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEInt32'");
	}

	Int32 Value = 0;
	auto Success = Buffer->ReadBEInt32(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadBEInt64(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEInt64'");
	}

	Int64 Value = 0;
	auto Success = Buffer->ReadBEInt64(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadBEUInt8(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEUInt8'");
	}

	UInt8 Value = 0;
	auto Success = Buffer->ReadBEUInt8(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadBEUInt16(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEUInt16'");
	}

	UInt16 Value = 0;
	auto Success = Buffer->ReadBEUInt16(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadBEUInt32(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEUInt32'");
	}

	UInt32 Value = 0;
	auto Success = Buffer->ReadBEUInt32(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadBEUInt64(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEUInt64'");
	}

	UInt64 Value = 0;
	auto Success = Buffer->ReadBEUInt64(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadBEFloat(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEFloat'");
	}

	float Value = 0.0f;
	auto Success = Buffer->ReadBEFloat(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadBEDouble(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBEDouble'");
	}

	double Value = 0.0;
	auto Success = Buffer->ReadBEDouble(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadBool(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadBool'");
	}

	bool Value = false;
	auto Success = Buffer->ReadBool(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadVarInt32(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadVarInt32'");
	}

	UInt32 Value = 0;
	auto Success = Buffer->ReadVarInt32(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadVarInt64(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadVarInt64'");
	}

	UInt64 Value = 0;
	auto Success = Buffer->ReadVarInt64(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadVarUTF8String(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadVarUTF8String'");
	}

	AString Value;
	auto Success = Buffer->ReadVarUTF8String(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadLEInt(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadLEInt'");
	}

	int Value = 0;
	auto Success = Buffer->ReadLEInt(Value);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadPosition64(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadPosition64'");
	}

	int X = 0;
	int Y = 0;
	int Z = 0;
	auto Success = Buffer->ReadPosition64(X, Y, Z);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(X);
	L.Push(Y);
	L.Push(Z);
	return 4;
}




static int tolua_cByteBuffer_ReadString(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadString'");
	}
	if (!L.CheckParamNumber(2))
	{
		return 0;
	}

	AString Value;
	size_t Count;
	L.GetStackValue(2, Count);
	auto Success = Buffer->ReadString(Value, Count);

	lua_settop(tolua_S, 2);
	L.Push(Success);
	L.Push(Value);
	return 2;
}





static int tolua_cByteBuffer_ReadAll(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadAll'");
	}

	AString Value;
	Buffer->ReadAll(Value);

	lua_settop(tolua_S, 2);
	L.Push(Value);
	return 1;
}





static int tolua_cByteBuffer_ReadAgain(lua_State * tolua_S)
{
	cLuaState L(tolua_S);
	if (!L.CheckParamUserType(1, "cByteBuffer"))
	{
		return 0;
	}

	cByteBuffer * Buffer = reinterpret_cast<cByteBuffer *>(tolua_tousertype(tolua_S, 1, nullptr));
	if (Buffer == nullptr)
	{
		return cManualBindings::lua_do_error(tolua_S, "invalid 'self' in function 'cByteBuffer:ReadAgain'");
	}

	AString Value;
	Buffer->ReadAll(Value);

	lua_settop(tolua_S, 2);
	L.Push(Value);
	return 1;
}





void cManualBindings::Bind(lua_State * tolua_S)
{
	tolua_beginmodule(tolua_S, nullptr);

		// Create the new classes:
		tolua_usertype(tolua_S, "cCryptoHash");
		tolua_usertype(tolua_S, "cLineBlockTracer");
		tolua_usertype(tolua_S, "cStringCompression");
		tolua_usertype(tolua_S, "cUrlParser");
		tolua_cclass(tolua_S, "cCryptoHash",        "cCryptoHash",        "", nullptr);
		tolua_cclass(tolua_S, "cLineBlockTracer",   "cLineBlockTracer",   "", nullptr);
		tolua_cclass(tolua_S, "cStringCompression", "cStringCompression", "", nullptr);
		tolua_cclass(tolua_S, "cUrlParser",         "cUrlParser",         "", nullptr);

		// Globals:
		tolua_function(tolua_S, "Clamp",                 tolua_Clamp);
		tolua_function(tolua_S, "StringSplit",           tolua_StringSplit);
		tolua_function(tolua_S, "StringSplitWithQuotes", tolua_StringSplitWithQuotes);
		tolua_function(tolua_S, "StringSplitAndTrim",    tolua_StringSplitAndTrim);
		tolua_function(tolua_S, "LOG",                   tolua_LOG);
		tolua_function(tolua_S, "LOGINFO",               tolua_LOGINFO);
		tolua_function(tolua_S, "LOGWARN",               tolua_LOGWARN);
		tolua_function(tolua_S, "LOGWARNING",            tolua_LOGWARN);
		tolua_function(tolua_S, "LOGERROR",              tolua_LOGERROR);
		tolua_function(tolua_S, "Base64Encode",          tolua_Base64Encode);
		tolua_function(tolua_S, "Base64Decode",          tolua_Base64Decode);
		tolua_function(tolua_S, "md5",                   tolua_md5_obsolete);  // OBSOLETE, use cCryptoHash.md5() instead

		tolua_beginmodule(tolua_S, "cBlockArea");
			tolua_function(tolua_S, "GetBlockTypeMeta",        tolua_cBlockArea_GetBlockTypeMeta);
			tolua_function(tolua_S, "GetCoordRange",           tolua_cBlockArea_GetCoordRange);
			tolua_function(tolua_S, "GetOrigin",               tolua_cBlockArea_GetOrigin);
			tolua_function(tolua_S, "GetNonAirCropRelCoords",  tolua_cBlockArea_GetNonAirCropRelCoords);
			tolua_function(tolua_S, "GetRelBlockTypeMeta",     tolua_cBlockArea_GetRelBlockTypeMeta);
			tolua_function(tolua_S, "GetSize",                 tolua_cBlockArea_GetSize);
			tolua_function(tolua_S, "LoadFromSchematicFile",   tolua_cBlockArea_LoadFromSchematicFile);
			tolua_function(tolua_S, "LoadFromSchematicString", tolua_cBlockArea_LoadFromSchematicString);
			tolua_function(tolua_S, "SaveToSchematicFile",     tolua_cBlockArea_SaveToSchematicFile);
			tolua_function(tolua_S, "SaveToSchematicString",   tolua_cBlockArea_SaveToSchematicString);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cBoundingBox");
			tolua_function(tolua_S, "CalcLineIntersection", tolua_cBoundingBox_CalcLineIntersection);
			tolua_function(tolua_S, "Intersect",            tolua_cBoundingBox_Intersect);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cChunkDesc");
			tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cChunkDesc_GetBlockTypeMeta);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cClientHandle");
			tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE);
			tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE);
			tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cCompositeChat");
			tolua_function(tolua_S, "AddRunCommandPart",     tolua_cCompositeChat_AddRunCommandPart);
			tolua_function(tolua_S, "AddSuggestCommandPart", tolua_cCompositeChat_AddSuggestCommandPart);
			tolua_function(tolua_S, "AddTextPart",           tolua_cCompositeChat_AddTextPart);
			tolua_function(tolua_S, "AddUrlPart",            tolua_cCompositeChat_AddUrlPart);
			tolua_function(tolua_S, "ParseText",             tolua_cCompositeChat_ParseText);
			tolua_function(tolua_S, "SetMessageType",        tolua_cCompositeChat_SetMessageType);
			tolua_function(tolua_S, "UnderlineUrls",         tolua_cCompositeChat_UnderlineUrls);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cCryptoHash");
			tolua_function(tolua_S, "md5", tolua_md5);
			tolua_function(tolua_S, "md5HexString", tolua_md5HexString);
			tolua_function(tolua_S, "sha1", tolua_sha1);
			tolua_function(tolua_S, "sha1HexString", tolua_sha1HexString);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cEntity");
			tolua_constant(tolua_S, "INVALID_ID", cEntity::INVALID_ID);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cFile");
			tolua_function(tolua_S, "ChangeFileExt",           tolua_cFile_ChangeFileExt);
			tolua_function(tolua_S, "Copy",                    tolua_cFile_Copy);
			tolua_function(tolua_S, "CreateFolder",            tolua_cFile_CreateFolder);
			tolua_function(tolua_S, "CreateFolderRecursive",   tolua_cFile_CreateFolderRecursive);
			tolua_function(tolua_S, "Delete",                  tolua_cFile_Delete);
			tolua_function(tolua_S, "DeleteFile",              tolua_cFile_DeleteFile);
			tolua_function(tolua_S, "DeleteFolder",            tolua_cFile_DeleteFolder);
			tolua_function(tolua_S, "DeleteFolderContents",    tolua_cFile_DeleteFolderContents);
			tolua_function(tolua_S, "Exists",                  tolua_cFile_Exists);
			tolua_function(tolua_S, "GetFolderContents",       tolua_cFile_GetFolderContents);
			tolua_function(tolua_S, "GetLastModificationTime", tolua_cFile_GetLastModificationTime);
			tolua_function(tolua_S, "GetSize",                 tolua_cFile_GetSize);
			tolua_function(tolua_S, "IsFile",                  tolua_cFile_IsFile);
			tolua_function(tolua_S, "IsFolder",                tolua_cFile_IsFolder);
			tolua_function(tolua_S, "ReadWholeFile",           tolua_cFile_ReadWholeFile);
			tolua_function(tolua_S, "Rename",                  tolua_cFile_Rename);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cHopperEntity");
			tolua_function(tolua_S, "GetOutputBlockPos", tolua_cHopperEntity_GetOutputBlockPos);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cItemGrid");
			tolua_function(tolua_S, "GetSlotCoords", Lua_ItemGrid_GetSlotCoords);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cLineBlockTracer");
			tolua_function(tolua_S, "Trace", tolua_cLineBlockTracer_Trace);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cLuaWindow");
			tolua_function(tolua_S, "new",              tolua_cLuaWindow_new);
			tolua_function(tolua_S, "new_local",        tolua_cLuaWindow_new_local);
			tolua_function(tolua_S, ".call",            tolua_cLuaWindow_new_local);
			tolua_function(tolua_S, "SetOnClosing",     tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnClosing>);
			tolua_function(tolua_S, "SetOnSlotChanged", tolua_SetObjectCallback<cLuaWindow, &cLuaWindow::SetOnSlotChanged>);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cMapManager");
			tolua_function(tolua_S, "DoWithMap", DoWithID<cMapManager, cMap, &cMapManager::DoWithMap>);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cMojangAPI");
			tolua_function(tolua_S, "AddPlayerNameToUUIDMapping", tolua_cMojangAPI_AddPlayerNameToUUIDMapping);
			tolua_function(tolua_S, "GetPlayerNameFromUUID",      tolua_cMojangAPI_GetPlayerNameFromUUID);
			tolua_function(tolua_S, "GetUUIDFromPlayerName",      tolua_cMojangAPI_GetUUIDFromPlayerName);
			tolua_function(tolua_S, "GetUUIDsFromPlayerNames",    tolua_cMojangAPI_GetUUIDsFromPlayerNames);
			tolua_function(tolua_S, "MakeUUIDDashed",             tolua_cMojangAPI_MakeUUIDDashed);
			tolua_function(tolua_S, "MakeUUIDShort",              tolua_cMojangAPI_MakeUUIDShort);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cPlayer");
			tolua_function(tolua_S, "GetPermissions",    tolua_cPlayer_GetPermissions);
			tolua_function(tolua_S, "GetRestrictions",   tolua_cPlayer_GetRestrictions);
			tolua_function(tolua_S, "PermissionMatches", tolua_cPlayer_PermissionMatches);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cPlugin");
			tolua_function(tolua_S, "GetDirectory",      tolua_cPlugin_GetDirectory);
			tolua_function(tolua_S, "GetLocalDirectory", tolua_cPlugin_GetLocalDirectory);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cPluginLua");
			tolua_function(tolua_S, "AddWebTab", tolua_cPluginLua_AddWebTab);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cPluginManager");
			tolua_function(tolua_S, "AddHook",               tolua_cPluginManager_AddHook);
			tolua_function(tolua_S, "BindCommand",           tolua_cPluginManager_BindCommand);
			tolua_function(tolua_S, "BindConsoleCommand",    tolua_cPluginManager_BindConsoleCommand);
			tolua_function(tolua_S, "CallPlugin",            tolua_cPluginManager_CallPlugin);
			tolua_function(tolua_S, "DoWithPlugin",          StaticDoWith<cPluginManager, cPlugin, &cPluginManager::DoWithPlugin>);
			tolua_function(tolua_S, "ExecuteConsoleCommand", tolua_cPluginManager_ExecuteConsoleCommand);
			tolua_function(tolua_S, "FindPlugins",           tolua_cPluginManager_FindPlugins);
			tolua_function(tolua_S, "ForEachCommand",        tolua_cPluginManager_ForEachCommand);
			tolua_function(tolua_S, "ForEachConsoleCommand", tolua_cPluginManager_ForEachConsoleCommand);
			tolua_function(tolua_S, "ForEachPlugin",         StaticForEach<cPluginManager, cPlugin, &cPluginManager::ForEachPlugin>);
			tolua_function(tolua_S, "GetAllPlugins",         tolua_cPluginManager_GetAllPlugins);
			tolua_function(tolua_S, "GetCurrentPlugin",      tolua_cPluginManager_GetCurrentPlugin);
			tolua_function(tolua_S, "GetPlugin",             tolua_cPluginManager_GetPlugin);
			tolua_function(tolua_S, "LogStackTrace",         tolua_cPluginManager_LogStackTrace);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cRoot");
			tolua_function(tolua_S, "FindAndDoWithPlayer", DoWith <cRoot, cPlayer, &cRoot::FindAndDoWithPlayer>);
			tolua_function(tolua_S, "DoWithPlayerByUUID",  DoWith <cRoot, cPlayer, &cRoot::DoWithPlayerByUUID>);
			tolua_function(tolua_S, "ForEachPlayer",       ForEach<cRoot, cPlayer, &cRoot::ForEachPlayer>);
			tolua_function(tolua_S, "ForEachWorld",        ForEach<cRoot, cWorld,  &cRoot::ForEachWorld>);
			tolua_function(tolua_S, "GetBrewingRecipe",    tolua_cRoot_GetBrewingRecipe);
			tolua_function(tolua_S, "GetBuildCommitID",    tolua_cRoot_GetBuildCommitID);
			tolua_function(tolua_S, "GetBuildDateTime",    tolua_cRoot_GetBuildDateTime);
			tolua_function(tolua_S, "GetBuildID",          tolua_cRoot_GetBuildID);
			tolua_function(tolua_S, "GetBuildSeriesName",  tolua_cRoot_GetBuildSeriesName);
			tolua_function(tolua_S, "GetFurnaceRecipe",    tolua_cRoot_GetFurnaceRecipe);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cScoreboard");
			tolua_function(tolua_S, "ForEachObjective", ForEach<cScoreboard, cObjective, &cScoreboard::ForEachObjective>);
			tolua_function(tolua_S, "ForEachTeam",      ForEach<cScoreboard, cTeam,      &cScoreboard::ForEachTeam>);
			tolua_function(tolua_S, "GetTeamNames",     tolua_cScoreboard_GetTeamNames);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cStringCompression");
			tolua_function(tolua_S, "CompressStringZLIB",     tolua_CompressStringZLIB);
			tolua_function(tolua_S, "UncompressStringZLIB",   tolua_UncompressStringZLIB);
			tolua_function(tolua_S, "CompressStringGZIP",     tolua_CompressStringGZIP);
			tolua_function(tolua_S, "UncompressStringGZIP",   tolua_UncompressStringGZIP);
			tolua_function(tolua_S, "InflateString",          tolua_InflateString);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cUrlParser");
			tolua_function(tolua_S, "GetDefaultPort",     tolua_cUrlParser_GetDefaultPort);
			tolua_function(tolua_S, "IsKnownScheme",      tolua_cUrlParser_IsKnownScheme);
			tolua_function(tolua_S, "Parse",              tolua_cUrlParser_Parse);
			tolua_function(tolua_S, "ParseAuthorityPart", tolua_cUrlParser_ParseAuthorityPart);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cWebAdmin");
			tolua_function(tolua_S, "AddWebTab",                 tolua_cWebAdmin_AddWebTab);
			tolua_function(tolua_S, "GetAllWebTabs",             tolua_cWebAdmin_GetAllWebTabs);
			tolua_function(tolua_S, "GetBaseURL",                tolua_cWebAdmin_GetBaseURL);
			tolua_function(tolua_S, "GetContentTypeFromFileExt", tolua_cWebAdmin_GetContentTypeFromFileExt);
			tolua_function(tolua_S, "GetHTMLEscapedString",      tolua_cWebAdmin_GetHTMLEscapedString);
			tolua_function(tolua_S, "GetPage",                   tolua_cWebAdmin_GetPage);
			tolua_function(tolua_S, "GetURLEncodedString",       tolua_cWebAdmin_GetURLEncodedString);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "HTTPRequest");
			tolua_variable(tolua_S, "FormData",   tolua_get_HTTPRequest_FormData,   nullptr);
			tolua_variable(tolua_S, "Params",     tolua_get_HTTPRequest_Params,     nullptr);
			tolua_variable(tolua_S, "PostParams", tolua_get_HTTPRequest_PostParams, nullptr);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cChannelManager");
			tolua_function(tolua_S, "RegisterChannel", tolua_cChannelManager_RegisterChannel);
		tolua_endmodule(tolua_S);

		tolua_beginmodule(tolua_S, "cByteBuffer");
			tolua_function(tolua_S, "ReadBEInt8", tolua_cByteBuffer_ReadBEInt8);
			tolua_function(tolua_S, "ReadBEInt16", tolua_cByteBuffer_ReadBEInt16);
			tolua_function(tolua_S, "ReadBEInt32", tolua_cByteBuffer_ReadBEInt32);
			tolua_function(tolua_S, "ReadBEInt64", tolua_cByteBuffer_ReadBEInt64);
			tolua_function(tolua_S, "ReadBEUInt8", tolua_cByteBuffer_ReadBEUInt8);
			tolua_function(tolua_S, "ReadBEUInt16", tolua_cByteBuffer_ReadBEUInt16);
			tolua_function(tolua_S, "ReadBEUInt32", tolua_cByteBuffer_ReadBEUInt32);
			tolua_function(tolua_S, "ReadBEUInt64", tolua_cByteBuffer_ReadBEUInt64);
			tolua_function(tolua_S, "ReadBEFloat", tolua_cByteBuffer_ReadBEFloat);
			tolua_function(tolua_S, "ReadBEDouble", tolua_cByteBuffer_ReadBEDouble);
			tolua_function(tolua_S, "ReadBool", tolua_cByteBuffer_ReadBool);
			tolua_function(tolua_S, "ReadVarInt32", tolua_cByteBuffer_ReadVarInt32);
			tolua_function(tolua_S, "ReadVarInt64", tolua_cByteBuffer_ReadVarInt64);
			tolua_function(tolua_S, "ReadVarUTF8String", tolua_cByteBuffer_ReadVarUTF8String);
			tolua_function(tolua_S, "ReadLEInt", tolua_cByteBuffer_ReadLEInt);
			tolua_function(tolua_S, "ReadPosition64", tolua_cByteBuffer_ReadPosition64);
			tolua_function(tolua_S, "ReadString", tolua_cByteBuffer_ReadString);
			tolua_function(tolua_S, "ReadAll", tolua_cByteBuffer_ReadAll);
			tolua_function(tolua_S, "ReadAgain", tolua_cByteBuffer_ReadAgain);
		tolua_endmodule(tolua_S);

		BindNetwork(tolua_S);
		BindRankManager(tolua_S);
		BindWorld(tolua_S);

	tolua_endmodule(tolua_S);
}