Skip to content

Commit 5241ee7

Browse files
authored
[IMPORTANT] NEW opt-in Introduce VANILLA world shading! (#534)
by @anodic01
1 parent 1af4511 commit 5241ee7

File tree

11 files changed

+76
-19
lines changed

11 files changed

+76
-19
lines changed

renderer/viewer/lib/basePlayerState.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export const getInitialPlayerState = () => proxy({
1818
backgroundColor: [0, 0, 0] as [number, number, number],
1919
ambientLight: 0,
2020
directionalLight: 0,
21+
cardinalLight: 'default',
2122
eyeHeight: 0,
2223
gameMode: undefined as GameMode | undefined,
2324
lookingAtBlock: undefined as {

renderer/viewer/lib/mesher/models.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,16 @@ function renderElement (world: World, cursor: Vec3, element: BlockElement, doAO:
387387
const aos: number[] = []
388388
const neighborPos = position.plus(new Vec3(...dir))
389389
// 10%
390-
const baseLight = world.getLight(neighborPos, undefined, undefined, block.name) / 15
390+
const { smoothLighting, shadingTheme, cardinalLight } = world.config
391+
const faceLight = world.getLight(neighborPos, undefined, undefined, block.name)
392+
const sideShading = (shadingTheme === 'high-contrast') ?
393+
(0.8 + 0.5 * Math.max(0, 0.66 * dir[0] + 0.66 * dir[1] + 0.33 * dir[2])) : //old directional light behavior
394+
(
395+
cardinalLight === 'nether' ?
396+
(0.5 + Math.abs(0.1 * dir[0] + 0.4 * dir[1] + 0.3 * dir[2])) :
397+
(0.75 + 0.25 * dir[1] + 0.05 * (Math.abs(dir[2]) - 3 * Math.abs(dir[0])))
398+
)
399+
const baseLight = sideShading * faceLight / 15
391400
for (const pos of corners) {
392401
let vertex = [
393402
(pos[0] ? maxx : minx),
@@ -414,7 +423,7 @@ function renderElement (world: World, cursor: Vec3, element: BlockElement, doAO:
414423
}
415424

416425
let light = 1
417-
const { smoothLighting } = world.config
426+
418427
// const smoothLighting = true
419428
if (doAO) {
420429
const dx = pos[0] * 2 - 1
@@ -427,7 +436,7 @@ function renderElement (world: World, cursor: Vec3, element: BlockElement, doAO:
427436
const side2 = world.getBlock(cursor.offset(...side2Dir))
428437
const corner = world.getBlock(cursor.offset(...cornerDir))
429438

430-
let cornerLightResult = baseLight * 15
439+
let cornerLightResult = faceLight
431440

432441
if (smoothLighting) {
433442
const dirVec = new Vec3(...dir)
@@ -444,7 +453,7 @@ function renderElement (world: World, cursor: Vec3, element: BlockElement, doAO:
444453
const cornerLightDir = getVec(new Vec3(...cornerDir))
445454
const cornerLight = world.getLight(cursor.plus(cornerLightDir))
446455
// interpolate
447-
const lights = [side1Light, side2Light, cornerLight, baseLight * 15]
456+
const lights = [side1Light, side2Light, cornerLight, faceLight]
448457
cornerLightResult = lights.reduce((acc, cur) => acc + cur, 0) / lights.length
449458
}
450459

@@ -455,8 +464,11 @@ function renderElement (world: World, cursor: Vec3, element: BlockElement, doAO:
455464
// TODO: correctly interpolate ao light based on pos (evaluate once for each corner of the block)
456465

457466
const ao = (side1Block && side2Block) ? 0 : (3 - (side1Block + side2Block + cornerBlock))
467+
const ao_bias = (shadingTheme === 'high-contrast') ? 0.25 : 0.4
468+
const ao_scale = (shadingTheme === 'high-contrast') ? 0.25 : 0.2
469+
458470
// todo light should go upper on lower blocks
459-
light = (ao + 1) / 4 * (cornerLightResult / 15)
471+
light = sideShading * (ao * ao_scale + ao_bias) * (cornerLightResult / 15)
460472
aos.push(ao)
461473
}
462474

renderer/viewer/lib/mesher/shared.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ export const defaultMesherConfig = {
88
enableLighting: true,
99
skyLight: 15,
1010
smoothLighting: true,
11+
shadingTheme: 'high-contrast',
12+
cardinalLight: 'default',
1113
outputFormat: 'threeJs' as 'threeJs' | 'webgpu',
1214
// textureSize: 1024, // for testing
1315
debugModelVariant: undefined as undefined | number[],

renderer/viewer/lib/worldrendererCommon.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ export const defaultWorldRendererConfig = {
4747
// Rendering engine settings
4848
dayCycle: true,
4949
smoothLighting: true,
50+
shadingTheme: 'high-contrast',
51+
cardinalLight: 'default',
5052
enableLighting: true,
5153
starfield: true,
5254
defaultSkybox: true,
@@ -171,6 +173,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
171173
soundSystem: SoundSystem | undefined
172174

173175
abstract changeBackgroundColor (color: [number, number, number]): void
176+
abstract changeCardinalLight (string): void
174177

175178
worldRendererConfig: WorldRendererConfig
176179
playerStateReactive: PlayerStateReactive
@@ -344,6 +347,9 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
344347
this.onReactivePlayerStateUpdated('backgroundColor', (value) => {
345348
this.changeBackgroundColor(value)
346349
})
350+
this.onReactivePlayerStateUpdated('cardinalLight', (value) => {
351+
this.changeCardinalLight(value)
352+
})
347353
}
348354

349355
watchReactiveConfig () {
@@ -572,6 +578,8 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
572578
enableLighting: this.worldRendererConfig.enableLighting,
573579
skyLight,
574580
smoothLighting: this.worldRendererConfig.smoothLighting,
581+
shadingTheme: this.worldRendererConfig.shadingTheme,
582+
cardinalLight: this.worldRendererConfig.cardinalLight,
575583
outputFormat: this.outputFormat,
576584
// textureSize: this.resourcesManager.currentResources!.blocksAtlasParser.atlas.latest.width,
577585
debugModelVariant: this.worldRendererConfig.debugModelVariant,

renderer/viewer/three/worldrendererThree.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export class WorldRendererThree extends WorldRendererCommon {
4646
directionalLight = new THREE.DirectionalLight(0xff_ff_ff, 0.5)
4747
entities = new Entities(this)
4848
cameraGroupVr?: THREE.Object3D
49-
material = new THREE.MeshLambertMaterial({ vertexColors: true, transparent: true, alphaTest: 0.1 })
49+
material = new THREE.MeshBasicMaterial({ vertexColors: true, transparent: true, alphaTest: 0.1 })
5050
itemsTexture: THREE.Texture
5151
cursorBlock: CursorBlock
5252
onRender: Array<() => void> = []
@@ -272,6 +272,9 @@ export class WorldRendererThree extends WorldRendererCommon {
272272
changeBackgroundColor (color: [number, number, number]): void {
273273
this.scene.background = new THREE.Color(color[0], color[1], color[2])
274274
}
275+
changeCardinalLight (cardinalLight: string): void {
276+
this.worldRendererConfig.cardinalLight = cardinalLight
277+
}
275278

276279
timeUpdated (newTime: number): void {
277280
const nightTime = 13_500

src/controls.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export const contro = new ControMax({
7878
zoom: ['KeyC'],
7979
viewerConsole: ['Backquote'],
8080
togglePerspective: ['F5', 'Up'],
81+
takeScreenshot: ['F2'],
8182
},
8283
ui: {
8384
toggleFullscreen: ['F11'],
@@ -146,6 +147,22 @@ const isSpectatingEntity = () => {
146147
return appViewer.playerState.utils.isSpectatingEntity()
147148
}
148149

150+
let lastScreenshotAt = 0
151+
const screenshotRepeatCooldownMs = 500
152+
153+
export const takeScreenshotAction = () => {
154+
const now = Date.now()
155+
if (now - lastScreenshotAt < screenshotRepeatCooldownMs) return
156+
lastScreenshotAt = now
157+
const canvas = document.getElementById('viewer-canvas') as HTMLCanvasElement | null
158+
if (!canvas) return
159+
const link = document.createElement('a')
160+
link.href = canvas.toDataURL('image/png')
161+
const date = new Date()
162+
link.download = `screenshot ${date.toLocaleString().replaceAll('.', '-').replace(',', '')}.png`
163+
link.click()
164+
}
165+
149166
contro.on('movementUpdate', ({ vector, soleVector, gamepadIndex }) => {
150167
miscUiState.usingGamepadInput = gamepadIndex !== undefined
151168
if (!bot || !isGameActive(false) || isSpectatingEntity()) return
@@ -489,6 +506,13 @@ const isCommandAvailableAfterDisconnect = (command: Command) => {
489506
contro.on('trigger', ({ command }) => {
490507
if (isCommandDisabled(command)) return
491508

509+
if (command === 'general.takeScreenshot') {
510+
if (isGameActive(true)) {
511+
takeScreenshotAction()
512+
}
513+
return
514+
}
515+
492516
const willContinue = !isGameActive(true)
493517
alwaysPressedHandledCommand(command)
494518
if (willContinue && !isCommandAvailableAfterDisconnect(command)) return
@@ -869,18 +893,6 @@ window.addEventListener('keydown', (e) => {
869893
}
870894
})
871895

872-
window.addEventListener('keydown', (e) => {
873-
if (e.code !== 'F2' || e.repeat || !isGameActive(true)) return
874-
e.preventDefault()
875-
const canvas = document.getElementById('viewer-canvas') as HTMLCanvasElement
876-
if (!canvas) return
877-
const link = document.createElement('a')
878-
link.href = canvas.toDataURL('image/png')
879-
const date = new Date()
880-
link.download = `screenshot ${date.toLocaleString().replaceAll('.', '-').replace(',', '')}.png`
881-
link.click()
882-
})
883-
884896
window.addEventListener('keydown', (e) => {
885897
if (e.code !== 'F1' || e.repeat || !isGameActive(true)) return
886898
e.preventDefault()

src/defaultOptions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export const defaultOptions = {
100100
showCursorBlockInSpectator: false,
101101
renderEntities: true,
102102
smoothLighting: true,
103+
vanillaLook: false,
103104
newVersionsLighting: false,
104105
chatSelect: true,
105106
autoJump: 'auto' as 'auto' | 'always' | 'never',

src/mineflayer/playerState.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ export class PlayerStateControllerMain {
5353
hasSkyLight = data.dimension.value.has_skylight.value
5454
} catch {}
5555
this.reactive.lightingDisabled = bot.game.dimension === 'the_nether' || bot.game.dimension === 'the_end' || !hasSkyLight
56+
let cardinalLight = 'default'
57+
try {
58+
cardinalLight = data.dimension.value.effects.value === 'minecraft:the_nether' ? 'nether' : 'default'
59+
} catch {}
60+
try {
61+
cardinalLight = data.dimension.value.cardinal_light.value //servers after 1.21.11, untested
62+
} catch {}
63+
this.reactive.cardinalLight = cardinalLight
5664
}
5765

5866
bot._client.on('login', (packet) => {

src/optionsGuiScheme.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ export const guiOptionsScheme: {
6868
activeRenderer: {
6969
text: 'Renderer',
7070
},
71+
vanillaLook: {
72+
tooltip: 'On: Minecraft-style face shading. Off: client’s higher-contrast shading (default).',
73+
},
7174
},
7275
{
7376
custom () {

src/react/OptionsItems.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,11 @@ export const OptionButton = ({ item, onClick, valueText, cacheKey }: {
156156
: (currentIndex + 1) % possibleValues.length
157157
options[item.id] = getOptionValue(possibleValues[nextIndex])
158158
}
159+
} else if (possibleValues && possibleValues.length === 1) {
160+
// Only one choice: keep it (do not use boolean ! which breaks string/enum values)
161+
options[item.id] = getOptionValue(possibleValues[0])
159162
} else {
160-
// Boolean toggle or single value
163+
// Boolean toggle
161164
options[item.id] = !options[item.id]
162165
}
163166
}

0 commit comments

Comments
 (0)