diff --git a/src/Event.c b/src/Event.c index 91cca9c68..66e04a4bc 100644 --- a/src/Event.c +++ b/src/Event.c @@ -82,6 +82,7 @@ void Event_UnregisterAll(void) { WorldEvents.Loading.Count = 0; WorldEvents.MapLoaded.Count = 0; WorldEvents.EnvVarChanged.Count = 0; + WorldEvents.LightingModeChanged.Count = 0; ChatEvents.FontChanged.Count = 0; ChatEvents.ChatReceived.Count = 0; diff --git a/src/Event.h b/src/Event.h index 398a6dfee..002b9ac84 100644 --- a/src/Event.h +++ b/src/Event.h @@ -162,10 +162,11 @@ CC_VAR extern struct _BlockEventsList { } BlockEvents; CC_VAR extern struct _WorldEventsList { - struct Event_Void NewMap; /* Player begins loading a new world */ - struct Event_Float Loading; /* Portion of world is decompressed/generated (Arg is progress from 0-1) */ - struct Event_Void MapLoaded; /* New world has finished loading, player can now interact with it */ - struct Event_Int EnvVarChanged; /* World environment variable changed by player/CPE/WoM config */ + struct Event_Void NewMap; /* Player begins loading a new world */ + struct Event_Float Loading; /* Portion of world is decompressed/generated (Arg is progress from 0-1) */ + struct Event_Void MapLoaded; /* New world has finished loading, player can now interact with it */ + struct Event_Int EnvVarChanged; /* World environment variable changed by player/CPE/WoM config */ + struct Event_Int LightingModeChanged; /* Lighting mode changed. 0 or 1 indicates whether client or server is the cause of the change */ } WorldEvents; CC_VAR extern struct _ChatEventsList { diff --git a/src/Lighting.c b/src/Lighting.c index 2e5a6fb13..690bd9d72 100644 --- a/src/Lighting.c +++ b/src/Lighting.c @@ -11,10 +11,14 @@ #include "Chat.h" #include "ExtMath.h" #include "Options.h" +#include "Builder.h" const char* const LightingMode_Names[LIGHTING_MODE_COUNT] = { "Classic", "Fancy" }; cc_uint8 Lighting_Mode; +cc_bool Lighting_ModeLockedByServer; +cc_bool Lighting_ModeSetByServer; +cc_uint8 Lighting_ModeCached; struct _Lighting Lighting; #define Lighting_Pack(x, z) ((x) + World.Width * (z)) @@ -414,7 +418,7 @@ static void ClassicLighting_SetActive(void) { /*########################################################################################################################* *---------------------------------------------------Lighting component----------------------------------------------------* *#########################################################################################################################*/ -void Lighting_ApplyActive(void) { +static void Lighting_ApplyActive(void) { if (Lighting_Mode != LIGHTING_MODE_CLASSIC) { FancyLighting_SetActive(); } else { @@ -422,18 +426,33 @@ void Lighting_ApplyActive(void) { } } -void Lighting_SwitchActive(void) { +static void Lighting_SwitchActive(void) { Lighting.FreeState(); Lighting_ApplyActive(); Lighting.AllocState(); } +static void Lighting_HandleModeChanged(void* obj, int locked) { + Builder_ApplyActive(); + if (World.Loaded) { + Lighting_SwitchActive(); + MapRenderer_Refresh(); + } else { + Lighting_ApplyActive(); + } +} + static void OnInit(void) { Lighting_Mode = Options_GetEnum(OPT_LIGHTING_MODE, LIGHTING_MODE_CLASSIC, LightingMode_Names, LIGHTING_MODE_COUNT); + Lighting_ModeLockedByServer = false; + Lighting_ModeSetByServer = false; + Lighting_ModeCached = Lighting_Mode; FancyLighting_OnInit(); Lighting_ApplyActive(); + + Event_Register_(&WorldEvents.LightingModeChanged, NULL, Lighting_HandleModeChanged); } static void OnReset(void) { Lighting.FreeState(); } static void OnNewMapLoaded(void) { Lighting.AllocState(); } diff --git a/src/Lighting.h b/src/Lighting.h index 73691a1af..999264b17 100644 --- a/src/Lighting.h +++ b/src/Lighting.h @@ -17,6 +17,12 @@ enum LightingMode { extern const char* const LightingMode_Names[LIGHTING_MODE_COUNT]; extern cc_uint8 Lighting_Mode; +extern cc_bool Lighting_ModeLockedByServer; +/* True if the current lighting mode has been set by the server instead of the client */ +extern cc_bool Lighting_ModeSetByServer; +/* The lighting mode that was set by the client before being set by the server */ +extern cc_uint8 Lighting_ModeCached; + /* How much ambient occlusion to apply in fancy lighting where 1.0f = none and 0.0f = maximum*/ #define FANCY_AO 0.5F @@ -65,8 +71,6 @@ CC_VAR extern struct _Lighting { PackedCol (*Color_ZSide_Fast)(int x, int y, int z); } Lighting; -void Lighting_SwitchActive(void); -void Lighting_ApplyActive(void); void FancyLighting_SetActive(void); void FancyLighting_OnInit(void); diff --git a/src/Menus.c b/src/Menus.c index 517391e7a..4d1c2d9fd 100644 --- a/src/Menus.c +++ b/src/Menus.c @@ -562,7 +562,7 @@ static void PauseScreen_Init(void* screen) { if (Server.IsSinglePlayer) return; s->btns[3].flags = WIDGET_FLAG_DISABLED; - s->btns[5].flags = WIDGET_FLAG_DISABLED; + s->btns[4].flags = WIDGET_FLAG_DISABLED; } static void PauseScreen_Free(void* screen) { @@ -2389,7 +2389,7 @@ static struct MenuOptionsScreen { Screen_Body const char* descriptions[MENUOPTS_MAX_OPTS + 1]; struct ButtonWidget* activeBtn; - InitMenuOptions DoInit, DoRecreateExtra, OnHacksChanged; + InitMenuOptions DoInit, DoRecreateExtra, OnHacksChanged, OnLightingModeServerChanged; int numButtons; struct FontDesc titleFont, textFont; struct TextGroupWidget extHelp; @@ -2584,6 +2584,14 @@ static void MenuOptionsScreen_OnHacksChanged(void* screen) { if (s->OnHacksChanged) s->OnHacksChanged(s); s->dirty = true; } +static void MenuOptionsScreen_OnLightingModeServerChanged(void* screen, int fromServer) { + struct MenuOptionsScreen* s = (struct MenuOptionsScreen*)screen; + /* This event only actually matters if it's from the server */ + if (fromServer) { + if (s->OnLightingModeServerChanged) s->OnLightingModeServerChanged(s); + s->dirty = true; + } +} static void MenuOptionsScreen_Init(void* screen) { struct MenuOptionsScreen* s = (struct MenuOptionsScreen*)screen; @@ -2606,6 +2614,7 @@ static void MenuOptionsScreen_Init(void* screen) { TextGroupWidget_Create(&s->extHelp, 5, s->extHelpTextures, MenuOptionsScreen_GetDesc); s->extHelp.lines = 0; Event_Register_(&UserEvents.HackPermsChanged, screen, MenuOptionsScreen_OnHacksChanged); + Event_Register_(&WorldEvents.LightingModeChanged, screen, MenuOptionsScreen_OnLightingModeServerChanged); s->maxVertices = Screen_CalcDefaultMaxVertices(s); } @@ -2629,6 +2638,7 @@ static void MenuOptionsScreen_Render(void* screen, float delta) { static void MenuOptionsScreen_Free(void* screen) { struct MenuOptionsScreen* s = (struct MenuOptionsScreen*)screen; Event_Unregister_(&UserEvents.HackPermsChanged, screen, MenuOptionsScreen_OnHacksChanged); + Event_Unregister_(&WorldEvents.LightingModeChanged, screen, MenuOptionsScreen_OnLightingModeServerChanged); Gui_RemoveCore((struct Screen*)&MenuInputOverlay); } @@ -2868,13 +2878,22 @@ void EnvSettingsScreen_Show(void) { /*########################################################################################################################* *--------------------------------------------------GraphicsOptionsScreen--------------------------------------------------* *#########################################################################################################################*/ +static void GraphicsOptionsScreen_CheckLightingModeAllowed(struct MenuOptionsScreen* s) { + struct Widget** widgets = s->widgets; + cc_bool disabled = Lighting_ModeLockedByServer; + struct ButtonWidget* btn = (struct ButtonWidget*)widgets[4]; + + MenuOptionsScreen_Update(s, btn); + Widget_SetDisabled(widgets[4], disabled); + MenuInputOverlay_CheckStillValid(s); +} + static void GraphicsOptionsScreen_GetViewDist(cc_string* v) { String_AppendInt(v, Game_ViewDistance); } static void GraphicsOptionsScreen_SetViewDist(const cc_string* v) { Game_UserSetViewDistance(Menu_Int(v)); } static void GraphicsOptionsScreen_GetSmooth(cc_string* v) { Menu_GetBool(v, Builder_SmoothLighting); } static void GraphicsOptionsScreen_SetSmooth(const cc_string* v) { Builder_SmoothLighting = Menu_SetBool(v, OPT_SMOOTH_LIGHTING); - Lighting_ApplyActive(); Builder_ApplyActive(); MapRenderer_Refresh(); } @@ -2882,10 +2901,9 @@ static void GraphicsOptionsScreen_GetLighting(cc_string* v) { String_AppendConst static void GraphicsOptionsScreen_SetLighting(const cc_string* v) { Lighting_Mode = Utils_ParseEnum(v, 0, LightingMode_Names, LIGHTING_MODE_COUNT); Options_Set(OPT_LIGHTING_MODE, v); - - Lighting_SwitchActive(); - Builder_ApplyActive(); - MapRenderer_Refresh(); + Lighting_ModeSetByServer = false; + /* Call with 0 to indicate clientside menu change */ + Event_RaiseInt(&WorldEvents.LightingModeChanged, 0); } static void GraphicsOptionsScreen_GetCamera(cc_string* v) { Menu_GetBool(v, Camera.Smooth); } @@ -2943,7 +2961,11 @@ static void GraphicsOptionsScreen_InitWidgets(struct MenuOptionsScreen* s) { { 1, 50, "Anaglyph 3D", MenuOptionsScreen_Bool, ClassicOptionsScreen_GetAnaglyph, ClassicOptionsScreen_SetAnaglyph } }; + + s->OnLightingModeServerChanged = GraphicsOptionsScreen_CheckLightingModeAllowed; + MenuOptionsScreen_AddButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); + GraphicsOptionsScreen_CheckLightingModeAllowed(s); s->descriptions[0] = "&eChange the smoothness of the smooth camera."; s->descriptions[1] = \ @@ -2955,9 +2977,11 @@ static void GraphicsOptionsScreen_InitWidgets(struct MenuOptionsScreen* s) { "&eSmooth lighting smooths lighting and adds a minor glow to bright blocks.\n" \ "&cNote: &eThis setting may reduce performance."; s->descriptions[4] = \ - "&eClassic: &fTwo levels of light, sun and shadow. Good for performance.\n" \ - "&eFancy: &fAllows bright blocks to cast a much wider range of light.\n" \ - "&cNote: &eFancy will reduce performance and increase memory usage."; + "&eClassic: &fTwo levels of light, sun and shadow.\n" \ + " Good for performance.\n" \ + "&eFancy: &fBright blocks cast a much wider range of light\n" \ + " May heavily reduce performance.\n" \ + "&cNote: &eIn multiplayer, this option may be changed or locked by the server."; s->descriptions[6] = \ "&eNone: &fNo names of players are drawn.\n" \ "&eHovered: &fName of the targeted player is drawn see-through.\n" \ diff --git a/src/Protocol.c b/src/Protocol.c index ea170e39a..917b0ddde 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -88,6 +88,7 @@ static struct CpeExt customModels_Ext = { "CustomModels", 2 }, pluginMessages_Ext = { "PluginMessages", 1 }, extTeleport_Ext = { "ExtEntityTeleport", 1 }, + lightingMode_Ext = { "LightingMode", 1 }, extTextures_Ext = { "ExtendedTextures", 1 }, extBlocks_Ext = { "ExtendedBlocks", 1 }; @@ -97,7 +98,7 @@ static struct CpeExt* cpe_clientExtensions[] = { &messageTypes_Ext, &hackControl_Ext, &playerClick_Ext, &fullCP437_Ext, &longerMessages_Ext, &blockDefs_Ext, &blockDefsExt_Ext, &bulkBlockUpdate_Ext, &textColors_Ext, &envMapAspect_Ext, &entityProperty_Ext, &extEntityPos_Ext, &twoWayPing_Ext, &invOrder_Ext, &instantMOTD_Ext, &fastMap_Ext, &setHotbar_Ext, &setSpawnpoint_Ext, &velControl_Ext, - &customParticles_Ext, &pluginMessages_Ext, &extTeleport_Ext, + &customParticles_Ext, &pluginMessages_Ext, &extTeleport_Ext, &lightingMode_Ext, #ifdef CUSTOM_MODELS &customModels_Ext, #endif @@ -1530,6 +1531,35 @@ static void CPE_ExtEntityTeleport(cc_uint8* data) { Classic_ReadAbsoluteLocation(data, id, flags); } +static void CPE_LightingMode(cc_uint8* data) { + cc_uint8 mode = *data++; + cc_uint8 lockedByte = *data++; + cc_bool locked = lockedByte > 0 ? true : false; + + if (mode == 0) { + if (!Lighting_ModeSetByServer) return; + /* locked is ignored with mode 0 and always set to false */ + Lighting_ModeLockedByServer = false; + Lighting_ModeSetByServer = false; + Lighting_Mode = Lighting_ModeCached; + /* Call event even if mode is unchanged in case menu needs to be enabled/disabled */ + /* 1 indicates changed by server and thus menu needs to update */ + Event_RaiseInt(&WorldEvents.LightingModeChanged, 1); + return; + } + /* Convert from Network mode (0 = no change, 1 = classic, 2 = fancy) to client mode (0 = classic, 1 = fancy) */ + mode--; + if (mode >= LIGHTING_MODE_COUNT) return; + + if (!Lighting_ModeSetByServer) Lighting_ModeCached = Lighting_Mode; + Lighting_ModeLockedByServer = locked; + Lighting_ModeSetByServer = true; + Lighting_Mode = mode; + /* Call event even if mode is unchanged in case menu needs to be enabled/disabled */ + /* 1 indicates changed by server and thus menu needs to update */ + Event_RaiseInt(&WorldEvents.LightingModeChanged, 1); +} + static void CPE_Reset(void) { cpe_serverExtensionsCount = 0; cpe_pingTicks = 0; CPEExtensions_Reset(); @@ -1572,6 +1602,7 @@ static void CPE_Reset(void) { Net_Set(OPCODE_SPAWN_EFFECT, CPE_SpawnEffect, 26); Net_Set(OPCODE_PLUGIN_MESSAGE, CPE_PluginMessage, 66); Net_Set(OPCODE_ENTITY_TELEPORT_EXT, CPE_ExtEntityTeleport, 11); + Net_Set(OPCODE_LIGHTING_MODE, CPE_LightingMode, 3); } static cc_uint8* CPE_Tick(cc_uint8* data) { diff --git a/src/Protocol.h b/src/Protocol.h index a27fe8005..4141fb60e 100644 --- a/src/Protocol.h +++ b/src/Protocol.h @@ -37,6 +37,7 @@ enum OPCODE_ { OPCODE_DEFINE_EFFECT, OPCODE_SPAWN_EFFECT, OPCODE_DEFINE_MODEL, OPCODE_DEFINE_MODEL_PART, OPCODE_UNDEFINE_MODEL, OPCODE_PLUGIN_MESSAGE, OPCODE_ENTITY_TELEPORT_EXT, + OPCODE_LIGHTING_MODE, OPCODE_COUNT };