update hires description

update hires description

--
-- Copyright (C) 2017-2020 DBotThePony

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do so,
-- subject to the following conditions:

-- The above copyright notice and this permission notice shall be included in all copies
-- or substantial portions of the Software.

-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-- PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
-- FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-- DEALINGS IN THE SOFTWARE.

PPM2.USE_HIGHRES_TEXTURES = CreateConVar('ppm2_cl_hires', '0', {FCVAR_ARCHIVE}, 'Double the texture resolution. Can take ages at texture encoding if CPU is slow, and require a lot of RAM for encoding and a lot of VRAM for textures!')
PPM2.FORCE_PRECACHE = CreateConVar('ppm2_cl_force_precache', '0', {FCVAR_ARCHIVE}, 'Force precache render textures instead of loading them when needed')

_Material = Material

Material = (path) ->
	return path if not PPM2.FORCE_PRECACHE\GetBool()
	matNew = _Material(path)
	return matNew

module = {
	BODY_DETAILS: {
		Material('models/ppm2/partrender/body_leggrad1.png')
		Material('models/ppm2/partrender/body_lines1.png')
		Material('models/ppm2/partrender/body_stripes1.png')
		Material('models/ppm2/partrender/body_headstripes1.png')
		Material('models/ppm2/partrender/body_freckles.png')
		Material('models/ppm2/partrender/body_hooves1.png')
		Material('models/ppm2/partrender/body_hooves2.png')
		Material('models/ppm2/partrender/body_headmask1.png')
		Material('models/ppm2/partrender/body_hooves1_crit.png')
		Material('models/ppm2/partrender/body_hooves2_crit.png')
		Material('models/ppm2/partrender/body_spots1.png')
		Material('models/ppm2/partrender/body_robotic.png')
		Material('models/ppm2/partrender/dash-e.png')
		Material('models/ppm2/partrender/eye_scar.png')
		Material('models/ppm2/partrender/eye_wound.png')
		Material('models/ppm2/partrender/body_scar.png')
		Material('models/ppm2/partrender/gear_socks.png')
		Material('models/ppm2/partrender/sharp_hooves.png')
		Material('models/ppm2/partrender/sharp_hooves2.png')
		Material('models/ppm2/partrender/separated_muzzle.png')
		Material('models/ppm2/partrender/eye_scar_left.png')
		Material('models/ppm2/partrender/eye_scar_right.png')
		Material('models/ppm2/partrender/android_albedo.png')
		Material('models/ppm2/partrender/android_paint.png')
		Material('models/ppm2/partrender/android_albedo_strip.png')
		Material('models/ppm2/partrender/android_paint_strip.png')
		Material('models/ppm2/partrender/cow_paint.png')
		Material('models/ppm2/partrender/deer_paint.png')
		Material('models/ppm2/partrender/deer_extended_paint.png')
		Material('models/ppm2/partrender/demonic_paint.png')
		Material('models/ppm2/partrender/ear_inner_paint.png')
		Material('models/ppm2/partrender/zebra_detail_paint.png')
	}

	UPPER_MANE_DETAILS: {
		[4]: {Material('models/ppm2/partrender/upmane_5_mask0.png')}
		[5]: {Material('models/ppm2/partrender/upmane_6_mask0.png')}
		[7]: {Material('models/ppm2/partrender/upmane_8_mask0.png'), Material('models/ppm2/partrender/upmane_8_mask1.png')}
		[8]: {Material('models/ppm2/partrender/upmane_9_mask0.png'), Material('models/ppm2/partrender/upmane_9_mask1.png'), Material('models/ppm2/partrender/upmane_9_mask2.png')}
		[9]: {Material('models/ppm2/partrender/upmane_10_mask0.png')}
		[10]: {Material('models/ppm2/partrender/upmane_11_mask0.png'), Material('models/ppm2/partrender/upmane_11_mask1.png'), Material('models/ppm2/partrender/upmane_11_mask2.png')}
		[11]: {Material('models/ppm2/partrender/upmane_12_mask0.png')}
		[12]: {Material('models/ppm2/partrender/upmane_13_mask0.png')}
		[13]: {Material('models/ppm2/partrender/upmane_14_mask0.png')}
		[14]: {Material('models/ppm2/partrender/upmane_15_mask0.png')}
	}

	LOWER_MANE_DETAILS: {
		[4]: {Material('models/ppm2/partrender/dnmane_5_mask0.png')}
		[7]: {Material('models/ppm2/partrender/dnmane_8_mask0.png'), Material('models/ppm2/partrender/dnmane_8_mask1.png')}
		[8]: {Material('models/ppm2/partrender/dnmane_9_mask0.png'), Material('models/ppm2/partrender/dnmane_9_mask1.png')}
		[9]: {Material('models/ppm2/partrender/dnmane_10_mask0.png'), Material('models/ppm2/partrender/dnmane_10_mask1.png'), Material('models/ppm2/partrender/dnmane_10_mask2.png')}
		[10]: {Material('models/ppm2/partrender/dnmane_11_mask0.png'), Material('models/ppm2/partrender/dnmane_11_mask1.png')}
		[11]: {Material('models/ppm2/partrender/dnmane_12_mask0.png')}
	}

	TAIL_DETAILS: {
		[4]: {Material('models/ppm2/partrender/tail_5_mask0.png')}
		[7]: {Material('models/ppm2/partrender/tail_8_mask0.png'), Material('models/ppm2/partrender/tail_8_mask1.png'), Material('models/ppm2/partrender/tail_8_mask2.png'), Material('models/ppm2/partrender/tail_8_mask3.png'), Material('models/ppm2/partrender/tail_8_mask4.png')}
		[9]: {Material('models/ppm2/partrender/tail_10_mask0.png')}
		[10]: {Material('models/ppm2/partrender/tail_11_mask0.png'), Material('models/ppm2/partrender/tail_11_mask1.png'), Material('models/ppm2/partrender/tail_11_mask2.png')}
		[11]: {Material('models/ppm2/partrender/tail_12_mask0.png'), Material('models/ppm2/partrender/tail_12_mask1.png')}
		[12]: {Material('models/ppm2/partrender/tail_13_mask0.png')}
		[13]: {Material('models/ppm2/partrender/tail_14_mask0.png')}
	}

	SOCKS_PATCHS: {
		'models/props_pony/ppm/ppm_socks/socks_striped_unlit'
		'models/props_pony/ppm2/ppm_socks/custom/geometric1_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric2_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric3_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric4_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric5_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric6_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric7_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric8_1.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/dark1.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers10.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers11.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers12.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers13.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers14.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers15.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers16.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers17.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers18.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers19.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers2.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers20.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers3.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers4.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers5.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers6.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers7.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers8.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers9.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/grey1.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/grey2.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/grey3.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/hearts1.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/hearts2.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/snow1.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/wallpaper1.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/wallpaper2.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/wallpaper3.png'
	}

	SOCKS_DETAILS_PATCHS: {
		[2]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric1_4.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric1_5.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric1_6.png'
		}

		[3]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric2_3.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric2_4.png'
		}

		[4]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric3_2.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric3_3.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric3_5.png'
		}

		[5]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric4_2.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric4_3.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric4_4.png'
		}

		[6]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric5_4.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric5_5.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric5_6.png'
		}

		[7]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric6_2.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric6_3.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric6_4.png'
		}

		[8]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric7_3.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric7_4.png'
		}

		[9]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric8_2.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric8_3.png'
		}
	}
}

additionTable = (...) ->
	tab = {'$ignorez': 1, '$vertexcolor': 1, '$vertexalpha': 1, '$nolod': 1}
	args = {...}
	for i = 1, #args, 2
		key, val = args[i], args[i + 1]
		tab[key] = val
	return tab

module.SOCKS_MATERIALS = [Material(id) for _, id in ipairs module.SOCKS_PATCHS]
module.SOCKS_DETAILS = {i, [Material(path) for path in *data] for i, data in pairs module.SOCKS_DETAILS_PATCHS}
module.CUTIEMARKS = [Material("models/ppm2/cmarks/#{mark}.png") for _, mark in ipairs PPM2.DefaultCutiemarks]
module.SUITS = [Material("models/ppm2/texclothes/#{mat}.png") for _, mat in ipairs {
	'clothes_royalguard', 'clothes_sbs_full'
	'clothes_sbs_light', 'clothes_wbs_full'
	'clothes_wbs_light', 'spidermane_light'
	'spidermane_full'
}]

module.TATTOOS = [Material("models/ppm2/partrender/tattoo/#{fil\lower()}.png") for _, fil in ipairs PPM2.TATTOOS_REGISTRY when fil ~= 'NONE']
debugwhite = {
	'$basetexture': 'models/debug/debugwhite'
	'$ignorez': 1
	'$vertexcolor': 1
	'$vertexalpha': 1
	'$nolod': 1
}

module.EYE_OVALS = {
	Material('models/ppm2/partrender/eye_oval.png')
	Material('models/ppm2/partrender/eye_oval_aperture.png')
}

module.EYE_REFLECTIONS = {
	_Material('models/ppm2/partrender/eye_reflection.png')
	_Material('models/ppm2/partrender/eye_reflection_crystal_foal.png')
	_Material('models/ppm2/partrender/eye_reflection_crystal_unisex.png')
	_Material('models/ppm2/partrender/eye_reflection_foal.png')
	_Material('models/ppm2/partrender/eye_reflection_male.png')
}

module.HEAD_CLOTHES = {
	[2]: {
		Material('models/ppm2/clothesrender/hat_aj.png')
	}

	[3]: {
		Material('models/ppm2/clothesrender/hat_braeburn_2.png')
	}

	[4]: {
		Material('models/ppm2/clothesrender/tr_hat_stars_1.png')
		Material('models/ppm2/clothesrender/tr_hat_stars_2.png')
	}

	[5]: {
		Material('models/ppm2/clothesrender/headphones_1.png')
		Material('models/ppm2/clothesrender/headphones_2.png')
		Material('models/ppm2/clothesrender/headphones_note.png')
	}
}

module.HEAD_CLOTHES_INDEX = {
	[2]: 0
	[3]: 1
	[4]: 2
	[5]: 3
}

module.NECK_CLOTHES = {
	[2]: {
		Material('models/ppm2/clothesrender/winter_scarf_1.png')
		Material('models/ppm2/clothesrender/winter_scarf_2.png')
	}

	[3]: {
		{
			Material('models/ppm2/clothesrender/cape_stars_1.png')
			Material('models/ppm2/clothesrender/cape_stars_2.png')
		}
		{
			Material('models/ppm2/clothesrender/gem.png')
		}
	}

	[4]: {
		Material('models/ppm2/clothesrender/tie_1.png')
		Material('models/ppm2/clothesrender/tie_2.png')
	}

	[5]: {
		Material('models/ppm2/clothesrender/bowtie_1.png')
		Material('models/ppm2/clothesrender/bowtie_2.png')
	}
}

module.NECK_CLOTHES_INDEX = {
	[2]: 4
	[3]: {5, 6}
	[4]: 7
	[5]: 8
}

module.BODY_CLOTHES = {
	[2]: {
		Material('models/ppm2/clothesrender/vest_pouches.png')
		Material('models/ppm2/clothesrender/vest_string.png')
	}

	[3]: {
		Material('models/ppm2/clothesrender/shirt.png')
	}

	[4]: {
		Material('models/ppm2/clothesrender/hoodie.png')
	}

	[5]: {
		Material('models/ppm2/clothesrender/badge.png')
	}
}

module.BODY_CLOTHES_INDEX = {
	[2]: 9
	[3]: 10
	[4]: 11
	[5]: 12
}

module.EYE_CLOTHES = {
	[2]: {
		{}
		{Material('models/ppm2/clothesrender/lense.png')}
	}
	[4]: {
		{}
		{Material('models/ppm2/clothesrender/shades_lense.png')}
	}
	[6]: {
		{}
		{}
	}
	[8]: {
		{}
		{}
	}
}

module.EYE_CLOTHES[3] = module.EYE_CLOTHES[2]
module.EYE_CLOTHES[5] = module.EYE_CLOTHES[4]
module.EYE_CLOTHES[7] = module.EYE_CLOTHES[6]
module.EYE_CLOTHES[9] = module.EYE_CLOTHES[8]

module.EYE_CLOTHES_INDEX = {
	[2]: {13, 14}
	[4]: {15, 16}
	[6]: {17, 18}
	[8]: {20, 21}
}

module.EYE_CLOTHES_INDEX[3] = module.EYE_CLOTHES_INDEX[2]
module.EYE_CLOTHES_INDEX[5] = module.EYE_CLOTHES_INDEX[4]
module.EYE_CLOTHES_INDEX[7] = module.EYE_CLOTHES_INDEX[6]
module.EYE_CLOTHES_INDEX[9] = module.EYE_CLOTHES_INDEX[8]

do
	_prMaterial = (tab) ->
		for i, sub in pairs(tab)
			if not istable(sub[1])
				tab[i] = {}
				tab[i][1] = [mat for mat in *sub when not isnumber(mat)]

	_prIndex = (tab) ->
		for i, sub in pairs(tab)
			if not istable(sub)
				tab[i] = {sub}

	_prMaterial(module.HEAD_CLOTHES)
	_prIndex(module.HEAD_CLOTHES_INDEX)
	_prMaterial(module.NECK_CLOTHES)
	_prIndex(module.NECK_CLOTHES_INDEX)
	_prMaterial(module.BODY_CLOTHES)
	_prIndex(module.BODY_CLOTHES_INDEX)
	_prMaterial(module.EYE_CLOTHES)
	_prIndex(module.EYE_CLOTHES_INDEX)

module.DEBUGWHITE = CreateMaterial('PPM2.Debugwhite', 'UnlitGeneric', debugwhite)
module.HAIR_MATERIAL_COLOR = CreateMaterial('PPM2.ManeTextureBase', 'UnlitGeneric', debugwhite)
module.TAIL_MATERIAL_COLOR = CreateMaterial('PPM2.TailTextureBase', 'UnlitGeneric', debugwhite)
module.WINGS_MATERIAL_COLOR = CreateMaterial('PPM2.WingsMaterialBase', 'UnlitGeneric', debugwhite)
module.HORN_MATERIAL_COLOR = CreateMaterial('PPM2.HornMaterialBase', 'UnlitGeneric', additionTable('$basetexture', 'models/ppm2/base/horn'))
module.BODY_MATERIAL = CreateMaterial('PPM2.BodyTexture', 'UnlitGeneric', additionTable('$basetexture', 'models/ppm2/base/body'))
module.HORN_DETAIL_BUMP = CreateMaterial('PPM2.HornBumpMapRenderer', 'UnlitGeneric', additionTable('$basetexture', 'models/ppm2/base/horn_normal'))
module.HORN_DETAIL_COLOR = Material('models/ppm2/partrender/horn_detail.png')
module.EYE_OVAL = Material('models/ppm2/partrender/eye_oval.png')
module.EYE_GRAD = Material('models/ppm2/partrender/eye_grad.png')
module.EYE_EFFECT = Material('models/ppm2/partrender/eye_effect.png')
module.EYE_LINE_L_1 = Material('models/ppm2/partrender/eye_line_l1.png')
module.EYE_LINE_R_1 = Material('models/ppm2/partrender/eye_line_r1.png')
module.EYE_LINE_L_2 = Material('models/ppm2/partrender/eye_line_l2.png')
module.EYE_LINE_R_2 = Material('models/ppm2/partrender/eye_line_r2.png')
module.EYEBROWS = Material('models/ppm2/partrender/eyebrows.png')
module.PONY_SOCKS = Material('models/ppm2/texclothes/pony_socks.png')

module.LIPS = Material('models/ppm2/partrender/lips.png')
module.NOSE = Material('models/ppm2/partrender/nose.png')
module.BODY_BUMP = Material('models/ppm2/partrender/body_bump2.png')

module.EYE_CORNERA = Material('models/ppm2/eyes/eye_cornea')
module.EYE_CORNERA_OVAL = Material('models/ppm2/eyes/eye_cornea_oval')
module.EYE_EXTRA = Material('models/ppm2/eyes/eye_extra')
module.EYE_EXTRA2 = Material('models/ppm2/eyes/eye_extra2')
module.EYE_LIGHTWARP = Material('models/ppm2/eyes/eye_lightwarp')
module.EYE_REFLECTION2 = Material('models/ppm2/eyes/eye_reflection')

module.MAGIC_HANDS_MATERIAL = Material('models/ppm2/base/magic_arms')

__index = (key) =>
	if key == 'size'
		return #getmetatable(@).original

	value = rawget(getmetatable(@).original, key)
	return value if not isstring(value)
	mat = _Material(value, 'smooth')
	rawset(@, key, mat)
	return mat

patch = (input) ->
	patch(value) for key, value in pairs(input) when istable(value)

	meta = {
		__index: __index
		original: table.Copy(input)
	}

	for k in *table.GetKeys(input)
		if not istable(input[k])
			input[k] = nil

	return setmetatable(input, meta)

PPM2.MaterialsRegistry = patch(module)

return module

--
-- Copyright (C) 2017-2020 DBotThePony

-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do so,
-- subject to the following conditions:

-- The above copyright notice and this permission notice shall be included in all copies
-- or substantial portions of the Software.

-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-- PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
-- FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-- DEALINGS IN THE SOFTWARE.

PPM2.USE_HIGHRES_TEXTURES = CreateConVar('ppm2_cl_hires', '0', {FCVAR_ARCHIVE}, 'Double the texture resolution. Can take ages at texture encoding if CPU is slow!')
PPM2.FORCE_PRECACHE = CreateConVar('ppm2_cl_force_precache', '0', {FCVAR_ARCHIVE}, 'Force precache render textures instead of loading them when needed')

_Material = Material

Material = (path) ->
	return path if not PPM2.FORCE_PRECACHE\GetBool()
	matNew = _Material(path)
	return matNew

module = {
	BODY_DETAILS: {
		Material('models/ppm2/partrender/body_leggrad1.png')
		Material('models/ppm2/partrender/body_lines1.png')
		Material('models/ppm2/partrender/body_stripes1.png')
		Material('models/ppm2/partrender/body_headstripes1.png')
		Material('models/ppm2/partrender/body_freckles.png')
		Material('models/ppm2/partrender/body_hooves1.png')
		Material('models/ppm2/partrender/body_hooves2.png')
		Material('models/ppm2/partrender/body_headmask1.png')
		Material('models/ppm2/partrender/body_hooves1_crit.png')
		Material('models/ppm2/partrender/body_hooves2_crit.png')
		Material('models/ppm2/partrender/body_spots1.png')
		Material('models/ppm2/partrender/body_robotic.png')
		Material('models/ppm2/partrender/dash-e.png')
		Material('models/ppm2/partrender/eye_scar.png')
		Material('models/ppm2/partrender/eye_wound.png')
		Material('models/ppm2/partrender/body_scar.png')
		Material('models/ppm2/partrender/gear_socks.png')
		Material('models/ppm2/partrender/sharp_hooves.png')
		Material('models/ppm2/partrender/sharp_hooves2.png')
		Material('models/ppm2/partrender/separated_muzzle.png')
		Material('models/ppm2/partrender/eye_scar_left.png')
		Material('models/ppm2/partrender/eye_scar_right.png')
		Material('models/ppm2/partrender/android_albedo.png')
		Material('models/ppm2/partrender/android_paint.png')
		Material('models/ppm2/partrender/android_albedo_strip.png')
		Material('models/ppm2/partrender/android_paint_strip.png')
		Material('models/ppm2/partrender/cow_paint.png')
		Material('models/ppm2/partrender/deer_paint.png')
		Material('models/ppm2/partrender/deer_extended_paint.png')
		Material('models/ppm2/partrender/demonic_paint.png')
		Material('models/ppm2/partrender/ear_inner_paint.png')
		Material('models/ppm2/partrender/zebra_detail_paint.png')
	}

	UPPER_MANE_DETAILS: {
		[4]: {Material('models/ppm2/partrender/upmane_5_mask0.png')}
		[5]: {Material('models/ppm2/partrender/upmane_6_mask0.png')}
		[7]: {Material('models/ppm2/partrender/upmane_8_mask0.png'), Material('models/ppm2/partrender/upmane_8_mask1.png')}
		[8]: {Material('models/ppm2/partrender/upmane_9_mask0.png'), Material('models/ppm2/partrender/upmane_9_mask1.png'), Material('models/ppm2/partrender/upmane_9_mask2.png')}
		[9]: {Material('models/ppm2/partrender/upmane_10_mask0.png')}
		[10]: {Material('models/ppm2/partrender/upmane_11_mask0.png'), Material('models/ppm2/partrender/upmane_11_mask1.png'), Material('models/ppm2/partrender/upmane_11_mask2.png')}
		[11]: {Material('models/ppm2/partrender/upmane_12_mask0.png')}
		[12]: {Material('models/ppm2/partrender/upmane_13_mask0.png')}
		[13]: {Material('models/ppm2/partrender/upmane_14_mask0.png')}
		[14]: {Material('models/ppm2/partrender/upmane_15_mask0.png')}
	}

	LOWER_MANE_DETAILS: {
		[4]: {Material('models/ppm2/partrender/dnmane_5_mask0.png')}
		[7]: {Material('models/ppm2/partrender/dnmane_8_mask0.png'), Material('models/ppm2/partrender/dnmane_8_mask1.png')}
		[8]: {Material('models/ppm2/partrender/dnmane_9_mask0.png'), Material('models/ppm2/partrender/dnmane_9_mask1.png')}
		[9]: {Material('models/ppm2/partrender/dnmane_10_mask0.png'), Material('models/ppm2/partrender/dnmane_10_mask1.png'), Material('models/ppm2/partrender/dnmane_10_mask2.png')}
		[10]: {Material('models/ppm2/partrender/dnmane_11_mask0.png'), Material('models/ppm2/partrender/dnmane_11_mask1.png')}
		[11]: {Material('models/ppm2/partrender/dnmane_12_mask0.png')}
	}

	TAIL_DETAILS: {
		[4]: {Material('models/ppm2/partrender/tail_5_mask0.png')}
		[7]: {Material('models/ppm2/partrender/tail_8_mask0.png'), Material('models/ppm2/partrender/tail_8_mask1.png'), Material('models/ppm2/partrender/tail_8_mask2.png'), Material('models/ppm2/partrender/tail_8_mask3.png'), Material('models/ppm2/partrender/tail_8_mask4.png')}
		[9]: {Material('models/ppm2/partrender/tail_10_mask0.png')}
		[10]: {Material('models/ppm2/partrender/tail_11_mask0.png'), Material('models/ppm2/partrender/tail_11_mask1.png'), Material('models/ppm2/partrender/tail_11_mask2.png')}
		[11]: {Material('models/ppm2/partrender/tail_12_mask0.png'), Material('models/ppm2/partrender/tail_12_mask1.png')}
		[12]: {Material('models/ppm2/partrender/tail_13_mask0.png')}
		[13]: {Material('models/ppm2/partrender/tail_14_mask0.png')}
	}

	SOCKS_PATCHS: {
		'models/props_pony/ppm/ppm_socks/socks_striped_unlit'
		'models/props_pony/ppm2/ppm_socks/custom/geometric1_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric2_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric3_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric4_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric5_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric6_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric7_1.png'
		'models/props_pony/ppm2/ppm_socks/custom/geometric8_1.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/dark1.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers10.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers11.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers12.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers13.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers14.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers15.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers16.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers17.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers18.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers19.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers2.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers20.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers3.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers4.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers5.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers6.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers7.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers8.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/flowers9.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/grey1.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/grey2.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/grey3.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/hearts1.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/hearts2.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/snow1.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/wallpaper1.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/wallpaper2.png'
		'models/props_pony/ppm2/ppm_socks/custom_textured/wallpaper3.png'
	}

	SOCKS_DETAILS_PATCHS: {
		[2]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric1_4.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric1_5.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric1_6.png'
		}

		[3]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric2_3.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric2_4.png'
		}

		[4]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric3_2.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric3_3.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric3_5.png'
		}

		[5]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric4_2.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric4_3.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric4_4.png'
		}

		[6]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric5_4.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric5_5.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric5_6.png'
		}

		[7]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric6_2.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric6_3.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric6_4.png'
		}

		[8]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric7_3.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric7_4.png'
		}

		[9]: {
			'models/props_pony/ppm2/ppm_socks/custom/geometric8_2.png'
			'models/props_pony/ppm2/ppm_socks/custom/geometric8_3.png'
		}
	}
}

additionTable = (...) ->
	tab = {'$ignorez': 1, '$vertexcolor': 1, '$vertexalpha': 1, '$nolod': 1}
	args = {...}
	for i = 1, #args, 2
		key, val = args[i], args[i + 1]
		tab[key] = val
	return tab

module.SOCKS_MATERIALS = [Material(id) for _, id in ipairs module.SOCKS_PATCHS]
module.SOCKS_DETAILS = {i, [Material(path) for path in *data] for i, data in pairs module.SOCKS_DETAILS_PATCHS}
module.CUTIEMARKS = [Material("models/ppm2/cmarks/#{mark}.png") for _, mark in ipairs PPM2.DefaultCutiemarks]
module.SUITS = [Material("models/ppm2/texclothes/#{mat}.png") for _, mat in ipairs {
	'clothes_royalguard', 'clothes_sbs_full'
	'clothes_sbs_light', 'clothes_wbs_full'
	'clothes_wbs_light', 'spidermane_light'
	'spidermane_full'
}]

module.TATTOOS = [Material("models/ppm2/partrender/tattoo/#{fil\lower()}.png") for _, fil in ipairs PPM2.TATTOOS_REGISTRY when fil ~= 'NONE']
debugwhite = {
	'$basetexture': 'models/debug/debugwhite'
	'$ignorez': 1
	'$vertexcolor': 1
	'$vertexalpha': 1
	'$nolod': 1
}

module.EYE_OVALS = {
	Material('models/ppm2/partrender/eye_oval.png')
	Material('models/ppm2/partrender/eye_oval_aperture.png')
}

module.EYE_REFLECTIONS = {
	_Material('models/ppm2/partrender/eye_reflection.png')
	_Material('models/ppm2/partrender/eye_reflection_crystal_foal.png')
	_Material('models/ppm2/partrender/eye_reflection_crystal_unisex.png')
	_Material('models/ppm2/partrender/eye_reflection_foal.png')
	_Material('models/ppm2/partrender/eye_reflection_male.png')
}

module.HEAD_CLOTHES = {
	[2]: {
		Material('models/ppm2/clothesrender/hat_aj.png')
	}

	[3]: {
		Material('models/ppm2/clothesrender/hat_braeburn_2.png')
	}

	[4]: {
		Material('models/ppm2/clothesrender/tr_hat_stars_1.png')
		Material('models/ppm2/clothesrender/tr_hat_stars_2.png')
	}

	[5]: {
		Material('models/ppm2/clothesrender/headphones_1.png')
		Material('models/ppm2/clothesrender/headphones_2.png')
		Material('models/ppm2/clothesrender/headphones_note.png')
	}
}

module.HEAD_CLOTHES_INDEX = {
	[2]: 0
	[3]: 1
	[4]: 2
	[5]: 3
}

module.NECK_CLOTHES = {
	[2]: {
		Material('models/ppm2/clothesrender/winter_scarf_1.png')
		Material('models/ppm2/clothesrender/winter_scarf_2.png')
	}

	[3]: {
		{
			Material('models/ppm2/clothesrender/cape_stars_1.png')
			Material('models/ppm2/clothesrender/cape_stars_2.png')
		}
		{
			Material('models/ppm2/clothesrender/gem.png')
		}
	}

	[4]: {
		Material('models/ppm2/clothesrender/tie_1.png')
		Material('models/ppm2/clothesrender/tie_2.png')
	}

	[5]: {
		Material('models/ppm2/clothesrender/bowtie_1.png')
		Material('models/ppm2/clothesrender/bowtie_2.png')
	}
}

module.NECK_CLOTHES_INDEX = {
	[2]: 4
	[3]: {5, 6}
	[4]: 7
	[5]: 8
}

module.BODY_CLOTHES = {
	[2]: {
		Material('models/ppm2/clothesrender/vest_pouches.png')
		Material('models/ppm2/clothesrender/vest_string.png')
	}

	[3]: {
		Material('models/ppm2/clothesrender/shirt.png')
	}

	[4]: {
		Material('models/ppm2/clothesrender/hoodie.png')
	}

	[5]: {
		Material('models/ppm2/clothesrender/badge.png')
	}
}

module.BODY_CLOTHES_INDEX = {
	[2]: 9
	[3]: 10
	[4]: 11
	[5]: 12
}

module.EYE_CLOTHES = {
	[2]: {
		{}
		{Material('models/ppm2/clothesrender/lense.png')}
	}
	[4]: {
		{}
		{Material('models/ppm2/clothesrender/shades_lense.png')}
	}
	[6]: {
		{}
		{}
	}
	[8]: {
		{}
		{}
	}
}

module.EYE_CLOTHES[3] = module.EYE_CLOTHES[2]
module.EYE_CLOTHES[5] = module.EYE_CLOTHES[4]
module.EYE_CLOTHES[7] = module.EYE_CLOTHES[6]
module.EYE_CLOTHES[9] = module.EYE_CLOTHES[8]

module.EYE_CLOTHES_INDEX = {
	[2]: {13, 14}
	[4]: {15, 16}
	[6]: {17, 18}
	[8]: {20, 21}
}

module.EYE_CLOTHES_INDEX[3] = module.EYE_CLOTHES_INDEX[2]
module.EYE_CLOTHES_INDEX[5] = module.EYE_CLOTHES_INDEX[4]
module.EYE_CLOTHES_INDEX[7] = module.EYE_CLOTHES_INDEX[6]
module.EYE_CLOTHES_INDEX[9] = module.EYE_CLOTHES_INDEX[8]

do
	_prMaterial = (tab) ->
		for i, sub in pairs(tab)
			if not istable(sub[1])
				tab[i] = {}
				tab[i][1] = [mat for mat in *sub when not isnumber(mat)]

	_prIndex = (tab) ->
		for i, sub in pairs(tab)
			if not istable(sub)
				tab[i] = {sub}

	_prMaterial(module.HEAD_CLOTHES)
	_prIndex(module.HEAD_CLOTHES_INDEX)
	_prMaterial(module.NECK_CLOTHES)
	_prIndex(module.NECK_CLOTHES_INDEX)
	_prMaterial(module.BODY_CLOTHES)
	_prIndex(module.BODY_CLOTHES_INDEX)
	_prMaterial(module.EYE_CLOTHES)
	_prIndex(module.EYE_CLOTHES_INDEX)

module.DEBUGWHITE = CreateMaterial('PPM2.Debugwhite', 'UnlitGeneric', debugwhite)
module.HAIR_MATERIAL_COLOR = CreateMaterial('PPM2.ManeTextureBase', 'UnlitGeneric', debugwhite)
module.TAIL_MATERIAL_COLOR = CreateMaterial('PPM2.TailTextureBase', 'UnlitGeneric', debugwhite)
module.WINGS_MATERIAL_COLOR = CreateMaterial('PPM2.WingsMaterialBase', 'UnlitGeneric', debugwhite)
module.HORN_MATERIAL_COLOR = CreateMaterial('PPM2.HornMaterialBase', 'UnlitGeneric', additionTable('$basetexture', 'models/ppm2/base/horn'))
module.BODY_MATERIAL = CreateMaterial('PPM2.BodyTexture', 'UnlitGeneric', additionTable('$basetexture', 'models/ppm2/base/body'))
module.HORN_DETAIL_BUMP = CreateMaterial('PPM2.HornBumpMapRenderer', 'UnlitGeneric', additionTable('$basetexture', 'models/ppm2/base/horn_normal'))
module.HORN_DETAIL_COLOR = Material('models/ppm2/partrender/horn_detail.png')
module.EYE_OVAL = Material('models/ppm2/partrender/eye_oval.png')
module.EYE_GRAD = Material('models/ppm2/partrender/eye_grad.png')
module.EYE_EFFECT = Material('models/ppm2/partrender/eye_effect.png')
module.EYE_LINE_L_1 = Material('models/ppm2/partrender/eye_line_l1.png')
module.EYE_LINE_R_1 = Material('models/ppm2/partrender/eye_line_r1.png')
module.EYE_LINE_L_2 = Material('models/ppm2/partrender/eye_line_l2.png')
module.EYE_LINE_R_2 = Material('models/ppm2/partrender/eye_line_r2.png')
module.EYEBROWS = Material('models/ppm2/partrender/eyebrows.png')
module.PONY_SOCKS = Material('models/ppm2/texclothes/pony_socks.png')

module.LIPS = Material('models/ppm2/partrender/lips.png')
module.NOSE = Material('models/ppm2/partrender/nose.png')
module.BODY_BUMP = Material('models/ppm2/partrender/body_bump2.png')

module.EYE_CORNERA = Material('models/ppm2/eyes/eye_cornea')
module.EYE_CORNERA_OVAL = Material('models/ppm2/eyes/eye_cornea_oval')
module.EYE_EXTRA = Material('models/ppm2/eyes/eye_extra')
module.EYE_EXTRA2 = Material('models/ppm2/eyes/eye_extra2')
module.EYE_LIGHTWARP = Material('models/ppm2/eyes/eye_lightwarp')
module.EYE_REFLECTION2 = Material('models/ppm2/eyes/eye_reflection')

module.MAGIC_HANDS_MATERIAL = Material('models/ppm2/base/magic_arms')

__index = (key) =>
	if key == 'size'
		return #getmetatable(@).original

	value = rawget(getmetatable(@).original, key)
	return value if not isstring(value)
	mat = _Material(value, 'smooth')
	rawset(@, key, mat)
	return mat

patch = (input) ->
	patch(value) for key, value in pairs(input) when istable(value)

	meta = {
		__index: __index
		original: table.Copy(input)
	}

	for k in *table.GetKeys(input)
		if not istable(input[k])
			input[k] = nil

	return setmetatable(input, meta)

PPM2.MaterialsRegistry = patch(module)

return module


stuff seems to have changed in leafo/pgmoon, breaking old config syntax

lapisconfig=require "lapis.config"
import config from lapisconfig

config "development", ->
  set "envmode","development"
config {"test","production"}, ->
  set "envmode","production"

config {"development","test","production"},->
  set "appname", "please set the appname in config.moon"
  session_name "please set the session name in config.moon"
  secret "please set the secret in config.moon"
  set "env_lua_path", (os.getenv "LUA_PATH")\gsub "%;", "\\;"
  set "env_lua_cpath", (os.getenv "LUA_CPATH")\gsub "%;", "\\;"
  set "env_moon_path", (os.getenv "MOON_PATH")\gsub "%;", "\\;"
  modules {}
  postgres ->
    database "please set the database in config.moon"
    password "please set the password in config.moon"
    host "127.0.0.1"
    port "5432"
    user "postgres"
    backend "pgmoon"

config {"development","test"}, ->
  port 8080
  enable_console true
  enable_web_migration true
  page_cache_size "1m"
  num_workers 1
  code_cache "off"
  run_daemon "off"
  measure_performance true

config "production", ->
  port 8081
  enable_console false
  enable_web_migration false
  page_cache_size "30m"
  num_workers 4
  code_cache "on"
  run_daemon "on"
  measure_performance false

return lapisconfig

lapisconfig=require "lapis.config"
import config from lapisconfig

config "development", ->
  set "envmode","development"
config {"test","production"}, ->
  set "envmode","production"

config {"development","test","production"},->
  set "appname", "please set the appname in config.moon"
  set "env_lua_path", (os.getenv "LUA_PATH")\gsub "%;", "\\;"
  set "env_lua_cpath", (os.getenv "LUA_CPATH")\gsub "%;", "\\;"
  set "env_moon_path", (os.getenv "MOON_PATH")\gsub "%;", "\\;"
  modules {}
  postgres ->
    backend "pgmoon"

config {"development","test"}, ->
  postgres ->
    database "please set the database in config.moon"
    password "please set the password in config.moon"
    host "127.0.0.1:5432"
    user "postgres"
  port 8080
  enable_console true
  enable_web_migration true
  page_cache_size "1m"
  code_cache "off"
  run_daemon "off"
  session_name "please set the session name in config.moon"
  secret "please set the secret in config.moon"
  measure_performance true

config "production", ->
  postgres ->
    database "please set the database in config.moon"
    password "please set the password in config.moon"
    host "127.0.0.1:5432"
    user "postgres"
  port 8081
  enable_console false
  enable_web_migration false
  page_cache_size "30m"
  code_cache "on"
  num_workers 4
  run_daemon "on"
  session_name "please set the session name in config.moon"
  secret "please set the secret in config.moon"
  measure_performance false

return lapisconfig


Added ppm2_sv_ragdolls_collisions

Added ppm2_sv_ragdolls_collisions

--
-- Copyright (C) 2017-2018 DBot
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--

hook.Add 'PlayerSpawn', 'PPM2.Hooks', =>
	if IsValid(@__ppm2_ragdoll)
		@__ppm2_ragdoll\Remove()
		@UnSpectate()
	timer.Simple 0, ->
		return unless @IsValid()
		if @GetPonyData()
			@GetPonyData()\PlayerRespawn()
			net.Start('PPM2.PlayerRespawn')
			net.WriteEntity(@)
			net.Broadcast()

do
	REQUIRE_CLIENTS = {}

	safeSendFunction = ->
		for ply, data in pairs REQUIRE_CLIENTS
			if not IsValid(ply)
				REQUIRE_CLIENTS[ply] = nil
				continue

			ent = table.remove(data, 1)
			if not ent
				REQUIRE_CLIENTS[ply] = nil
				continue

			data = ent\GetPonyData()
			continue if not data
			data\NetworkTo(ply)

	errorTrack = (err) ->
		PPM2.Message 'Networking Error: ', err
		PPM2.Message debug.traceback()

	timer.Create 'PPM2.Require', 0.25, 0, -> xpcall(safeSendFunction, errorTrack)
	net.Receive 'PPM2.Require', (len = 0, ply = NULL) ->
		return if not IsValid(ply)
		REQUIRE_CLIENTS[ply] = for ent in *ents.GetAll()
			continue if ent == ply
			data = ent\GetPonyData()
			continue if not data
			ent

net.Receive 'PPM2.EditorStatus', (len = 0, ply = NULL) ->
	return if not IsValid(ply)
	ply\SetNWBool('PPM2.InEditor', net.ReadBool())

ENABLE_NEW_RAGDOLLS = CreateConVar('ppm2_sv_new_ragdolls', '1', {FCVAR_NOTIFY, FCVAR_REPLICATED}, 'Enable new ragdolls')
RAGDOLL_COLLISIONS = CreateConVar('ppm2_sv_ragdolls_collisions', '1', {FCVAR_NOTIFY, FCVAR_REPLICATED}, 'Enable ragdolls collisions')

createPlayerRagdoll = =>
	@__ppm2_ragdoll\Remove() if IsValid(@__ppm2_ragdoll)
	@__ppm2_ragdoll = ents.Create('prop_ragdoll')
	rag = @GetRagdollEntity()
	rag\Remove() if IsValid(rag)
	with @__ppm2_ragdoll
		\SetModel(@GetModel())
		\SetPos(@GetPos())
		\SetAngles(@EyeAngles())
		\SetCollisionGroup(COLLISION_GROUP_INTERACTIVE_DEBRIS) if RAGDOLL_COLLISIONS\GetBool()
		\SetCollisionGroup(COLLISION_GROUP_WORLD) if not RAGDOLL_COLLISIONS\GetBool()
		\Spawn()
		\Activate()
		hook.Run 'PlayerSpawnedRagdoll', @, @GetModel(), @__ppm2_ragdoll
		.__ppm2_ragdoll_parent = @
		\SetCollisionGroup(COLLISION_GROUP_INTERACTIVE_DEBRIS)
		\SetNWBool('PPM2.IsDeathRagdoll', true)
		vel = @GetVelocity()
		\SetVelocity(vel)
		\SetAngles(@EyeAngles())
		@Spectate(OBS_MODE_CHASE)
		@SpectateEntity(@__ppm2_ragdoll)
		for boneID = 0, @__ppm2_ragdoll\GetBoneCount() - 1
			physobjID = @__ppm2_ragdoll\TranslateBoneToPhysBone(boneID)
			pos, ang = @GetBonePosition(boneID)
			physobj = @__ppm2_ragdoll\GetPhysicsObjectNum(physobjID)
			physobj\SetVelocity(vel)
			physobj\SetMass(300) -- lol
			physobj\SetPos(pos, true) if pos
			physobj\SetAngles(ang) if ang
		copy = @GetPonyData()\Clone(@__ppm2_ragdoll)
		timer.Simple 0.5, -> copy\Create() if IsValid(@__ppm2_ragdoll)

ALLOW_RAGDOLL_DAMAGE = CreateConVar('ppm2_sv_ragdoll_damage', '1', {FCVAR_ARCHIVE, FCVAR_NOTIFY}, 'Should death ragdoll cause damage?')

hook.Add 'EntityTakeDamage', 'PPM2.DeathRagdoll', (dmg) =>
	attacker = dmg\GetAttacker()
	return if not IsValid(attacker)
	if attacker.__ppm2_ragdoll_parent
		dmg\SetAttacker(attacker.__ppm2_ragdoll_parent)
		if not ALLOW_RAGDOLL_DAMAGE\GetBool()
			dmg\SetDamage(0)
			dmg\SetMaxDamage(0)

hook.Add 'PostPlayerDeath', 'PPM2.Hooks', =>
	return if not @GetPonyData()
	@GetPonyData()\PlayerDeath()
	net.Start('PPM2.PlayerDeath')
	net.WriteEntity(@)
	net.Broadcast()
	if ENABLE_NEW_RAGDOLLS\GetBool() and @IsPony()
		createPlayerRagdoll(@)

hook.Add 'PlayerDeath', 'PPM2.Hooks', =>
	return if not @GetPonyData()
	if ENABLE_NEW_RAGDOLLS\GetBool() and @IsPony()
		createPlayerRagdoll(@)
	return nil

hook.Add 'EntityRemoved', 'PPM2.PonyDataRemove', =>
	return if @IsPlayer()
	return if not @GetPonyData()
	with @GetPonyData()
		net.Start('PPM2.PonyDataRemove')
		net.WriteUInt(.netID, 16)
		net.Broadcast()
		\Remove()

hook.Add 'PlayerDisconnected', 'PPM2.NotifyClients', =>
	@__ppm2_ragdoll\Remove() if IsValid(@__ppm2_ragdoll)
	data = @GetPonyData()
	return if not data
	net.Start('PPM2.NotifyDisconnect')
	net.WriteUInt(data.netID, 16)
	net.Broadcast()

BOTS_ARE_PONIES = CreateConVar('ppm2_bots', '1', {FCVAR_ARCHIVE, FCVAR_NOTIFY}, 'Whatever spawn bots as ponies')

hook.Add 'PlayerSetModel', 'PPM2.Bots', =>
	return if not BOTS_ARE_PONIES\GetBool()
	return if not @IsBot()
	@SetModel('models/ppm/player_default_base_new.mdl')
	return true

PlayerSpawnBot = =>
	return if not BOTS_ARE_PONIES\GetBool()
	return if not @IsBot()
	timer.Simple 1, ->
		return if not IsValid(@)
		@SetViewOffset(Vector(0, 0, PPM2.PLAYER_VIEW_OFFSET))
		@SetViewOffsetDucked(Vector(0, 0, PPM2.PLAYER_VIEW_OFFSET_DUCK))
		if not @GetPonyData()
			data = PPM2.NetworkedPonyData(nil, @)
			PPM2.Randomize(data)
			data\Create()

hook.Add 'PlayerSpawn', 'PPM2.Bots', PlayerSpawnBot
timer.Simple 0, -> PlayerSpawnBot(ply) for ply in *player.GetAll()

--
-- Copyright (C) 2017-2018 DBot
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--     http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--

hook.Add 'PlayerSpawn', 'PPM2.Hooks', =>
	if IsValid(@__ppm2_ragdoll)
		@__ppm2_ragdoll\Remove()
		@UnSpectate()
	timer.Simple 0, ->
		return unless @IsValid()
		if @GetPonyData()
			@GetPonyData()\PlayerRespawn()
			net.Start('PPM2.PlayerRespawn')
			net.WriteEntity(@)
			net.Broadcast()

do
	REQUIRE_CLIENTS = {}

	safeSendFunction = ->
		for ply, data in pairs REQUIRE_CLIENTS
			if not IsValid(ply)
				REQUIRE_CLIENTS[ply] = nil
				continue

			ent = table.remove(data, 1)
			if not ent
				REQUIRE_CLIENTS[ply] = nil
				continue

			data = ent\GetPonyData()
			continue if not data
			data\NetworkTo(ply)

	errorTrack = (err) ->
		PPM2.Message 'Networking Error: ', err
		PPM2.Message debug.traceback()

	timer.Create 'PPM2.Require', 0.25, 0, -> xpcall(safeSendFunction, errorTrack)
	net.Receive 'PPM2.Require', (len = 0, ply = NULL) ->
		return if not IsValid(ply)
		REQUIRE_CLIENTS[ply] = for ent in *ents.GetAll()
			continue if ent == ply
			data = ent\GetPonyData()
			continue if not data
			ent

net.Receive 'PPM2.EditorStatus', (len = 0, ply = NULL) ->
	return if not IsValid(ply)
	ply\SetNWBool('PPM2.InEditor', net.ReadBool())

ENABLE_NEW_RAGDOLLS = CreateConVar('ppm2_sv_new_ragdolls', '1', {FCVAR_NOTIFY, FCVAR_REPLICATED}, 'Enable new ragdolls')

createPlayerRagdoll = =>
	@__ppm2_ragdoll\Remove() if IsValid(@__ppm2_ragdoll)
	@__ppm2_ragdoll = ents.Create('prop_ragdoll')
	rag = @GetRagdollEntity()
	rag\Remove() if IsValid(rag)
	with @__ppm2_ragdoll
		\SetModel(@GetModel())
		\SetPos(@GetPos())
		\SetAngles(@EyeAngles())
		\SetCollisionGroup(COLLISION_GROUP_INTERACTIVE_DEBRIS)
		\Spawn()
		\Activate()
		hook.Run 'PlayerSpawnedRagdoll', @, @GetModel(), @__ppm2_ragdoll
		.__ppm2_ragdoll_parent = @
		\SetCollisionGroup(COLLISION_GROUP_INTERACTIVE_DEBRIS)
		\SetNWBool('PPM2.IsDeathRagdoll', true)
		vel = @GetVelocity()
		\SetVelocity(vel)
		\SetAngles(@EyeAngles())
		@Spectate(OBS_MODE_CHASE)
		@SpectateEntity(@__ppm2_ragdoll)
		for boneID = 0, @__ppm2_ragdoll\GetBoneCount() - 1
			physobjID = @__ppm2_ragdoll\TranslateBoneToPhysBone(boneID)
			pos, ang = @GetBonePosition(boneID)
			physobj = @__ppm2_ragdoll\GetPhysicsObjectNum(physobjID)
			physobj\SetVelocity(vel)
			physobj\SetMass(300) -- lol
			physobj\SetPos(pos, true) if pos
			physobj\SetAngles(ang) if ang
		copy = @GetPonyData()\Clone(@__ppm2_ragdoll)
		timer.Simple 0.5, -> copy\Create() if IsValid(@__ppm2_ragdoll)

ALLOW_RAGDOLL_DAMAGE = CreateConVar('ppm2_sv_ragdoll_damage', '1', {FCVAR_ARCHIVE, FCVAR_NOTIFY}, 'Should death ragdoll cause damage?')

hook.Add 'EntityTakeDamage', 'PPM2.DeathRagdoll', (dmg) =>
	attacker = dmg\GetAttacker()
	return if not IsValid(attacker)
	if attacker.__ppm2_ragdoll_parent
		dmg\SetAttacker(attacker.__ppm2_ragdoll_parent)
		if not ALLOW_RAGDOLL_DAMAGE\GetBool()
			dmg\SetDamage(0)
			dmg\SetMaxDamage(0)

hook.Add 'PostPlayerDeath', 'PPM2.Hooks', =>
	return if not @GetPonyData()
	@GetPonyData()\PlayerDeath()
	net.Start('PPM2.PlayerDeath')
	net.WriteEntity(@)
	net.Broadcast()
	if ENABLE_NEW_RAGDOLLS\GetBool() and @IsPony()
		createPlayerRagdoll(@)

hook.Add 'PlayerDeath', 'PPM2.Hooks', =>
	return if not @GetPonyData()
	if ENABLE_NEW_RAGDOLLS\GetBool() and @IsPony()
		createPlayerRagdoll(@)
	return nil

hook.Add 'EntityRemoved', 'PPM2.PonyDataRemove', =>
	return if @IsPlayer()
	return if not @GetPonyData()
	with @GetPonyData()
		net.Start('PPM2.PonyDataRemove')
		net.WriteUInt(.netID, 16)
		net.Broadcast()
		\Remove()

hook.Add 'PlayerDisconnected', 'PPM2.NotifyClients', =>
	@__ppm2_ragdoll\Remove() if IsValid(@__ppm2_ragdoll)
	data = @GetPonyData()
	return if not data
	net.Start('PPM2.NotifyDisconnect')
	net.WriteUInt(data.netID, 16)
	net.Broadcast()

BOTS_ARE_PONIES = CreateConVar('ppm2_bots', '1', {FCVAR_ARCHIVE, FCVAR_NOTIFY}, 'Whatever spawn bots as ponies')

hook.Add 'PlayerSetModel', 'PPM2.Bots', =>
	return if not BOTS_ARE_PONIES\GetBool()
	return if not @IsBot()
	@SetModel('models/ppm/player_default_base_new.mdl')
	return true

PlayerSpawnBot = =>
	return if not BOTS_ARE_PONIES\GetBool()
	return if not @IsBot()
	timer.Simple 1, ->
		return if not IsValid(@)
		@SetViewOffset(Vector(0, 0, PPM2.PLAYER_VIEW_OFFSET))
		@SetViewOffsetDucked(Vector(0, 0, PPM2.PLAYER_VIEW_OFFSET_DUCK))
		if not @GetPonyData()
			data = PPM2.NetworkedPonyData(nil, @)
			PPM2.Randomize(data)
			data\Create()

hook.Add 'PlayerSpawn', 'PPM2.Bots', PlayerSpawnBot
timer.Simple 0, -> PlayerSpawnBot(ply) for ply in *player.GetAll()


hotfix: typo

hotfix: typo

import escape from require "lapis.util"
http = require "lapis.nginx.http"
import render_html from require "lapis.html"

UsersModel=require "lazuli.modules.user_management.models.users"
YubiCloudModel=require "lazuli.modules.user_management.models.yubicloud"

frandom = nil
ranval=->
  frandom or= assert io.open "/dev/urandom", "rb"
  s = frandom\read 4
  assert s\len! == 4
  v = 0
  for i = 1, 4
    v = 256 * v + s\byte i
  return v

class YubiCloud
  new: (@app,@modulename,@config) =>
    @apiurl = @config.apiurl or "http://api.yubico.com/wsapi/2.0/verify?id=1&otp=$OTP$&nonce=$NONCE$&timestamp=1"
    @required = @config.required or false
    @takeControlOfForm = @takeControlOfForm or true

  fillUrl: (otp,nonce) =>
    @apiurl\gsub("$OTP$",escape otp)\gsub("$NONCE$",escape nonce)

  tryLogin: (params) =>
    nonce=@mkNonce!
    res=http.simple @fillUrl params.yubikey, nonce
    if res\find "status=OK", 1, true and res\find "nonce="..nonce, 1, true
      entry=YubiCloudModel\find idstr: params.yubikey\lower!\sub(-33)
      if entry
        return entry\get_user!, res
    if @required
      return nil, res
    else
      return false, res

  mkNonce: =>
    now=os.time!
    hash=now..encode_base64 hmac_sha1 now..ranval!,ranval!..now
    hash=hash\gsub "%/","_"
    hash\sub 1,20

  getLoginOkHtml:    => ""
  getLoginErrorHtml: => ""

  getLoginHtml: =>
    render_html ->
      div class: "pure-control-group yubigroup", ->
        label for: "yubikey", "YubiCloud:"
        input id: "yubikey", type: "yubikey", name: "yubikey", autocomplete: "off", placeholder: "YubiKey OTP", autofocus: @takeControlOfForm and "autofocus" or nil
        if @takeControlOfForm
          input type: "button", value: "X", id: "closeYubiKeyBtn"
      if @takeControlOfForm
        script ->
          raw [[
            document.getElementsByClassName("usernamegroup")[0].hidden=true
            document.getElementsByClassName("passwordgroup")[0].hidden=true
            document.getElementById("closeYubiKeyBtn").onclick=function(){
              document.getElementsByClassName("usernamegroup")[0].hidden=false
              document.getElementsByClassName("passwordgroup")[0].hidden=false
              document.getElementsByClassName("yubigroup")[0].hidden=true
              document.getElementById("username").focus()
            }
          ]]

import escape from require "lapis.util"
http = require "lapis.nginx.http"
import render_html from require "lapis.html"

UsersModel=require "lazuli.modules.user_management.models.users"
YubiCloudModel=require "lazuli.modules.user_management.models.yubicloud"

frandom = nil
ranval=->
  frandom or= assert io.open "/dev/urandom", "rb"
  s = frandom\read 4
  assert s\len! == 4
  v = 0
  for i = 1, 4
    v = 256 * v + s\byte i
  return v

class YubiCloud
  new: (@app,@modulename,@config) =>
    @apiurl = @config.apiurl or "http://api.yubico.com/wsapi/2.0/verify?id=1&otp=$OTP$&nonce=$NONCE$&timestamp=1"
    @required = @config.required or false
    @takeControlOfForm = @takeControlOfForm or true

  fillUrl: (otp,nonce) =>
    @apiurl\gsub("$OTP$",escape otp)\gsub("$NONCE$",escape nonce)

  tryLogin: (params) =>
    nonce=@mkNonce
    res=http.simple @fillUrl params.yubikey, nonce
    if res\find "status=OK", 1, true and res\find "nonce="..nonce, 1, true
      entry=YubiCloudModel\find idstr: params.yubikey\lower!\sub(-33)
      if entry
        return entry\get_user!, res
    if @required
      return nil, res
    else
      return false, res

  mkNonce: =>
    now=os.time!
    hash=now..encode_base64 hmac_sha1 now..ranval!,ranval!..now
    hash=hash\gsub "%/","_"
    hash\sub 1,20

  getLoginOkHtml:    => ""
  getLoginErrorHtml: => ""

  getLoginHtml: =>
    render_html ->
      div class: "pure-control-group yubigroup", ->
        label for: "yubikey", "YubiCloud:"
        input id: "yubikey", type: "yubikey", name: "yubikey", autocomplete: "off", placeholder: "YubiKey OTP", autofocus: @takeControlOfForm and "autofocus" or nil
        if @takeControlOfForm
          input type: "button", value: "X", id: "closeYubiKeyBtn"
      if @takeControlOfForm
        script ->
          raw [[
            document.getElementsByClassName("usernamegroup")[0].hidden=true
            document.getElementsByClassName("passwordgroup")[0].hidden=true
            document.getElementById("closeYubiKeyBtn").onclick=function(){
              document.getElementsByClassName("usernamegroup")[0].hidden=false
              document.getElementsByClassName("passwordgroup")[0].hidden=false
              document.getElementsByClassName("yubigroup")[0].hidden=true
              document.getElementById("username").focus()
            }
          ]]